GitLabCI/CD流程

gitlab如果没有和Docker很好的结合。那么它会是一个很平凡的产品。但是有了CI对比其他产品Gogs、github等它还算可堪一用。上一篇文章写了gitlab_ci.yml配置文件的一些参数的含义。本篇文章记录一下如何从零在Gitlab上完成简单的CI/CD流程。基础流程如下Build流程构建我们需要的镜像上传到镜像仓库。部署的时候从镜像仓库直接拉取重启容器
GitlabCI

1. 安装Docker

这个没什么好说的。无脑apt就好了。安装完毕后需要将本地用户加入到Docker用户组。方便命令的执行。在生产环境下需要注意的是最好修改它的默认配置,/etc/docker/daemon.json

1
2
3
4
5
6
7
8
{
"data-root": "/data/docker",
"registry-mirrors": ["https://xxx.mirror.aliyuncs.com"],
"log-opts": {
"max-size": "50m",
"max-file": "3"
}
}
  1. 现在云主机都是低容量系统盘外加高容量挂载盘组成。修改一下默认的根目录会比较好
  2. 没个镜像源下载dockerhub镜像不明智啊
  3. 限定一下最大日志量总没错。否则时间太长日志多了也很烦人

2. 搭建Docker镜像仓库

我使用的是Vmware出品的Harbor。安装中遇到了以下几个坑

  1. 按照文档从源码安装失败。直接下载八百多兆的离线安装包安装好歹算是成功了
  2. 我将HTTPS放到负载均衡上面。实际请求到后端的是http协议。所以我将配置修改为http。但是登陆失败。查了下将common/config/registry/config.yml的token由http改成https可以登陆了。解决了这个然后还不能push…没办法。我将负载均衡改成TCP端口转发。直接将证书放在harbor上。可算是没毛病了
  3. 以前配置过一次Harbor。导致了历史遗留文件。再次安装结果并不会覆盖掉以前的配置也不会做任何提示。
  4. 配置文件里面我改了一下secretkey_path地址。结果无法使用,无奈又改回来了

总结。在Harbor作为宣称的企业级Docker镜像工具。杀手级功能是异地复制,镜像验证。安全扫描啥的。如果只是要搞个基础的镜像仓库。最后想了想还不如折腾Gitlab的Docker仓库。说不定在权限上和Gitlab结合的更好

3. 注册Gitlab-runner

这应该算是CI强大的地方了。它和Gitlab本身松耦合。客户端建立长连接和Gitlab服务器保持通信。当满足条件的时候由Gitlab对Runner进行调度。Gitlab-runner是使用Go编写的,便于部署。当Runner接收到请求的时候它会执行shell脚本。想象一下python界的fabric。依次执行Bash命令。Runner也是差不多的套路。多条Bash命令间是没有相关性的。比如你上一条执行cd demo下一条pwd得到的还是本地用户目录,并不是demo。

  1. 启动gitlab-runner Service
1
2
3
4
docker run -d --name gitlab-runner --restart always \
-v /var/gitlab-runner/config:/etc/gitlab-runner \
-v /var/run/docker.sock:/var/run/docker.sock \
gitlab/gitlab-runner:latest

顺便说一下。要是执行gitlab-runner看它的命令行参数还挺多。其实是自身设计的不太好。显得好像很复杂,很多命令需要被废弃了.它的使用其实还是很简单的。如果你需要看帮助。那么执行gitlab-runner register -h还有点用

  1. 添加Runner
1
2
3
4
docker exec -it gitlab-runner gitlab-runner register -n --tag-list "name" \
-r "token" --name "BigBrother" -u https://gitlab.company.com \
--executor "docker" --docker-image "default_image" \
--docker-volumes /var/run/docker.sock:/var/run/docker.sock
  • n 表示非交互模式
  • tag-list表示该Runner的标签(单独的项目用单独的tag也挺好。互不干扰)
  • r 该项目的token
  • name 名称标识
  • u Gitlab地址
  • executor 和上面说的执行bash命令。有多种方式。无脑用docker挺好
  • docker-image executor选择了docker之后,需要选择默认的镜像
  • docker-volumes 这个是为了在docker里面使用Docker构建镜像

以上两步完成后就能够在Gitlab后台看到正常状态的Runner了

4. 编写.gitlab-ci.yml文件

如果你有丰富的Docker使用经验,这一步实际上没有太大的问题。本例中我只是通过docker build构建了镜像。然后上传到仓库。需要部署的时候使用SSH连接到远程机器上使用docker-compose up --build -d更新程序
Demo项目目录如下。正常本地启动执行python main.py

1
2
3
4
5
6
7
8
9
10
11
12
.
├── README.md
├── conf.py
├── deploy
│   ├── Dockerfile
│   ├── prod_env
│   ├── docker-compose.yml
│   └── stage_env
├── main.py
├── .gitlab-ci.yml
└── requirements.txt

Dockerfile如下

1
2
3
4
5
6
7
8
9
10
11
12
FROM ficapy/python35_alpine

RUN mkdir /app
WORKDIR /app
ENV PYTHONPATH=/app

COPY ./requirements.txt /app/requirements.txt
RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

COPY . /app

CMD ["python", "main.py"]

docker-compose.yml如下

1
2
3
4
5
6
7
8
version: '3'

services:
Name:
image: registry.company.com/repos/projectname:${TAG}
restart: always
env_file:
- ${ENV}_env

.gitlab-ci.yml如下

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
image: ficapy/docker:latest

variables:
SSH: "Host xxxxx"

stages:
- build
- deploy

build:
stage: build
only:
- master
tags:
- tag
script:
- export DOCKER_TAG=$(env TZ='Asia/Shanghai' date -d @$(git log -n1 $CI_COMMIT_SHA --format="%at") +%Y_%m_%d_%H%M%S)
- echo $DOCKER_TAG
- docker login -u deploy -p $DOCKER_PWD registry.company.com
- docker build -t registry.company.com/repos/must_lower_case:$DOCKER_TAG -f deploy/Dockerfile .
- docker push registry.company.com/repos/must_lower_case:$DOCKER_TAG

prod_deploy:
stage: deploy
only:
- master
tags:
- tag
when: manual
variables:
SERVER: ssh_name
before_script:
- export DOCKER_TAG=$(env TZ='Asia/Shanghai' date -d @$(git log -n1 $CI_COMMIT_SHA --format="%at") +%Y_%m_%d_%H%M%S)
- echo $DOCKER_TAG
- eval $(ssh-agent -s)
- bash -c "ssh-add <(echo '$SSH_PRIVATE_KEY')"
- mkdir -p ~/.ssh
- '[[ -f /.dockerenv ]] && echo -e "$SSH" > ~/.ssh/config'
script:
- ssh $SERVER "mkdir -p ~/$CI_PROJECT_NAME || true"
- rsync -r deploy $SERVER:~/$CI_PROJECT_NAME
- ssh $SERVER "docker login -u deploy -p $DOCKER_PWD registry.company.com"
- ssh $SERVER "cd $CI_PROJECT_NAME/deploy && TAG=$DOCKER_TAG ENV=prod docker-compose up --build -d"
environment:
name: PROD

整个过程看配置文件应该还是比较容易理解的。如果有些参数不太明白请查看前一篇gitlabci yml笔记。因为它只是个Demo。所以我让他在每次master分支提交的时候都进行触发。整个部署流程实际上就是使用了SSH远程连接之后操作docker-compose进行更新。过程中感觉让我比较难以决断的是如何搞一个好的TAG方法

总结

完成上述过程之后我做一个自我总结。所谓CI/CD不过是将我们懒得输入的命令组合形成文件。让它依次执行Test->Build->Deploy。该方案几乎使用了全套Docker.从gitlab-runner、build到镜像仓库到生产环境的部署。在项目比较多的时候它是有好处的。比如有十个项目需要更新。每个项目需要更新到多个环境下。那么使用这种自动化还是有优势的。如果就一两个项目,而且只需要更新到测试和生产环境。个人觉得fabric就够了。而且该方案有一个缺点就是部署速度较慢。Gitlab每次执行任务速度并不是想象的那么快。最后生成镜像,上传,再拉取到正式环境。如果镜像过大就更慢了。而如果不使用Docker镜像的方式。直接git pull拉取源码。再supervisorctl更新程序。时间基本是秒级的。在频繁更新的测试环境它可能更高效。