日常项目开发过程中,一般都有多套环境,比如开发、测试和生产。各个环境部署的代码版本不一致,手动一个个来部署效率低且容易出错。如果项目采用了敏捷开发方式,可能每天需要部署几十次。手动方式更加不可行,因此必须要把多环境的部署工作自动化。本文将介绍在笔者参与项目中实际推行的一种方案,供大家参考。
整体方案
当开发人员 push 代码到 develop、release 和 master 分支时将自动触发构建 Docker 镜像,然后部署到分支对应的开发环境。
Git 分支模型
每套环境部署的代码版本都不一样,还在开发中的功能只能部署到开发环境,已经开发完成的功能可以部署到测试环境,测试通过的功能才能部署到生产环境。依托于 Git 强大的分支功能,我们可以轻松地为每个环境维护一个分支,适当的时候在分支之间进行代码的合并。但分支多了容易混乱,开发人员可能搞不清什么时候应该提交到哪个分支。所以团队里需要制定一个分支管理规范,或者说确定一个分支模型。
上图是 Git-flow 的分支模型。图中 develop 和 master 为长线分支,feature、release 和 hotfix 为短线分支。develop、release 和 master 分别部署到开发环境、测试环境和生产环境。develop 分支用来汇总下个版本功能的提交,在下个版本的 release 分支创建之前不允许提交非下个版本的功能到 develop 分支。当下个版本的所有功能开发完成后,从 develop 分支创建下个版本的 release 分支来测试,测试过程中 bug 修复需要提交到该 release 分支。测试完成后,将 release 分支合并到 master 分支去上线,同时还要把 release 分支上的 bug 修复合并回 develop 分支,最后删除 release 分支。
Git-flow 的安装请参考官方文档,安装完成后会给 git 命令增加一个子命令 flow
,使用这个子命令可以简化分支操作。
初始化
为了能在 Git 项目里使用 git flow
命令,需要先初始化 Git-flow。
> git flow init
Initialized empty Git repository in /Users/jagger/tmp/git-flow/.git/
No branches exist yet. Base branches must be created now.
Branch name for production releases: [master]
Branch name for "next release" development: [develop]
How to name your supporting branch prefixes?
Feature branches? [feature/]
Release branches? [release/]
Hotfix branches? [hotfix/]
Support branches? [support/]
Version tag prefix? []
所有需要输入的地方直接回车,使用默认值就可以。
开发
对新功能的开发,如果功能较大建议创建一个 feature 分支来进行,小的话就直接在 develop 分支上进行。当 feature 分支功能开发完成后,合并到 develop 分支,然后删除该 feature 分支。
> git flow feature start rss-feed
Switched to a new branch 'feature/rss-feed'
Summary of actions:
- A new branch 'feature/rss-feed' was created, based on 'develop'
- You are now on branch 'feature/rss-feed'
Now, start committing on your feature. When done, use:
git flow feature finish rss-feed
> git flow feature finish rss-feed
Switched to branch 'develop'
Already up-to-date.
Deleted branch feature/rss-feed (was 810a2a4).
Summary of actions:
- The feature branch 'feature/rss-feed' was merged into 'develop'
- Feature branch 'feature/rss-feed' has been removed
- You are now on branch 'develop'
通过简单的 git flow feature start
和 git flow feature finish
两条指令就能完成上述工作。
测试
当下个版本的功能都已开发完成,就可以从 develop 分支创建下个版本的 release 分支来测试。测试过程中的 bug 修复需要提交到该 release 分支。
> git flow release start 2.0
Switched to a new branch 'release/2.0'
Summary of actions:
- A new branch 'release/2.0' was created, based on 'develop'
- You are now on branch 'release/2.0'
Follow-up actions:
- Bump the version number now!
- Start committing last-minute fixes in preparing your release
- When done, run:
git flow release finish '2.0'
发布
测试通过后,合并 release 分支到 master 和 develop 分支,然后删除 release 分支。
> git flow release finish 2.0
Switched to branch 'master'
Deleted branch release/2.0 (was 810a2a4).
Summary of actions:
- Latest objects have been fetched from 'origin'
- Release branch has been merged into 'master'
- The release was tagged '2.0'
- Release branch has been back-merged into 'develop'
- Release branch 'release/2.0' has been deleted
Docker 自动化部署
各个环境的分支代码都有了,但怎么快速可靠地把分支代码部署到对应环境了?使用 Docker 可以大大简化部署的复杂性,因为它解决了应用对系统环境的依赖问题,使得应用部署变成了一项十分简单的工作。借助于 GitLab Webhook 和 容器编排服务,可以实现当分支代码有 push 的时候,自动把该分支代码部署到对应环境。
这里以 DaoCloud 容器编排服务为例来讲解。当然大家可以选择任意其它第三方或自己搭建的容器编排服务,操作方式都类似。
创建项目
一个项目对应一个 Git 仓库,项目存在的目的是为了构建和部署应用镜像。DaoCloud 除了支持 GitHub、Bitbucket 这类公有服务,自己搭建的 GitLab 服务也支持。
每次分支代码有 push 的时候,都会触发构建镜像。
通过流程定义来配置要执行的操作和顺序,一般按照“测试 => 构建 => 部署”这样的流程。每个操作都可以单独配置触发条件,比如 push 到指定分支。
创建主机集群
主机集群由安装了 Docker Engine 的多台服务器构成,通过在服务器上安装 DaoCloud Monitor 来把它加入到某个主机集群。部署应用时需指定用来运行应用的主机集群,或者集群里的某台服务器。
上面的 dev 集群只包含一台本地的 MacBook Pro。
编排应用
编排应用就是把应用编制排放到主机集群上去运行。大多数时候应用都依赖其它后端服务,比如 MySQL、Redis 等,启动应用时需要把它们一起启动起来,并且相互之间可互相访问。这样的一组应用在 Docker Compose 里称为 Stack。
下面我们创建了三个开发环境的 Stack,分别为应用服务 Stack zqc-dev,数据库服务 Stack db-dev,缓存服务 cache-dev。之所以不把数据库和缓存服务跟应用服务放在一个 Stack 里,是因为数据库和缓存服务属于公共服务,会被多个应用服务共享,放在某个应用服务里不合适。
Docker Compose 会为每个 Stack 创建一个默认的网络,以便 Stack 里的各个服务之间可以互相访问。那么 Stack 之间了?zqc-dev 需要访问 db-dev 里的数据库服务和 cache-dev 里的缓存服务。很简单,只要把 zqc-dev 里的应用服务加入到 db-dev 和 cache-dev 的网络里就可以了。具体可参考下面的应用服务 Docker Compose 配置文件。
应用服务 Stack。
version: '2'
services:
zqc-server:
image: daocloud.io/jaggerwang/zqc-server:develop-6be5996
environment:
ZQC_DIR_DATA: /data
ZQC_SERVER_DEBUG: 'true'
ZQC_SESSION_SECRETKEY: xxxxxxxx
ZQC_LOG_LEVEL: debug
ZQC_MONGODB_ZQC_ADDRS: mongo:27017
ZQC_REDIS_ZQC_ADDRESS: redis:6379
ZQC_REDIS_ZQC_DB: 1
ZQC_STORAGE_BUCKETS_ZQC_ENDPOINT: oss-cn-shanghai.aliyuncs.com
ports:
- 10200:1323
volumes:
- /Users/jagger/data/zqc/server:/data
networks:
- db-dev
- cache-dev
networks:
db-dev:
external:
name: db-dev_default
cache-dev:
external:
name: cache-dev_default
应用服务 Docker Compose 配置文件。
数据库服务 Stack。
version: '2'
services:
mysql:
image: index.docker.io/library/mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: xxxxxxxx
ports:
- 10000:3306
volumes:
- /Users/jagger/data/db/mysql:/var/lib/mysql
mongo:
image: index.docker.io/library/mongo:3.4
ports:
- 10001:27017
volumes:
- /Users/jagger/data/db/mongodb:/data/db
数据库服务 Docker Compose 配置文件。
缓存服务 Stack。
version: '2'
services:
redis:
image: redis:4.0
command:
- redis-server
- --appendonly
- 'yes'
ports:
- 10010:6379
volumes:
- /Users/jagger/data/cache/redis:/data
缓存服务 Docker Compose 配置文件。
参考资料
本文转自 https://blog.jaggerwang.net/git-docker-multiple-env-deploy/,如有侵权,请联系删除。