Web应用通常由多个部分组成,包括:前端、后端和基础中间件。前端代码是静态的(html+js),可以放在nginx中运行;后端业务逻辑在nodejs或java容器中运行;mysql、mongodb等通用中间件进行数据持久存储。本文以一个实际项目为例,演示如何利用docker方便运维对应用的多个部分进行发布。
项目概述
项目地址:https://github.com/jasony62/tms-mongodb-web
项目包括3个部分:
- ue_admin:前端代码,采用VUE开发,放在nginx中独立运行
- back:后端代码,采用nodejs开发,独立运行
- mongodb:数据持久化,独立运行
通过docker要解决两方面问题:1、减轻开发人员个人开发环境的搭建,让项目具备单机开箱即用能力;2、实现代码和运行环境的整体发布,简化并规范运维工作。
问题1通过编写docker-compose.yml解决。相关知识可以参考前一篇文章:用Docker简化Nodejs开发1——开发环境。需要注意的是前端代码独立部署有跨域(CORS)问题,需要在nginx上设置反向代理。
本文的重点是关注问题2,通过docker实现一个完整的从开发到测试的发布流程。
基本发布流程如下:
- 开发人员在开发环境将代码发布到git仓库;
- 运维人员在构建环境从git仓库拉取代码;编译前端代码;分别将不同模块打包成镜像;
- 构建环境将镜像发布到私有镜像仓库;
- 测试环境从镜像仓库拉取镜像,启动运行;
- 测试通过后,生产环境从镜像仓库拉取镜像,启动运行。
为演示上述过程,准备3台机器,开发,构建和测试,都安装好docker和docker-compose。
开发环境
为了让前端运行环境更干净,镜像中只包含编译完的静态内容,所以需要在制作镜像前执行命令生成前端代码(默认在dist目录)
cnpm i
yarn build 或 npm run build
ue_admin目录下的nginx.conf
,back目录下的config
目录不放在镜像中,它们需要在运行环境中进行指定。
docker-compose.yml
volumes:
- ./back/config:/usr/src/app/config
volumes:
- ./ue_admin/nginx.conf:/etc/nginx/nginx.conf:ro
If neither ‘rw’ or ‘ro’ is specified then the volume is mounted in read-write mode.
参考:https://docs.docker.com/engine/reference/run/#volume-shared-filesystems
参考:https://hub.docker.com/_/nginx
参考:https://www.nginx.com/blog/deploying-nginx-nginx-plus-docker/
参考:JS-Web项目常见问题(3)-前后端分离导致的跨域问题分析
构建环境
用树莓派3B+作为构建环境(其他环境也可以),安装docker和docker-compose,建立私有docker仓库,从github上拉取代码,制作镜像,发布镜像到私有仓库。
安装docker
sudo curl -sSL https://get.docker.com | sh
时间有些长,大约等3分钟。
按照提示执行下面的命令,否则会报权限错误。
sudo usermod -aG docker pi
安装docker-compose
通过pyenv安装python,通过pip安装docker-compose。
sudo apt install zlib1g-dev libreadline-dev libssl-dev libbz2-dev libsqlite3-dev libffi-dev
curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash
vi ~/.bash_profile
export PATH="/hom/pi/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
source ~/.bash_profile
pyenv install 3.7.0
pyenv global 3.7.0
pip install docker-compose
搭建私有镜像库
拉取(pull)arm版本的registry镜像。
docker pull budry/registry-arm
创建存储镜像文件的目录。
mkdir docker-registry
启动镜像仓库容器。
docker run --name registry-arm -d -p 5000:5000 -v /home/pi/docker-registry:/var/lib/registry --restart always budry/registry-arm
从github拉取代码
安装git(如果没有安装过)
sudo apt-get install git
从git库拉取代码。
编译代码
cd tms-mongodb-web/ue_admin
cnpm i
npm run build
检查是否生成dist
目录。
制作镜像
官方MongoDb镜像没有树莓派的版本,需要换成rpi3-mongodb3
。注意,这时并不需要修改docker-compose.yml
,docker支持用docker-compose.override.yml
文件指定需要覆盖的选项(查看官网文档中关于-f
选项的说明)。
version: '3.7'
services:
mongodb:
image: andresvidal/rpi3-mongodb3
logging:
driver: "json-file"
参考:https://hub.docker.com/r/andresvidal/rpi3-mongodb3
执行命令,生成镜像。
docker-compose build
发布镜像
在发布和获取镜像前,需要让客户端支持以http(非https)访问私库。
客户端直接在界面中设置。
在树莓派中新建文件/etc/docker/daemon.json
,添加如下内容:
{ "insecure-registries": ["192.168.43.30:5000"] }
修改完成后需要重启docker才能生效。
完成上面的工作,在树莓派(私库)上查看已有的镜像。
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tms-mw-ue_admin latest bb34d5e9ee16 13 hours ago 21.8MB
tms-mw-back latest 0abb9b5c6cb6 13 hours ago 162MB
nginx alpine 7e9d7b4eafa6 7 days ago 18.4MB
node alpine 30bb03f6ec2e 2 weeks ago 96.6MB
andresvidal/rpi3-mongodb3 latest fca24dc11d8c 23 months ago 366MB
budry/registry-arm latest c440ef8a31ab 24 months ago 139MB
tms-mw-ue_admin
和tms-mw-back
是应用的镜像,需要发布到私有镜像库。
docker tag tms-mw-back 192.168.43.30:5000/tms-mw-back
docker push 192.168.43.30:5000/tms-mw-back
用开发机或测试机看看是否能够成功拉取镜像。
docker pull 192.168.43.30:5000/tms-mw-back
注意:可以不用tag的操作,直接在docker-compose.override.yml
文件中将镜像指定为私有库镜像。
back:
image: 192.168.43.30:5000/tms-mw-back
ue_admin:
image: 192.168.43.30:5000/tms-mw-ue_admin
运行命令
docker-compose build
镜像版本
代码更新了就需要生成新的镜像版本,为了方便回滚等需要,可以将现有的镜像版本保留下来。
docker tag 192.168.43.30:5000/tms-mw-ue_admin:latest 192.168.43.30:5000/tms-mw-ue_admin:v1
原则上,每一次生成新版本镜像前,都应该将现有最新版本(latest)标记为一个指定版本号的镜像。
参考:https://docs.docker.com/engine/reference/commandline/tag/
测试环境
安装docker和docker-compose。
复制docker-compose.yml
,ue_admin/nginx.conf
和back/config
到测试环境项目根目录下。修改docker-compose.yml
文件中进行的位置和文件的位置。
version: '3.7'
services:
mongodb:
image: mongo:latest
container_name: tms-mw-mongo
ports:
- '27017:27017'
logging:
driver: none
back:
image: 192.168.43.30:5000/tms-mw-back
container_name: tms-mw-back
ports:
- '3000:3000'
volumes:
- ./config:/usr/src/app/config
depends_on:
- mongodb
ue_admin:
image: 192.168.43.30:5000/tms-mw-ue_admin
container_name: tms-mw-ue_admin
ports:
- '8080:80'
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- back
docker-compose up
如果镜像的版本更新了,需要主动拉取新版本的镜像。
docker-compose pull
开发环境
如果开发环境可以连私有仓库,那么开发环境和测试环境的部署就没有什么区别,如果不通,可以采用手工导入导出镜像的方法。
导出镜像
docker save ID > xxx.tar
导入镜像
docker load < xxx.tar
总结
通过docker可以将代码和它依赖的运行环境打包成一个整体进行发布,通过docker-compose.override.yml
文件修改镜像制作参数,通过启动容器时用-v
选项指定配置文件和数据目录,可以解决设置与特定运行环境相关参数的需求。
按照上面的流程基本可以实现基于docker的版本发布,但是需要手工操作的环节太多,下一步研究如何利用工具将这个过程自动化。