CI/CD笔记-gitLab之ci/cd
一、概念普及
- CI/CD
- gitlab CI/CD
- gitlab-Job
- gitlab-Pipeline
- gitlab-Stage
- 什么是.gitlab-ci.yml文件
- .gitlab-ci.yml文件介绍
variables
default
stages
stage
script
before_script 和after_script
only 和 except
tags
allow_failure
when
gitlab预设变量
二、实验环境
三、前期准备
四. 配置Runner - 安装runner
- 获取runner需要的gitlab地址及gitlab之CI的token
- 注册runner
- gitlab上查看是否注册成功
- 写一个测试项目及相关的Dockerfile与gitlabci.yml文件
五、卸载gitlab-runner
一、概念普及
1. CI/CD
CI(continuous integration):持续集成,即在代码构建过程中持续地进行代码的集成、构建、以及自动化测试等;有了 CI 工具,我们可以在代码提交的过程中通过单元测试等尽早地发现引入的错误。 CD(continuous Deployment):持续交付,在代码构建完毕后,可以方便地将新版本部署上线,这样有利于快速迭代并交付产品。
2. gitlab CI/CD
GitLab CI/CD(后简称 GitLab CI)是一套基于 GitLab 的 CI/CD 系统,可以让开发人员通过 .gitlab-ci.yml 在项目中配置 CI/CD 流程,在提交后,系统可以自动/手动地执行任务,完成 CI/CD 操作。而且,它的配置非常简单,CI Runner 由 Go 语言编写,最终打包成单文件,所以只需要一个 Runner 程序、以及一个用于运行 jobs 的执行平台(如裸机+SSH,Docker 或 Kubernetes 等,我推荐用 Docker,因为搭建相当容易)即可运行一套完整的 CI/CD 系统。
3. gitlab-Job
Job 为任务,是 GitLab CI 系统中可以独立控制并运行的最小单位。在提交代码后,开发者可以针对特定的 commit完成一个或多个 job,从而进行 CI/CD 操作。作业就是运行器(Runner)要执行的指令集合,Job 可以被关联到一个 Stage。当一个 Stage 执行的时候,与其关联的所有 Job 都会被执行。在有足够运行器的前提下,同一阶段的所有作业会并发执行。作业状态与阶段状态是一样的,实际上,阶段的状态就是继承自作业的。作业必须包含script(由Runner执行的shell脚本),随着项目越来越大,Job 越来越多,Job 中包含的重复逻辑可能会让配置文件臃肿不堪。.gitlab-ci.yml 中提供了 before_script 和 after_script 两个全局配置项。这两个配置项在所有 Job 的 script 执行前和执行后调用。Job 的执行过程中往往会产生一些数据,默认情况下 GitLab Runner 会保存 Job 生成的这些数据,然后在下一个 Job 执行之前(甚至不局限于当次 CI/CD)将这些数据恢复。这样即便是不同的 Job 运行在不同的 Runner 上,它也能看到彼此生成的数据。
4. gitlab-Pipeline
Pipeline 即流水线,可以像流水线一样执行多个 Job. 在代码提交或 被合并时,GitLab 可以在最新生成的 commit上建立一个 pipeline,在同一个 pipeline 上产生的多个任务中,所用到的代码版本是一致的。
5. gitlab-Stage
一般的流水线通常会分为几段;在 pipeline中,可以将多个任务划分在多个阶段中,只有当前一阶段的所有任务都执行成功后,下一阶段的任务才可被执行。
注:如果某一阶段的任务均被设定为“允许失败”,那这个阶段的任务执行情况,不会影响到下一阶段的执行。
CI Pipeline
上图中,整条流水线从左向右依次执行,每一列均为一个阶段,而列中的每个可操控元素均为任务。左边两个阶段的任务是自动执行的任务,在commit提交后即可自动开始运行,执行成功或失败后,可以点击任务右边的按钮重试;而右边两个是手动触发任务,需要人工点击右边的“播放”按钮来手动运行。
6. 什么是.gitlab-ci.yml文件
官方文档:https://docs.gitlab.com/ee/ci/yaml/README.html#parameter-details
GitLab CI使用YAML文件(.gitlab-ci.yml)来管理项目配置。该文件存放于项目仓库的根目录,并且包含了你的项目如何被编译的描述语句,YAML文件使用一系列约束叙述定义了Job启动时所要做的事情。
Job是.gitlab-ci.yml文件中最基本的元素,由一系列参数定义了任务启动时所要做的事情,用户可以创建任意个任务;每个任务必须有一个独一无二的名字,但有一些保留keywords不能用于Job名称,image,services,stages,types,before_script,after_script,variables,cache,include。
Job被定义为顶级元素,并且至少包括一条script语句,如果一个 Job 没有显式地关联某个 Stage,则会被默认关联到 test 阶段。
job1:# 关联到bulid阶段stage: build# 所需执行的脚本script:- execute-script-for-job1
7. .gitlab-ci.yml文件介绍
variables
用于自定义可用于所有job的全局变量,这个关键字也可以在每个job中单独定义,相同变量名时,优先级是先job再全局
variables:SERVICE_ENV: R1APPNAME: AI-DATA
default
全局默认值,即为了简便不用重复设置每个任务中相同关键字对应的相同的值,如每个job应用相同的镜像名,就可以在default下配置,则如果job中没有配置自己的镜像则使用default中的,default中支持以下关键字
image,services,before_script,after_script,tags,cache,artifacts,retry,timeout,interruptible
default:image: base-python2:v1stages:- build- deploybuild-app-job:stage: buildscript: "run build script file"only:- branchesbuild-mysql-job:stage: buildimage: mysql6:v1script: "do something"stages
用于定义所有作业job可以使用的全局阶段,gitlab-ci.yml允许定义多个阶段,stages元素的顺序定义了作业执行的顺序。Job关联的stage名相同时,该多个Job将并行执行(在拥有足够Runner情况下),下一个阶段的Job将会在前一个阶段的job都完成的情况下执行。
如果没有定义stages,那么默认包含build,test,deploy 三个stage,stage中并不能直接配置任何具体的执行逻辑,具体的执行逻辑应该在Job中配置。
stages:- build- test- deploy
stage
为每个任务Job指定其属于那个阶段,其依赖stages中定义好的阶段
script
script 是一系列通过Runner来执行的shell脚本,也可以直接执行shell命令
有些时候,script命令需要被单引号或者双引号所包裹。举个例子,命令中包涵冒号的时候,该命令需要被引号所包裹,这样YAML解析器才知道该命令语句不是“key: value”语法的一部分。当命令中包涵以下字符时需要注意打引号:: { } [ ] , & * #? | - < > = ! % @
test-job1: # 每个任务必须指定阶段(stage)和对应要做的任务(script)stage: testscript: - ehco "执行对应写好的需要runner执行的命令或脚本,多个命令这样写" - uname -a - echo "hello,$GITLAB_USER_LOGIN"test-job2:stage: testscript: echo "如果只是一条命令可以直接在这个后面写"
- image 和 services
官方文档:https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#define-image-and-services-from-gitlab-ciyml
这两个关键字定义运行时,docker的镜像名和需要用到的已经存在运行的服务名,前提是注册runner时选择的是docker而不是shell
build-job:image:access-web:v1services: # 定义构建access-web镜像时可以访问服务名- mysql:v1
before_script 和after_script
定义一些在所有任务Job执行前或之后需要执行的命令,每个任务Job中如果定义了,就执行自己的,全局的就不会执行
# 定义全局before_scriptdefault:before_script: - global before script# 覆盖全局的before_scripttest-job1:before_script: - 执行自己的在本任务执行前要做的事script: - uname -aafter_script: - 执行命令等等
only 和 except
更多参考官方文档:https://docs.gitlab.com/ee/ci/yaml/README.html#onlyexcept-basic
如果任务job没有指定only关键字,默认是所有的分支push或标签创建时当做触发条件,except默认为空即不过滤
only和except都是定义job什么时候会被触发创建,only和except可以使用正则,可以指定仓库地址,可以同时用;
only定义了job是以分支还是标签提交时被触发;
except定义了job在某个分支或标签提交时不会被执行;
only和except可以使用的一些关键字:
job1:stage: testscript: echo "do something"only: # 仅以开头以issue-的引用的时候被触发,而所有分支均被过跳过 # 通过正则默认区分大小写,如果想不区分需要后面加i,即/^issue-.*$/i - /^issue-.*$/except: - branchesjob2:stage: testscript: echo "do something"only: # 仅为分支标记了标签、或者通过api请求、或者定时任务时才会运行次job - tags - triggers - schedulesjob3:stage: testscript: echo "do anything"only: # 指定仓库所有的分支都会被触发- branches@仓库地址except: # master分支不会被触发本任务- master@仓库地址 # 以release开头的命名的也不会被触发- /^release/.*$/@仓库地址
tags
用于指定注册的某个runner来运行任务,注册runner时有为每个runner设置标签,这里就是匹配那个的
job:tags: # 如果指定多个标签,那么那些标签必须某个running都有关联才会调用- python-runner
allow_failure
允许某个任务失败不影响CI的其他任务执行结果,默认是false即不允许失败
job1:stage: testscript: "本任务执行成功与否不影响job2的执行"allow_failure: truejob2:stage: testscript: "本人必须运行成功后面的任务才会被执行"
when
用于实现发生故障或发生故障时运行的作业
when支持的值如下:
on_success(默认) 早期所有的作业都成功或者视为成功的all_failure:true
on_failure仅在早期至少一个作业失败时运行
always 无论早期作业结果如何都执行
manual 手动执行
delayed 延迟指定的时间再执行,gitlab11.14中新增
- never 使用rules,不执行,使用workflow:rules ,不要运行管道
job:stage: deployscript:- make deploywhen:manual
gitlab预设变量
官方文档:https://docs.gitlab.com/ee/ci/variables/predefined_variables.html#predefined-environment-variables-reference
用于获取gitlab用于ci/cd 预设的一些环境变量如获取分支名CI_COMMIT_BRANCH
docker build:script: docker build -t my-image:$CI_COMMIT_REF_SLUG .rules: - if: '$CI_COMMIT_BRANCH == "master"' when: delayed start_in: '3 hours' allow_failure: true
gitlab-runner安装在服务部署的机器上,其自动根据你在gitlab-ci.yml中规定的触发条件如某个分支提交后执行,其首先会自动从gitlab仓库上拉取仓库代码到服务器本地,然后根据gitlab-ci文件定义的job执行,如打包文件构建镜像,然后部署服务【多台可以通过建立docker swarm集群的模式,在本地部署一个,会自动分布到多台】
二、实验环境
系统:centos8.0_x64
gitlab: 192.168.0.152:8888
docker-swarm集群:192.168.0.150【master】192.168.0.153【slave】
docker仓库:192.168.0.150:5000
- gitlab-runner:192.168.0.150
三、前期准备
搭建gitlab:请参考:https://mp.weixin.qq.com/s/amWWG34BXoTAumy1p4SnvA
搭建docker集群请参考:https://mp.weixin.qq.com/s/cIkPOnna9u0h1AMbz4aOjw
搭建docker私有仓库请参考:https://mp.weixin.qq.com/s/4KI3fqyJFv5yJI_H_HK0RA
- 构建python3的基础镜像
# 1. 直接重docker-hub上拉取centos系统docker pull centos# 2. 构建一个容器docker run --name=genPython -it centos /bin/bash# 3. 换yum仓库mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-8.repo && yum clean all && yum makecache# 4. 安装python3yum -y install python38# 5. 查看Python安装whereis pythonpython3 --versionpip3 list# 6. 退出容器,将刚才改变的容器生成新的镜像`docker commit 容器id 仓库/新的镜像名:标签`docker commit 0426a83fc666 192.168.0.150:5000/python3:v1# 7. 推送到私有仓库,需要先配置本地docker配置文件指定仓库地址vim /etc/docker/daemon.json{"registry-mirrors": ["192.168.0.150:5000"], # 加速的地址"insecure-registries" : ["192.168.0.150:5000"]}systemctl daemon-reload && systemctl restart dockerdocker push 192.168.0.150:5000/python3:v1注为了方便也将其推送到dockerhub上docker logindocker tag 192.168.0.150:5000/python3:v1 addmoney2018/python3:v1docker push addmoney2018/python3:v1
四. 配置Runner
1. 安装runner
官方文档:https://docs.gitlab.com/runner/install/
### 在192.168.0.150上,只有安装在集群管理节点上,才能通过docker swarm集群部署到多台上# 下载二进制文件并写入文件gitlab-runner# Linux x86-64curl -L --output /usr/local/bin/gitlab-runner "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64"# 授予其执行权限chmod +x /usr/local/bin/gitlab-runner# 创建一个GitLab CI用户useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash# 修改gitlab-runner密码echo "gitlab-runner" | passwd --stdin gitlab-runner# 安装并作为服务运行gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner# 将服务添加到开启启动chkconfig gitlab-runner on# 启动gitlab-runner start# 经过实践发现runner执行docker命令时会报权限不够,因此需要加权usermod -aG docker gitlab-runner# 测试下sudo -u gitlab-runner -H docker info注:之后想修改上面指定的用户或工作目录修改这个文件即可:/etc/systemd/system/gitlab-runner.service
2. 获取runner需要的gitlab地址及gitlab之CI的token
登陆gitlab---选择对应的仓库---选择仓库的setting---选择CI/CD---选择Runners的expand----复制下图中地址和token
- 注册runner
官方文档:https://docs.gitlab.com/runner/register/index.html
注意:
如果选择的runner执行模式是docker,则runner中的job会在指定的基础镜像中执行,因此需要你指定的镜像里可以执行ci文件中定义的命令,如docker build
如果选择的runner执行模式是shell,即在runner服务安装的物理机执行,因此你如果不是通过容器安装runner,而想通过runner打镜像,建议通过shell模式
# 执行如下命令gitlab-runner register[root@gitlab bin]# gitlab-runner registerRuntime platform arch=amd64 os=linux pid=10254 revision=943fc252 version=13.7.0Running in system-mode. # 输入gitlab实例地址 Enter the GitLab instance URL (for example, https://gitlab.com/):http://192.168.0.152:8888/# 输入runner的tokenEnter the registration token:WecGC7zY9otwQgdss7yZ# 输入这个runner的描述Enter a description for the runner:[gitlab.example.com]: try to run a python service# 输入这个runner的标签,每个标签用逗号隔开【用于区分不同类型的 Runner,使不同阶段的 job 在不同的 Runner 中运行】Enter tags for the runner (comma-separated):Python3-runnerRegistering runner... succeeded runner=WecGC7zY# 选择执行runner的方式Enter an executor: docker-ssh, parallels, docker-ssh+machine, custom, shell, ssh, virtualbox, docker+machine, kubernetes, docker:dockerEnter the default Docker image (for example, ruby:2.6): # 指定基础镜像,注意本地你需要先下载docker镜像,将其推动到你得私有仓库,因为你本地daemon.json配置了本地仓库,runner就是在指定得镜像中构建得192.168.0.150:5000/dockerRunner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!# 重启下runnergitlab-runner restart# 注如果想更改上面得配置vi /etc/gitlab-runner/config.toml
4. gitlab上查看是否注册成功
5. 写一个测试项目及相关的Dockerfile与gitlabci.yml文件
- 项目目录结构
test-runner
- main.py
- requirements.txt
- .gitlab-ci.yml
- Dockerfile
docker-compose.yml
- Dockerfile文件
FROM 192.168.0.150:5000/python3:v1# 创建容器中的服务根目录RUN mkdir -p /app/code/# 拷贝代码到容器中COPY . /app/code/test-gitlab01# 指定工作目录WORKDIR /app/code/test-gitlab01# 安装依赖RUN pip3 install --no-cache-dir -r /app/code/test-gitlab01/requirements.txt -i http://pypi.douban.com/simple --trusted-host pypi.douban.com# 映射端口EXPOSE 8100# 启动CMD ["python3","main.py"]
- .gitlab-ci.yml文件
variables:SERVICE_ENV: R1IMAGE_NAME: python-test-app:v3DOCKER_FILE_PATH: .DOCKER_HUB: 192.168.0.150:5000/stages:- build- test- deploybuild-app:stage: buildonly: # 仅当什么事件发生就触发本任务: 发生推送 - masterscript: - echo "开始执行构建app的阶段" - echo "环境为:$SERVICE_ENV" - echo "runner为shell模式就在物理机上执行下面得命令" - echo "当前位置:$(pwd),当前的主机名:$(hostname)" - echo "当前目录下的文件:$(ls -lrt)" - docker build -t $IMAGE_NAME $DOCKER_FILE_PATH - docker tag $IMAGE_NAME $DOCKER_HUB$IMAGE_NAME - docker push $DOCKER_HUB$IMAGE_NAME - echo "构建镜像成功!"tags: # 指定某个runner执行本任务 - python-shell-runnertest-app:stage: testonly: - masterscript: - echo "开始测试阶段" - echo "查看镜像是否推送到仓库:$(curl http://192.168.0.150:5000/v2/_catalog)" - export TEST_PORT=$RANDOM - docker run -d -p $TEST_PORT:8100 $DOCKER_HUB$IMAGE_NAME - sleep 3 - curl http://192.168.0.150:$TEST_PORT - echo "测试阶段完成!"tags: - python-shell-runnerdeploy-app:stage: deployonly: - masterscript: - echo "开始部署服务阶段" - echo "当前位置:$(pwd)" - echo "当前目录下的文件:$(ls -lrt)" - docker stack deploy -c docker-compose.yml web - sleep 3 - docker service ls - docker service ps web_python-test-web - curl http://192.168.0.150:8100 - echo "部署阶段完成"tags: - python-shell-runner
- docker-compose.yml文件
version: '3'services:python-test-web: image: 192.168.0.150:5000/python-test-app:v3 ports: - 8100:8100 restart: always deploy: replicas: 2 restart_policy: condition: on-failure volumes: - /etc/localtime:/etc/localtime networks: - python-netnetworks:python-net:
- main.py文件
# _*_ coding:utf-8 _*_# DevVersion: Python3.6.8# Date: 2021-01-01 18:10# Author: Sun# PyCharm|mainfrom flask import Flaskapp = Flask(__name__)@app.route("/")def index(): return {"message": "happy new year 2021"}if __name__ == '__main__': app.run("0.0.0.0", "8100")
- requirements.txt文件
click==7.1.2
Flask==1.1.2
itsdangerous==1.1.0
Jinja2==2.11.2
MarkupSafe==1.1.1
Werkzeug==1.0.1
![](https://s4.51cto.com/images/blog/202104/04/cf56f16dd104efb09a8ee88071da1aa6.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)![](https://s4.51cto.com/images/blog/202104/04/da96908ee6ac946521adddc74520da6f.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)![](https://s4.51cto.com/images/blog/202104/04/f4348ba639e754ef8650dbeddc29e28d.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)![](https://s4.51cto.com/images/blog/202104/04/b81d453d6970565495c448d24b031f77.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)![](https://s4.51cto.com/images/blog/202104/04/b376728f1ee146bd96d264f7b88632b7.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)**五、卸载gitlab-runner**
关闭gitlab-runnergitlab-runner stop
关闭开启启动chkconfig gitlab-runner off
卸载gitlab-runner uninstall
删除安装目录rm -rf /etc/gitlab-runner/
rm -rf /usr/local/bin/gitlab-runner
userdel -r gitlab-runner