“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情”
docker-compose自动部署太爽啦!!
正好最近比较休闲,潦草的过了一遍docker,于是突发奇想 把自己的毕设系统利用docker-compose进行一键自动部署,尝尝鲜~~ 本文基于该项目,这是github地址!
What’s docker
Docker 是一个 开源 的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的 镜像 中,然后发布到任何流行的 Linux 或 Windows 机器上,可以实现 虚拟化。容器是完全使用 沙箱 机制,相互之间不会有任何接口。
What‘s docker-compose
docker-compose是基于 docker 的开源项目,托管于github上,调用docker服务的API实现对docker容器集群的快速编排,即通过一个单独的yaml文件,来定义一组相关的容器来为一个项目服务。
正篇
首先没有安装docker的同学需要先安装,这里建议大家下载个docker desktop,它会帮助大家一键安装docker环境,能够通过界面操控镜像容器,还支持Win,Mac等操作系统,总之对新人非常的友好下载地址
编写Dockerfile文件
dockerfile文件没有后缀名,文件命名就是 Dockerfile,内容如下
接下里会一一讲解内容的步骤以及过程
# 1.拉取node镜像
FROM node:14.17.6
# 2.更换当前目录为 /usr/local/workspace
WORKDIR /usr/local/workspace
# 3.复制宿主机 yuecaimasyer 目录下的文件到镜像当前目录下,即/usr/local/workspace
COPY ./yuecaimaster .
# 4.更换当前目录为 /usr/local/workspace/web
WORKDIR /usr/local/workspace/web
# 5.执行三个命令
RUN yarn install \
&& yarn build \
&& cp -r ./dist ../api/public
# 6.更换当前工作目录为 /usr/local/workspace/api
WORKDIR /usr/local/workspace/api
# 7.执行命令 yarn install
RUN yarn install
# 8.暴露端口
EXPOSE 3100
# 9.启动容器时候执行的命令
CMD [ "yarn","serve" ]
step1. 首先是拉取镜像 FROM ,定制的镜像都是基于 FROM 的镜像,这里的 node 就是定制需要的基础镜像,后续的操作都是基于 node.
step2. WORKDIR /usr/local/workspace 这行代码的意思就相当于 cd /usr/local/workspace,更换当前的工作路径.
step3. COPY ./yuecaimaster . 把宿主机(您当前的主机)的当前工作路径下的yuecaimaster目录下的文件复制到 docker镜像的 /usr/local/workspace下,因为step2我们指定过docker的工作路径为 /usr/local/workspace
step4. 与setp 2 等同
step5. RUN用于执行命令、 注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如下面,docker会创建三层:
RUN yarn install
RUN yarn build
RUN cp -r ./dist ../api/public
于是为了避免以上现象,我们可以替换成一行命令 用 && 衔接,只需创建一层:
RUN yarn install \
&& yarn build \
&& cp -r ./dist ../api/public
step6, step7略过
step8. EXPOSE 3100 仅仅只是声明端口,这个端口不会被暴露给宿主机,需要在启动镜像的时候,也就是 docker run -P 时,docker容器端口3100会随机映射到宿主机的某个端口上。
step9. CMD [ "yarn","serve" ] 当我们启动一个新的容器的时候,容器会自动执行 yarn serve 命令,CMD 命令与 RUN 命令类似,但是CMD 是在容器启动阶段 即docker run -P 执行 ,RUN是在构建docker镜像的时候执行命令 即 docker build -t mydocker .,RUN和CMD执行的阶段完全不同.
然后我们执行 docker build -t mtdocker . 命令
执行docker images 查看我们的docker镜像
如果您已下载docker desktop 我们可以直接通过它来启动
也可以通过命令启动 docker run -P mydocker(随机映射端口给宿主机,docker run -p [宿主机端口号]:[镜像端口号] mydocker ,可自定义映射端口)
此时我们的镜像就启动好了,可以通过 docker ps -a 查看所有的容器
这样子构成的镜像看似完美,但还是缺少了某些服务,比如数据库,我们还需要另外的Dockerfile创建镜像来放数据库吗?答案是 YES. 但更好的方法去创建,请往下看
编写 docker-compose.yml
docker-compose陈述它是对容器集群的快速编排,同来yml文件来定义一组容器为项目服务。上文很显然我们还缺少一个数据库服务。开始编写yml文件
version: '2'
# 定义自己的docker网络 ,名字叫做mynet1,配置网段方便分配指定的IP
networks:
mynet1:
ipam:
config:
- subnet: 172.30.0.0/16
# 服务项目
services:
web:
# 容器名
container_name: myweb
# 依靠当前文件下的Dockerfile文件构建镜像
build: .
# 暴露镜像内部3100端口给宿主机3100端口
ports:
- "3100:3100"
# 依赖数据库服务,需先等待数据库服务健康启动,在执行web服务
depends_on:
db:
condition: service_healthy
# 指定 mynet1 网络,指定ip地址
networks:
mynet1:
ipv4_address: 172.30.0.2
db:
container_name: mysql
# 构建镜像为mysql:5.7,会自动从docker.io上拉取镜像
image: mysql:5.7
# 当启动失败时 自动重启
restart: "always"
# 配置mysql环境,定义mysql用户,创建root密码,即可以通过 mysql -uroot -p123456登录
environment:
MYSQL_ROOT_HOST: "%"
MYSQL_ROOT_PASSWORD: "123456"
MYSQL_USER: "admin"
MYSQL_PASS: "123456"
# 创建数据库 名 yuecaidb
MYSQL_DATABASE: "yuecaidb"
# 这里我们可以暴露3306端口给宿主机
ports:
- "3306:3306"
# 每隔3秒检查服务是否健康
healthcheck:
test: "/usr/bin/mysql --user=root --password=123456 --execute \"SHOW DATABASES;\""
interval: 3s
timeout: 1s
retries: 5
networks:
mynet1:
ipv4_address: 172.30.0.3
yml定义两个分别为 web和db 的服务,web服务直接利用上面的Dockerfile去构建镜像,然后暴露指定的端口给宿主机,db服务则是选择拉取镜像里的镜像,配置好参数方便我们的web服务连接数据库。
执行 docker-compose up -d
等待四五分钟会出现如下界面(我本地已经创建过镜像,所以它会自动帮我跳过构建镜像的过程)
通过docker desktop可以看到我们创建的容器集群,打开localhost:3100就可以访问到服务了
有兴趣的可以先去github把项目克隆下来试一下
槽点
这句话的大概意思就是告诉你 depends_on 不会让你的服务等待另外一个服务完全启动即ready阶段,而是running阶段,意味着如果serviceA依赖serviceB,depends_on不能保障serviceB比serviceA先进入ready阶段。
depends_on does not wait for db and redis to be “ready”
before starting web - only until they have been started.
If you need to wait for a service to be ready, see Controlling
startup order for more on this problem and strategies for solving it.
web服务如果比数据库服务先启动,会出现连接失败的问题。这里我选择的解决方法是通过healthcheck检查数据库服务是否健康启动,让depend_on依赖数据库的状态service_healthy,然后再启动服务。网上也有比较好的开源工具 wait for,使用起来会更加复杂一些。
尾声
自己这一周在通过官网和社区文献的学习过程中比较痛苦,许多好的文献不是过于深奥就是没上下文,似乎对初学者不太友好(也许是自己领悟不高😣)!文章的目的也很单纯,利用所学的知识通过实践的方式分享给刚入坑的新人,希望对您们能有所帮助。如果文章有误希望能帮助我指出。
如果您有任何疑问,希望您不要吝啬于言语,社区会帮您解决问题!