8.3. 为所有作业设置默认值before_script或after_script
-
Gitlab简介
GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的web服务。GitLab和GitHub一样属于第三方基于Git开发的作品,免费且开源(基于MIT协议),与Github类似, 可以注册用户,任意提交你的代码,添加SSHKey等等。不同的是,GitLab是可以部署到自己的服务器 上,数据库等一切信息都掌握在自己手上,适合团队内部协作开发
此文档主要为明确代码托管工具gitlab使用流程,描述代码仓库的常用功能使用指导,阐述清楚各场景下必须遵守的使用规范,为自动化运维相关工作实施提供依据。
维护gitlab服务器与应用,管理人员与仓库访问权限编写运维脚本,配置流水线分析执行结果和预期,生产执行和分析优化
- 开发工程师:
使用仓库托管代码,同步本地代码,合并代码,代码复审,进行代码审查、分支合并管理
- 测试工程师:
查看测试测试报告,测试分析执行结果和预期,代码管理规范性检查
本文相关名词定义如下:
名称 | 说明 |
gitlab-ci | GitLab CI是GitLab用于协调jobs的开源持续集成服务件 |
gitlab-runner | GitLab Runner是一个开源项目,用于运行你的作业(jobs)并将结果发送回GitLab |
- 通过commit/tag等方式自动触发测试、构建或部署
- 远程服务器执行测试与构建,节省本地计算资源
- Gitlab 仓库不再管理打包后文件,避免仓库过大问题
- 可以方便地进行代码规范检测、单元测试等,使代码更可靠
部署GitLab的实例要求至少使用2个vCPU和4GiB的内存,示例操作系统:Ubuntu 20.04
第1步 - 安装依赖项
- sudo apt update
- sudo apt install ca-certificates curl openssh-server postfix
第2步 - 安装GitLab
- cd /tmp
- #下载安装脚本
- curl -LO https://packages.gitlab.com/install/repositories/gitlab/git lab-ce/script.deb.sh
- #检查下载脚本安全性
- less /tmp/script.deb.sh
- #运行安装程序
- sudo bash /tmp/script.deb.sh
- #安装gitlab-ce版
- sudo apt install gitlab-ce
第3步 - 调整防火墙规则(内网环境可关闭防火墙)
- #查看活动防火墙的当前状态
- sudo ufw status
- #当前规则允许SSH流量通过,但对其他服务的访问受到限制
- Status: active
- To Action From
- -- ------ ----
- 80 ALLOW Anywhere
- 22 ALLOW Anywhere
- 80 (v6) ALLOW Anywhere (v6)
- 22 (v6) ALLOW Anywhere (v6)
#允许HTTP,HTTPS,OpenSSH访问
- sudo ufw allow http
- sudo ufw allow https
- sudo ufw allow OpenSSH
第4步 - 编辑GitLab配置文件
打开Gitlab的配置文件
- sudo vim /etc/gitlab/gitlab.rb
- ## GitLab URL
- ##! URL on which GitLab will be reachable.
- ##! For more details on configuring external_url see:
- ##! https://docs.gitlab.com/omnibus/settings/configuration.html#configuring-the-external-url-for-gitlab
- ##!
- ##! Note: During installation/upgrades, the value of the environment variable
- ##! EXTERNAL_URL will be used to populate/replace this value.
- ##! On AWS EC2 instances, we also attempt to fetch the public hostname/IP
- ##! address from AWS. For more details, see:
- ##! https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html
- external_url 'http://example.com' // 此处修改为您的域名或ip地址
设置定义了一个电子邮件地址列表
- letsencrypt['contact_emails'] = ['someone@example.com']
保存并关闭文件,运行以下命令重新配置Gitlab
- sudo gitlab-ctl reconfigure
重启 GitLab
- sudo gitlab-ctl restart
常用命令 | 说明 |
sudo gitlab-ctl reconfigure | 重新加载配置,每次修改/etc/gitlab/gitlab.rb文件之后执行 |
sudo gitlab-ctl status | 查看 GitLab 状态 |
sudo gitlab-ctl start | 启动 GitLab |
sudo gitlab-ctl stop | 停止 GitLab |
sudo gitlab-ctl restart | 重启 GitLab |
sudo gitlab-ctl tail | 查看所有日志 |
sudo gitlab-ctl tail nginx/gitlab_acces.log | 查看 nginx 访问日志 |
sudo gitlab-ctl tail postgresql | 查看 postgresql 日志 |
GitLab常用命令
第5步 - 首次登录
在Web浏览器中访问GitLab服务器的域名:
- #设置GitLab开机自启动命令为
- sudo systemctl enable gitlab-runsvdir.service
- #禁止GitLab开机自启动命令为
- sudo systemctl disable gitlab-runsvdir.service
以下用企业邮箱为例
第1步 - 开启企业邮箱的POP3/SMTP服务并保存好授权码
第2步 - 修改gitlab的配置文件
打开gitlab配置文件
- sudo vim /etc/gitlab/gitlab.rb
修改如下配置
- #配置邮箱来源, 与展示的名称
- gitlab_rails['gitlab_email_enabled'] = true
- gitlab_rails['gitlab_email_from'] = '企业邮箱地址'
- gitlab_rails['gitlab_email_display_name'] = '邮箱显示名称'
- #smtp配置
- gitlab_rails['smtp_enable'] = true
- gitlab_rails['smtp_address'] = "smtp.exmail.qq.com"
- gitlab_rails['smtp_port'] = 465
- gitlab_rails['smtp_user_name'] = "企业邮箱地址"
- gitlab_rails['smtp_password'] = "企业邮箱授权码"
- gitlab_rails['smtp_domain'] = "smtp.exmail.qq.com"
- gitlab_rails['smtp_authentication'] = "login"
- gitlab_rails['smtp_enable_starttls_auto'] = true
- gitlab_rails['smtp_tls'] = true
第3步 - 重新加载配置
- sudo gitlab-ctl reconfigure
第4步 - 发送测试邮件
- sudo gitlab-rails console
- #进入控制台,然后发送邮件
- Notify.test_email('测试邮箱地址', '邮件标题', '邮件正文').deliver_now
第1步 - 安装
参考官网安装流程:Install GitLab Runner using the official GitLab repositories | GitLab
第2步 - 注册
参考官网注册流程:Registering runners | GitLab
GitLab - 专业 Git 代码版本管理平台,即代码仓库。
1).原则上不托管非源码类(如.jar\.war\.zip)的交付物
2).此类交付物建议项目团队自行管理版本
3).因为此类交付物多数是二进制格式、且文件容量较大,在代码仓库进行版本管理后,占用空间过大。
- 角色划分
1.GitLab配置管理员:xxx<xxx@xxx.com>
2.项目空间管理员:各公司/部门下具体项目的管理员,一般是项目经理
3.项目管理员:代码交付的负责人,一般是技术经理或交付经理
4.开发工程师:代码交付的开发人员
- 项目空间(Group)
项目的集合,一个项目空间下可以拥有多个项目。
在项目空间分配的人员权限,会穿透到该空间下所有项目中。
在项目中又对其进行二次权限分配,会以项目中的权限为准
- 项目(Project)
项目为Gitlab中的最小管理单元,所有的文件/代码都存放在项目下。
操作指导:
- 如果已有AD账号,直接登录即可(参看下图),无须申请。
- 如果无AD账号,请在联系IT同事进行AD账号注册。
操作规范:
公司Gitlab使用AD账号登录
由项目空间管理员完成:
- 项目空间内→new project或new subgroup
- 空项目:指定project的name,即git仓库的path段
- 导入项目:填入源项目的仓库地址 与 新项目的名称,导入即可
- 注意:源项目非开放的话,需要填入用户名密码,如http://user:password@git.xxxxxx.com//xxx/yyy.git
操作规范:
- 项目的可视范围为 private(默认)
1).默认从“项目空间”的权限继承
2).另外两个权限:public是无需登录即可访问、internal是只要登录无需授权即可访问
- 项目的路径(即project slug)必须是英文
操作指导:
- 由项目空间管理员和项目管理员完成
- 项目空间申请下来后,上述申请中填写的项目负责人会被设置为项目空间的管理员,具有整个空间的管理权限
- 可以进行空间内子组和项目的创建、修改、删除
- 可以进行空间内所有的权限分配
- 根据项目实际情况,由管理员添加各成员及分配其角色。角色如下
- Owner:只在“项目空间”上分配,可以对“项目空间”和“项目”进行管理
- Master:管理员,具备项目修改、权限分配等权限
- Developer:开发人员,具备开发相关权限,包括创建分支、提交代码等
- Reporter:问题提报人员,具备代码分支的查看权限
- Guest:访客,只能看到项目的基本信息,无权浏览代码
- 权限的划分分两个级别
- 组的用户权限分配
- 项目的用户权限分配。默认继承所属组的权限,重新配置后,覆盖前者
操作规范:
- 1.【强制】必须遵循“最小权限”原则
- 2.【强制】开发人员只能拥有Developer角色
- 3.【强制】不具备任何代码修改权限的人员,只能分配Reporter或Guest权限
操作规范:
- 1.【强制】项目代码的提交,遵循“源码最小化原则”,即 与编译打包不相关的源代码,无需向仓库提交
- 2.【强制】项目根目录必须包含 .gitignore文件,并按项目的开发语言平台设置合适的忽略内容,可以参看gitignore网站
- 3.【建议】项目根据开发语言平台,选择合适的包管理工具,以保证仅向仓库提交项目开发的源代码与依赖声明配置文件,而不需要提供依赖的程序包
操作指导:
- 1.由项目管理员完成。
- 2.项目创建后,可在项目首页看到项目的访问地址(参考下图):
本机执行clone命令初始化项目
- git clone http://git.xxxxxxx.com/xxx/xxx.git
- cd xxx
- touch README.md
- git add README.md
- git commit -m "add README"
- git push -u origin master
已经有项目代码,但代码之前并未在Gitlab上管理,可执行以下命令进行初始化
- cd existing_folder
- git init
- git remote add origin http://git.xxxxxx.com/xxx/xxx.git
- git add .
- git commit -m "Initial commit"
- git push -u origin master
项目代码之前在其他Git仓库进行管理,现在需要迁移到当前项目下,执行以下命令进行初始化
- cd existing_repo
- git remote rename origin old-origin
- git remote add origin http://git.xxxxxx.com/xxx/xxx.git
- git push -u origin --all
- git push -u origin --tags
通过软件开发的持续方法,可以持续构建、测试和部署迭代代码更改。这种迭代过程有助于减少基于有缺陷或失败的先前版本开发新代码的机会。 使用这种方法,可以努力减少从开发新代码到部署的人工干预,甚至根本不需要干预。
操作指导:
- 确保有可用的 runner 运行作业。 如果没有 runner,需要为项目或群组安装 GitLab Runner并注册 runner(下图一)。
- 在仓库的根目录下创建一个 .gitlab-ci.yml 文件。该文件是定义 CI/CD 作业的地方(下图二)。
- 当成员将文件提交到仓库时,runner 会运行CI作业。作业结果显示在流水线中。
.gitlab-ci.yml 文件是一个 YAML 文件,可以在其中配置 GitLab CI/CD 的特定指令。
在此文件中定义:
-
- runner应执行的作业的结构和顺序。
- runner在遇到特定条件时应做出的决定
创建一个 .gitlab-ci.yml 文件:
-
- 在左侧边栏上,选择 项目信息 > 详细信息。
- 在文件列表上方,选择要提交的分支,点击加号图标,然后选择 新建文件:
示例代码:
- build-job:
- stage: build
- script:
- - echo "Hello, $GITLAB_USER_LOGIN!"
- test-job1:
- stage: test
- script:
- - echo "This job tests something"
- test-job2:
- stage: test
- script:
- - echo "This job tests something, but takes more time than test-job1."
- - echo "After the echo commands complete, it runs the sleep command for 20 seconds"
- - echo "which simulates a test that runs 20 seconds longer than test-job1"
- - sleep 20
- deploy-prod:
- stage: deploy
- script:
- - echo "This job deploys something from the $CI_COMMIT_BRANCH branch."
$GITLAB_USER_LOGIN 和 $CI_COMMIT_BRANCH 是在作业运行时填充的预定义变量
点击提交变更,提交后,流水线开始(如下图)。
- default:
- image: ruby:2.7.5
此命令告诉runner使用来自Docker Hub的Ruby镜像并在从该镜像生成的容器中运行作业。
此过程不同于将应用程序构建为Docker容器。应用程序无需构建为Docker容器即可在Docker容器中运行 CI/CD 作业。
- 每个作业都包含脚本和阶段:
- default 关键字用于自定义默认值,例如 before_script 和 after_script。
- stage 描述了作业的顺序执行。 只要有可用的 runner,单个阶段中的作业就会并行运行。
- 可以设置其他配置来自定义作业和阶段的执行方式
- 使用rules关键字指定何时运行或跳过作业。only和except旧关键字仍受支持,但不能在同一作业中与 rules 一起使用。
- 使用cache和artifacts在流水线中保持跨作业和阶段的信息持久化。这些关键字是存储依赖项和作业输出的方法,即使在为每个作业使用临时runner时也是如此。
- 有关完整的 .gitlab-ci.yml 语法,请参阅完整的 .gitlab-ci.yml 参考主题。
- 要查看流水线的可视化表示,请单击流水线ID:
- 要查看作业的详细信息,请单击作业名称,例如 build-package:
权限问题,重新针对文件所在的最近一层文件夹赋予可执行权限
只有一个runner的情况下,默认的配置是只能运行一个job的,打开gitlab-runner的配置文件修改一下配置:
- vi /etc/gitlab-runner/config.toml
gitlab-runner 打包的直接地址在/home/gitlab-runner,是存放在系统盘,项目多的时候系统盘会爆,所有建议把数据放在数据盘;需要把打包目录改一下,修改方式如下:
- vi /etc/systemd/system/gitlab-runner.service
注意需要给新的gitlab-runner-build-dir目录权限:chmod -R 777 gitlab-runner-build-dir
重启runner
gitlab-runner服务器下的没有设置免密登录远程服务器,使用命令cd ~/.ssh进入~/.ssh文件夹,输入vi id_rsa.pub打开id_rsa.pub文件,复制其中所有内容到远程服务器的~/.ssh/authorized_keys文件内。使用示例如下:
- # 通过ssh-copy-id命令将 ~/.ssh/id_rsa.pub 公钥上传到服务器的 ~/.ssh/authorized_keys 文件内
- cd ~/.ssh
- ssh-copy-id -i id_rsa.pub root@xxx.xxx.xxx.xxx
- # 若文件不存在则需要创建文件并设置对应的读写权限
- mkdir .ssh # 创建文件夹
- touch .ssh/authorized_keys # 创建文件
- chmod 700 .ssh # 设置权限
- chmod 644 .ssh/auauthorized_keys # 设置权限
若提示gitlab-runner执行shell脚本时报错 sudo: no tty present and no askpass program specified,由于帐号并没有开启免密码导致的,假设当前帐号为gitlab切换到root下
- #打开sudoers
- vi /etc/sudoers
- #在 sudoers 文件中添加免密码
- gitlab ALL = NOPASSWD: ALL
创建备份
gitlab-rake gitlab:backup:create 使用以上命令会在/var/opt/gitlab/backups目录下创建一个名称类似为1660639275_2022_08_16_15.2.2_gitlab_backup.tar的压缩包, 这个压缩包就是Gitlab整个的完整部分, 其中开头的1660639275是备份创建的日期。
需要手动打包相关文件目录如下:
- root@cicd-gitlab:/etc/gitlab# ll
- total 176
- drwxrwxr-x 4 root root 4096 Aug 9 09:22 ./
- drwxr-xr-x 103 root root 4096 Aug 10 06:26 ../
- -rw------- 1 root root 19201 Aug 9 09:22 gitlab-secrets.json
- -rw------- 1 root root 137722 Aug 9 09:22 gitlab.rb
- -rw------- 1 root root 749 Aug 9 09:00 initial_root_password
- drwxr-xr-x 2 root root 4096 Aug 9 09:20 ssl/
- drwxr-xr-x 2 root root 4096 Aug 9 09:00 trusted-certs/
- root@cicd-gitlab:/etc/gitlab# pwd
- /etc/gitlab
可以通过修改/etc/gitlab/gitlab.rb来修改默认存放备份文件的目录:
修改完成之后使用gitlab-ctl reconfigure命令重载配置文件即可.
Gitlab自动备份
实现每天凌晨2点进行一次自动备份:通过crontab使用备份命令实现
0 2 * * * /opt/gitlab/bin/gitlab-rake gitlab:backup:create
- #!/bin/bash
- #delname=`date -d "1 days ago" +%Y_%m_%d`
- rm -f /var/opt/gitlab/backups/*.tar
- /opt/gitlab/bin/gitlab-rake gitlab:backup:create
- today=`date -d today +%Y_%m_%d`
- cd /var/opt/gitlab/backups/
- file="*$today"_15.2.2_gitlab_backup.tar""
- scp $file nfs-server:/opt/backup/gitlab_bk
- #配置互信
- #! /bin/bash
- for ip in `cat ip_test`
- do
- cd ~/.ssh/
- scp ./id_rsa.pub root@$ip:/root/.ssh/1_id_rsa.pub
- ssh root@$ip "cat ~/.ssh/1_id_rsa.pub >> ~/.ssh/authorized_keys"
- echo "*****$ip*****"
- ssh root@$ip "ls /tmp"
- done
目标机器自动清理
- #!/bin/bash
- #nfs-server机器
- delname=`date -d "2 days ago" +%Y_%m_%d`
- rm /opt/backup/gitlab_bk/*$delname*.tar
恢复备份
停止相关数据连接服务
gitlab-ctl stop unicorn
gitlab-ctl stop sidekiq
从1660639275编号备份中恢复
gitlab-rake gitlab:backup:restore BACKUP=1660639275
启动Gitlab
sudo gitlab-ctl start
Gitlab迁移
迁移如同备份与恢复的步骤一样, 只需要将老服务器/var/opt/gitlab/backups目录下的备份文件拷贝到新服务器上的/var/opt/gitlab/backups即可(如果你没修改过默认备份目录的话).
需要注意的是新服务器上的Gitlab的版本必须与创建备份时的Gitlab版本号相同.
- /etc/gitlab/gitlab.rb gitlab #配置文件须迁移,迁移后需要调整数据存放目录
- /var/opt/gitlab/nginx/conf nginx #配置文件目录须迁移
执行一下操作进行数据迁移
- gitlab-ctl stop unicorn
- gitlab-ctl stop sidekiq
- chmod 777
- /var/opt/gitlab/backups/1660639275_2022_08_16_15.2.2_gitlab_backup.tar
- gitlab-rake gitlab:backup:restore BACKUP=1660639275
更改仓库存储位置
默认时GitLab的仓库存储位置在“/var/opt/gitlab/git-data/repositories”,在实际生产环境中显然我们不会存储在这个位置,一般都会划分一个独立的分区来存储仓库的数据,我这里规划把数据存放在“/data/git-data”目录下
- chown -R git.git /data/git-data #修改创建目录的属主和属组为git用户
- cp /etc/gitlab/gitlab.rb /etc/gitlab/gitlab.rb.bak
vim /etc/gitlab/gitlab.rb 启用git_data_dirs参数,并修改如下:
git_data_dirs 路径 "/data/git-data"
1)停止gitlab
gitlab-ctl stop
2)卸载gitlab
rpm -e gitlab-ce
3)查看gitlab进程
ps aux | grep gitlab
4)杀掉第一个进程
kill -9 90570
杀掉后,在ps aux | grep gitlab确认一遍,还有没有gitlab的进程
5)删除所有包含gitlab文件
find / -name gitlab | xargs rm –rf。
1)关闭gitlab服务
gitlab-ctl stop unicorn
gitlab-ctl stop sidekiq
gitlab-ctl stop nginx
2)备份gitlab
gitlab-rake gitlab:backup:create
3)下载gitlab的RPM包并进行升级
yum install gitlab-ce-15.2.2-ce.0.el7.x86_64.rpm
使用 rpm -Uvh gitlab-ce-15.2.2-ce.0.el7.x86_64.rpm
4)启动并查看gitlab版本信息
gitlab-ctl reconfigure
gitlab-ctl restart
# head -1 /opt/gitlab/version-manifest.txt
gitlab-ce 15.2.2
*gitlab的版本升级不建议跨大版本升级
1)内存消耗太大
解决方案:根据服务器使用情况,给unicorn['worker_processes']设置一个合适的值
2)时间不一致
设置时区为:gitlab_rails['time_zone'] = 'Asia/Shanghai'
有时,script命令必须用单引号或双引号括起来。例如,包含冒号(:)的命令必须用单引号 ( ') 括起来。YAML 解析器需要将文本解释为字符串而不是“键:值”对。
例如:
- job:
- script:
- - curl --request POST --header 'Content-Type: application/json' "https://gitlab/api/v4/projects"
要被视为有效的 YAML,您必须将整个命令用单引号括起来。如果命令已使用单 引号,则应尽可能将它们更改为双引号 ( "):
- job:
- script:
- - 'curl --request POST --header "Content-Type: application/json" "https://gitlab/api/v4/projects"'
使用这些字符时也要小心:
{, }, [, ], ,, &, *, #, ?, |, -, <, >, =, !, %, @, `.
当脚本命令返回非零的退出代码时,作业将失败并且不会执行其他命令。
将退出代码存储在变量中以避免这种行为
- job:
- script:
- - false || exit_code=$?
- - if [ $exit_code -ne 0 ]; then echo "Previous command failed"; fi;
使用before_script定义一个默认的命令数组,这些命令应该在所有作业中的命令之前运行。
使用after_script定义作业完成后应运行的默认命令数组。
通过在作业中定义不同的默认值来覆盖默认值。忽略默认使用before_script: []或 after_script: []:
示例如下:
- default:
- before_script:
- - echo "Execute this `before_script` in all jobs by default."
- after_script:
- - echo "Execute this `after_script` in all jobs by default."
- job1:
- script:
- - echo "These script commands execute after the default `before_script`,"
- - echo "and before the default `after_script`."
- job2:
- before_script:
- - echo "Execute this script instead of the default `before_script`."
- script:
- - echo "This script executes after the job's `before_script`,"
- - echo "but the job does not use the default `after_script`."
- after_script: []
将长命令拆分为多行命令,以使用|(字符)和>(折叠)YAML 多行块标量指示符提高可读性。
警告:如果将多个命令组合成一个命令字符串,则只报告最后一个命令的失败或成功。 由于错误,早期命令的失败将被忽略。要解决此问题,请将每个命令作为单独的script:项运行,或将exit 1 命令添加到每个命令字符串。
可以使用|(字符)YAML 多行块标量指示器在作业描述部分的|多行中编写命令。script每一行都被视为一个单独的命令。作业日志中仅重复第一个命令,但仍执行其他命令:
- job:
- script:
- - |
- echo "First command line."
- echo "Second command line."
- echo "Third command line."
上面的示例在作业日志中呈现为:
- $ echo First command line # collapsed multiline command
- First command line
- Second command line.
- Third command line.
(折叠符>)YAML 多行块标量指示器将部分之间的空行视为新命令的开始:
- job:
- script:
- - >
- echo "First command line
- is split over two lines."
- echo "Second command line."
>这与没有或|块标量指示符的多行命令类似:
- job:
- script:
- - echo "First command line
- is split over two lines."
- echo "Second command line."
上面的两个示例都在作业日志中呈现为:
- $ echo First command line is split over two lines. # collapsed multiline command
- First command line is split over two lines.
- Second command line.
脚本输出可以使用ANSI 转义码着色,或者通过运行输出 ANSI 转义码的命令或程序来着色。
例如,使用带有颜色代码的 Bash:
- job:
- script:
- - echo -e "\e[31mThis text is red,\e[0m but this text isn't\e[31m however this text is red again."
可以在Shell环境变量中定义颜色代码,甚至可以自定义 CI/CD 变量,这使得命令更易于阅读和重用。
例如,使用与上面相同的示例和在 a 中定义的环境变量before_script:
- job:
- before_script:
- - TXT_RED="\e[31m" && TXT_CLEAR="\e[0m"
- script:
- - echo -e "${TXT_RED}This text is red,${TXT_CLEAR} but this part isn't${TXT_RED} however this part is again."
- - echo "This text is not colored"