都9012年了,你还在手动部署代码吗(二)

前言

在写完基于 Webhooks 的“第一篇《都9012年了,你还在手动部署代码吗》”之后,有同学评论到”至少你得用个 docker 啊””一对一嘛…感觉面试吹这个会被吊起来锤”….于是我决定出一篇基于 Docker 的自动部署文章 (:

这是一篇利用 Docker 和 Gitlab-CI 的学习自动部署和实践的笔记,如果您是 Docker 资深玩家,跪求大佬不要吊锤;如果您是萌新,刚开始 Docker 学习之旅,那么希望笔记中的理解和操作能够对您有所帮助.

然鹅,饱和的需求和人的惰性让第二篇拖到了今天ORZ!!! 王者峡谷一时爽,一直王者一直爽

背景

偷懒是第一生产力,当你享受过自动化带给你的便捷时,再也不会想回到手动打包部署上传的”石器时代”.

目标

在本地开发完成 push 后,集成环境能够自动完成测试部署打包上传 FTP

前置条件
  1. 位于内网服务器的 Gitlab 源码仓库(版本支持 Gitlab-CI )
  2. 位于内网服务器的集成测试环境(能够 Pull 远程仓库代码)
  3. 集成测试服务器能够安装 Docker

行动

工欲善其事必先利其器,开始行动前有必要理解一波 Docker 和 Gitlab-CI 自动部署原理;

这波要理解的东西有点多,不过不慌,我们一个一个来 !

Docker

Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口. 它将应用程序与该程序的依赖,打包在一个文件里面. 运行这个文件,就会生成一个虚拟容器. 程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样. 有了 Docker,就不用担心环境问题.

Docker 容器常常拿来和虚拟机 VM 相比较,提到 VM ,就不得不说….别提了,我还记得当年在大学的虚拟机课程,等虚拟机启动的时间里,老师可以寂寞地抽完几根烟…

有几个概念我们需要理解一下:

  • Image (镜像)
  • Container (容器): 运行镜像
  • Repository (仓库): 储存镜像

我们首先根据文档在集成服务器上安装 Docker => CentOS7上安装Docker

不建议各位同学在window系统上尝试 Docker ,过程及其残忍

1
2
3
4
5
6
7
8
9
我在这次部署中常用的docker命令:
docker search NAME 搜索image镜像
docker pull NAME 拉取image镜像
docker run -d -p 2222:22 --name NAME <IMAGE> 后台运行IMAGE命名为NAME并映射容器端口22到宿主机端口2222(-d:后台运行 -p:端口映射)
docker ps 查看正在运行的docker容器
docker images 查看本地所有镜像
docker stop NAME 停止容器
docker rm 删除容器
docker exec -it <IMAGE> bash 以伪终端交互方式进入容器,运行bash
理解Gitlab-CI自动部署原理

本地仓库 -> (push提交代码) -> 远程仓库(Gitlab-CI) -> (通知注册完成的runner) -> 集成服务器(runner Executor执行命令)-> 打包上传FTP

通过简单的比较我们可以发现,整个流程和使用 webhooks 并无太大差别,但是区别于webhooks 使用 Token 请求具体服务, Gitlab-CI 会找出与这个工程相关联的Runner,并通知这些Runner, 然后这些Runner在宿主机上更新代码, 进行测试, 自动部署, 打包上传.

我们可以把 Gitlab-CI 和 Runner 看做工厂和工人的关系, 工人在工厂里先注册, 工厂开工的时候通知工人干活 ~

配置远程仓库Gitlab-CI

理解完原理后我们来配置(搞定)Gitlab-CI(Gitlab-8.0版本以后默认集成Gitlab-CI):

找到项目 Project 的 Settings 中的 CI/CD, 点击 Runners settings.这时你会发现两种 Runners:

  • Shared Runners: 管理员才有资格创建的所有工程都能使用的 Runner
  • Specific Runners: 拥有访问权限的人为指定工程创建的 Runner

这里我们使用 Specific Runner, 记住 Specific Runner 配置里的 URLtoken, 等下我们就是利用这两个参数在集成服务器配置 Runner 和 Gitlab-CI 建立联系 !

集成服务器(宿主机)配置

这里 Gitlab-runner 的安装方式分两种:

  • 使用 yum install gitlab-ci-multi-runner安装
  • 使用 Docker 安装 Gitlab-runner

我们这里使用 Docker 安装 Gitlab-runner , 注意: 操作前修改 Docker 镜像源为国内源

ps: 注意一下 Gitlab 和 Gitlab-runner 的版本是否匹配, 否则 runner 可能连不上 Gitlab-CI

1
2
3
4
5
6
7
8
9
10
11
12
下载Gitlab-runner
docker search gitlab-runner
docker pull gitlab/gitlab-runner

运行Gitlab-runner,将容器gitlab-runner config.toml映射到主机,方便修改
docker run -d --name gitlab-runner --restart always
-v /data/docker/gitlab-runner/config:/etc/gitlab-runner \
-v /var/run/docker.sock:/var/run/docker.sock \
gitlab/gitlab-runner

进入Gitlab-runner bash
docker exec -it gitlab-runner bash
Gitlab-runner注册runner
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
gitlab-runner register

Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
gitlab-ci URL

Please enter the gitlab-ci token for this runner:
gitlab-ci Token

Please enter the gitlab-ci description for this runner:
输入runner名字/描述即可

Please enter the gitlab-ci tags for this runner (comma separated):
输入runner的tag *后面编辑.gitlab-ci.yml需要用到这个tag

Whether to run untagged builds [true/false]:
[false]: 是否运行没有tag的构建

Whether to loack the Runner to current project [true/false]:
[true]: 是否锁定此Runner到正确的project

Registering runner... succeeded runner=******
Please enter the executor: docker, docker-ssh, shell, ssh, docker-ssh+machine, kubernetes, parallels, virtualbox, docker+machine:
选择执行器类型 这里我们选docker

Please enter the default Docker iamge (e.g. ruby: 2.1):
选择执行Docker运行的image镜像 这里我打包了一个服务node环境镜像到本地使用 如果项目服务需要什么依赖,比如数据库之类的也可以打包到镜像中

Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded !
此时Runner创建成功!

docker restart gitlab-runner
重启一下gitlab-runner

此时我们刷新 Gitlab-CI -> Settings -> CI/CD -> Runners settings 页面可以看到我们刚刚注册的 Runner 已经出现了 !

项目 .gitlab-ci.yml 配置

Gitlab-CI 会在仓库发生 push 时通知 Runner 执行脚本动作,具体的脚本动作就需要我们在项目目中新建 .gitlab-ci.yml 编写:

小贴士:

stages 可以拥有多个不重名的 job

我们可以根据自己项目的实际情况编写属于自己的 job

script 定义由Runner执行的shell脚本或命令

before_script 覆盖在作业之前执行的脚本或命令

tags 定义job所适用的runner,tags为runner标签

cache 定义需要被缓存的文件、文件夹列表

具体更多配置推荐阅读官方文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 这是我的 .gitlab-ci.yml
stages:
- test
- deploy
- package

# 测试job
test:
stage: test
script:
- npm config set registry https://registry.npm.taobao.org
- npm i
- npm run test
cache:
# key: "$CI_BUILD_REF_NAME"
paths:
- node_modules
tags:
- ego

# 部署job
deploy-dev:
stage: deploy
before_script:
- echo "Start to deploy to dev host"
script:
- echo "deploy front ...."
- sh deploy-front.sh
- echo "deploy backend ...."
- sh ./app/deploy-backend.sh
only:
- /^release\/.*/
tags:
- dennis
- node

# 打包job
package:
stage: package
before_script:
- echo "Start to deploy to dev host"
only:
- /^release\/.*/
script:
- echo "start package..."
- sh package.sh $VERSION
when: manual
tags:
- dennis
- node

Gitlab CI/CD 的 Pipelines 中每一次提交的 stages 就是根据 .gitlab-ci.yml 中的配置形成的, 你可以在Pipelines 中看到你每一次提交的 job 执行情况(成功/失败/等待/取消等状态), 因为网络情况的失败除了可以自动重试外, 我们还可以手动点击重试.

这里的 deploy-front.sh deploy-backend.sh package.sh 前后端部署打包命令就不详细展示了,大家可以根据自己的项目实际情况编写.

ps: 这里要注意一下脚本命令在环境中的执行权限

最后,今天的文章到这里就差不多要结束了,其实当中每个部分都可以深入学习很久,我在文章中也是最粗浅的运用,总目标都是为搭建一整套流程,运行畅通服务,如果您对其中某个部分比如 Dokcer , .gitliab-ci.yml 感兴趣,可以自主深入学习,我也在文章中给出了官网文档~

有关多机部署

虽然Runner可以分布在不同的主机上,同一个主机上也可以有多个Runner。难道我们要在每个部署服务器上都安装运行 Gitlab-runner 吗 ? 这里引用我第一篇文章中 @Axetroy老哥的评论:

恕我直言,服务端需要安装配套工具(服务)的,都是垃圾。

有 10 机器,就得给这 10 台机器安装工具(服务),例如这里是用 nodejs 写的 hook 接受服务 (当然可以解决,自己基于 centerOS 打包一个 Docker 镜像,内置 nodejs 和 hook 服务,然后这 10 台机器就以这个镜像开启。当然这并不是所有的服务器商都支持自定义镜像)

能纯客户端部署的,才是好的。在 CI 构建成功的阶段,只要 CI 的环境变量服务器 IP,端口,用户名和密码,就能通过 SSH 部署。

结果

好了, 又构建失败发邮件了,待我去看看什么问题 (:

最后的最后感谢强哥,在我学习使用 Docker 和 Gitlab-CI 的过程中给予的巨大帮助 ! ! !