Git + Docker 多环境自动化部署

威尔we
• 阅读 2123

日常项目开发过程中,一般都有多套环境,比如开发、测试和生产。各个环境部署的代码版本不一致,手动一个个来部署效率低且容易出错。如果项目采用了敏捷开发方式,可能每天需要部署几十次。手动方式更加不可行,因此必须要把多环境的部署工作自动化。本文将介绍在笔者参与项目中实际推行的一种方案,供大家参考。

整体方案

Git + Docker 多环境自动化部署

当开发人员 push 代码到 develop、release 和 master 分支时将自动触发构建 Docker 镜像,然后部署到分支对应的开发环境。

Git 分支模型

每套环境部署的代码版本都不一样,还在开发中的功能只能部署到开发环境,已经开发完成的功能可以部署到测试环境,测试通过的功能才能部署到生产环境。依托于 Git 强大的分支功能,我们可以轻松地为每个环境维护一个分支,适当的时候在分支之间进行代码的合并。但分支多了容易混乱,开发人员可能搞不清什么时候应该提交到哪个分支。所以团队里需要制定一个分支管理规范,或者说确定一个分支模型。

Git + Docker 多环境自动化部署

上图是 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 startgit 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 服务也支持。

Git + Docker 多环境自动化部署

每次分支代码有 push 的时候,都会触发构建镜像。

Git + Docker 多环境自动化部署

通过流程定义来配置要执行的操作和顺序,一般按照“测试 => 构建 => 部署”这样的流程。每个操作都可以单独配置触发条件,比如 push 到指定分支。

创建主机集群

主机集群由安装了 Docker Engine 的多台服务器构成,通过在服务器上安装 DaoCloud Monitor 来把它加入到某个主机集群。部署应用时需指定用来运行应用的主机集群,或者集群里的某台服务器。

Git + Docker 多环境自动化部署

上面的 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 配置文件。

Git + Docker 多环境自动化部署

应用服务 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 配置文件。

Git + Docker 多环境自动化部署

数据库服务 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 配置文件。

Git + Docker 多环境自动化部署

缓存服务 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 配置文件。

参考资料

  1. Git-flow
  2. Docker Compose

本文转自 https://blog.jaggerwang.net/git-docker-multiple-env-deploy/,如有侵权,请联系删除。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Android蓝牙连接汽车OBD设备
//设备连接public class BluetoothConnect implements Runnable {    private static final UUID CONNECT_UUID  UUID.fromString("0000110100001000800000805F9B34FB");
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这