前言
工作中我们总会遇到许多抽象的需求,前段时间组长让我写了个验证码组件,前端后端数据库都让我整,写完打包给他,耗时1周整完。
正当我准备继续摸鱼时,组长又给我提个需求,把前端后端数据库所有服务用docker整合进一个镜像中,到时候直接运行。。。。我听完懵逼了两秒,不是哪有这种操作啊?这不违反了Docker的单一职责原则吗,用Docker Compose多香啊。。。。
吐槽归吐槽,该干还得干,去网上搜了一下,牛魔的根本没人会这么干啊,只能自己摸着石头过河了。
前端,后端,数据库,三个服务,一个容器
基础镜像的选择
首先是基础镜像的选择,我一开始想的是用 mysql:8.0、openjdk:8-alpine 或者 nginx 为基础镜像,在这个基础镜像上安装其他服务所需要的环境,但是后来发现,这三个镜像没有包管理器,不能使用 apt 或者 yum 安装其他服务,所以这条路走不通。
既然那三个镜像没有包管理器,那我们就找一个自带包管理器的基础镜像就行了,这里我选的是Ubuntu,包管理器为 apt
然后是版本的选择,下面这个表格是不同Ubuntu版本和它们通常默认安装的MySQL版本
Ubuntu版本 | 默认MySQL版本 |
---|---|
Ubuntu 22.04 LTS | MySQL 8.0 |
Ubuntu 20.04 LTS | MySQL 8.0 |
Ubuntu 18.04 LTS | MySQL 5.7 |
Ubuntu 16.04 LTS | MySQL 5.7 |
Ubuntu 14.04 LTS | MySQL 5.5 |
Ubuntu 12.04 LTS | MySQL 5.5 |
我使用的数据库是 MySQL 8,所以应该选 22 或者 20 的版本,关于 22 和 20 两个版本的选择,我给出的答案是选择 22,理由如下
在 Ubuntu 20.04 版本中,使用 apt install -y mysql-server
安装 mysql 时,会在提示我们选择时区,此时系统会阻塞并等待我们输入,但是我们在写 Dockerfile 构建镜像时应该尽可能避免这种要交互的操作
FROM ubuntu:20.04
# 安装MYSQL
RUN apt update \
&& apt install -y mysql-server
而 Ubuntu 22.04 则不需要选择时区,直接就能安装成功,所以这里我选择的是 Ubuntu 22.04 版本
MySQL 的安装和配置
选择完基础镜像后就是安装 MySQL,使用 apt install -y mysql-server
安装完 mysql 后,默认是没有密码的,输入mysql -u rooot
直接就能登录成功,接下来需要设置密码,这一步不能少,否则后端会连接不上!!!
设置密码的常规操作是先登录进 mysql,然后设置密码
mysql -u root
ALTER user 'root'@'localhost' identified with mysql_native_password by 'root';
我这里设置的密码是 root,大家可以自行设置,改最后的引号里的内容
然而,我们要在 Dockerfile 里面完成设置密码这件事,需要把登录mysql 和 设置密码 合成一句话,变成这样
mysql -u root -e "ALTER user 'root'@'localhost' identified with mysql_native_password by 'root';"
写在 Dockerfile 中是这样
FROM ubuntu:22.04
# 安装MYSQL
RUN apt update \
&& apt install -y mysql-server
# 改密码
RUN service mysql restart \
&& mysql -u root -e "ALTER user 'root'@'localhost' identified with mysql_native_password by 'root';"
其中这句 service mysql restart
不能少,安装完 mysql 后要重启一次才能正常登录,否则会报下面这个错误
然后我们再把执行 sql 文件的部分加进去,记得先将 sql 文件和 Dockerfile 放在一个目录下
复制 sql 文件到容器中,执行sql,同理,也是登录和执行写成一句话
mysql -u root < /verify-code.sql
Dockerfile
FROM ubuntu:22.04
# 复制sql文件
COPY ./verify-code.sql /
# 安装MYSQL
RUN apt update \
&& apt install -y mysql-server
# 执行sql && 设置密码
RUN service mysql restart \
&& mysql -u root < /verify-code.sql \
&& mysql -u root -e "ALTER user 'root'@'localhost' identified with mysql_native_password by 'root';"
这里我把执行 sql 放在设置密码前面,这样就可以少写一个-p root
了
至此,MySQL 的安装算是告一段落了
JDK的安装
apt install -y openjdk-8-jdk
准备好后端 jar 包(这里默认大家都会了哈),和 Dockerfile 放一起
Dockerfile
FROM ubuntu:22.04
# 复制sql文件
........
# 复制后端jar包
COPY ./verify-code-server-0.0.1-SNAPSHOT.jar /tmp/verify-code-server-0.0.1-SNAPSHOT.jar
# 安装MYSQL && jdk8
RUN apt update \
&& apt install -y mysql-server \
&& apt install -y openjdk-8-jdk
# 执行sql && 设置密码
........
运行 jar 包的操作我们后续会放到 entrypoint 中
Nginx的安装和配置
安装 nginx
apt install -y nginx
Dockerfile
FROM ubuntu:22.04
# 复制sql文件
# 复制后端jar包
........
# 安装MYSQL && jdk8 && nginx
RUN apt update \
&& apt install -y mysql-server \
&& apt install -y openjdk-8-jdk \
&& apt-get install -y nginx
# 执行sql && 设置密码
........
Nginx 配置文件
nginx 配置文件分两种情况,自己提前写好了有完整的 nginx.conf 和 没有 nginx.conf
1.先说有 nginx.conf 的情况,直接把自己的 nginx.conf 文件复制到容器的 /etc/nginx/
目录下,覆盖掉原来的 nginx.conf
将 nginx.conf 文件和 Dockerfile 放在同级目录
Dockerfile
COPY ./nginx.conf /etc/nginx/
FROM ubuntu:22.04
# 复制sql文件
# 复制后端jar包
........
# 安装MYSQL && jdk8 && nginx
........
# 执行sql && 设置密码
........
# 复制nginx.conf配置文件
COPY ./nginx.conf /etc/nginx/
2.第二种是没有 nginx.conf 文件,可以写一个精简版的
先在 Dockerfile 的目录下新建一个 my.conf
文件
touch my.conf
使用 vim 编辑 my.conf
vim my.conf
内容
server {
listen 5173;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
然后将这个 my.conf 复制到容器的 /etc/nginx/conf.d
目录下
COPY ./my.conf /etc/nginx/conf.d/
FROM ubuntu:22.04
# 复制sql文件 && 复制后端jar包
........
# 安装MYSQL && jdk8 && nginx
.........
# 执行sql && 设置密码
.........
# 复制自定义Nginx配置文件
COPY ./my.conf /etc/nginx/conf.d/
前端的打包
记得先将请求路径改成服务器的url
将 dist 文件夹和 Dockerfile 放到同一目录
将 dist 目录重命名为 html
mv dist html
打包成后缀 .tar.gz 格式,文件名 html.tar.gz
tar -czvf html.tar.gz html
将打包文件复制到/usr/share/nginx/html
目录下(先删除html目录,然后直接解压)
rm -rf /usr/share/nginx/html
tar -xzvf /usr/share/nginx/html.tar.gz -C /usr/share/nginx
FROM ubuntu:22.04
# 复制sql文件 && 复制后端jar包
........
# 安装MYSQL && jdk8 && nginx
.........
# 执行sql && 设置密码
.........
# 复制自定义Nginx配置文件
........
# 复制前端打包文件
COPY ./html.tar.gz /usr/share/nginx/
# 解压覆盖
RUN rm -rf /usr/share/nginx/html
RUN tar -xzvf /usr/share/nginx/html.tar.gz -C /usr/share/nginx
启动 nginx 的命令我们也是后面放到 entrypoint 中
暴露端口
这里我后端的端口是 8080,前端是5173
FROM ubuntu:22.04
# 中间省略
........
# 暴露端口
EXPOSE 8080 5173
ENTRYPOINT
在 Dockerfile 同级目录下新建一个 entrypoint.sh
touch entrypoint.sh
使用 vim 编辑
vim entrypoint.sh
内容
#!/bin/bash
# 重启MySQL服务
service mysql restart
# 启动后端
java -jar /tmp/verify-code-server-0.0.1-SNAPSHOT.jar > /dev/null 2>&1 &
# 启动前端
/usr/sbin/nginx
# 保持容器运行
exec tail -f /dev/null
最后在 Dockerfile 中加上执行 entrypoint 脚本的语句
FROM ubuntu:22.04
# 中间省略
........
# 复制自定义的entrypoint脚本到镜像中
COPY entrypoint.sh /usr/local/bin/
# 赋予脚本执行权限
RUN chmod +x /usr/local/bin/entrypoint.sh
# 设置ENTRYPOINT为自定义脚本
ENTRYPOINT ["bash", "/usr/local/bin/entrypoint.sh"]
接下来就可以进行构建了
docker build -t verify-code:1.0 .
运行
docker run --name verify-code -p 8080:8080 -p 5173:5173 -itd verify-code:1.0
导出镜像
docker save -o verify-code.tar verify-code:1.0
最后附上完整的 Dockerfile 供大家参考
FROM ubuntu:22.04
# 复制sql文件
COPY ./verify-code.sql /
# 复制后端jar包
COPY ./verify-code-server-0.0.1-SNAPSHOT.jar /tmp/verify-code-server-0.0.1-SNAPSHOT.jar
# 安装MYSQL && jdk8 && nginx
RUN apt update \
&& apt install -y mysql-server \
&& apt install -y openjdk-8-jdk \
&& apt-get install -y nginx
# 执行sql && 设置密码
RUN service mysql restart \
&& mysql -u root < /verify-code.sql \
&& mysql -u root -e "ALTER user 'root'@'localhost' identified with mysql_native_password by 'root';"
# 复制自定义Nginx配置文件
COPY ./my.conf /etc/nginx/conf.d/
# 复制前端打包文件
COPY ./html.tar.gz /usr/share/nginx/
# 解压覆盖
RUN rm -rf /usr/share/nginx/html
RUN tar -xzvf /usr/share/nginx/html.tar.gz -C /usr/share/nginx
# 暴露端口
EXPOSE 8080 5173
# 复制自定义的entrypoint脚本到镜像中
COPY entrypoint.sh /usr/local/bin/
# 赋予脚本执行权限
RUN chmod +x /usr/local/bin/entrypoint.sh
# 设置ENTRYPOINT为自定义脚本
ENTRYPOINT ["bash", "/usr/local/bin/entrypoint.sh"]
OK,大功告成,又可以愉快的摸鱼了