CI/CD 环境搭建:Docker+Jenkins+Gerrit
前言
软件开发的连续方法旨在通过自动执行脚本,以最大限度地减少在开发应用程序时引入错误的可能性。从新代码的开发到部署,它们只需要较少的人为干预甚至根本不需要干预;它涉及在每次小迭代中不断构建,测试和部署代码更改,从而减少基于有缺陷或失败的先前版本开发新代码的机会。目前比较流行的软件开发方法主要有三种:
- 持续集成(Continuous Integration, CI): 代码合并,构建,部署,测试都在一起,不断地执行这个过程,并对结果反馈。
- 持续部署(Continuous Deployment, CD): 部署到测试环境、预生产环境/灰度环境、生产环境。
- 持续交付(Continuous Delivery, CD): 将最终产品发布到生产环境、给用户使用。
掌握这些方法能够帮助团队提高开发和运维的效率,提升软件质量,快速响应市场和用户需求,从而增强竞争力。
准备
- 系统环境:Ubuntu 18.04
- 相关资料:
基本流程
- 在本地使用 Docker 运行 Gerrit 和 Jenkins 服务。
- 配置 Docker 的卷和端口,使其可以通过 Web 访问。
- 在 Gerrit 中创建一个新的项目 “unit_test”,用于管理源代码。
- 在 Jenkins 中创建一个任务来构建 “unit_test”项目。
- 确保 Gerrit 中的补丁可以被 Jenkins 构建。
- 在 “unit_test” 项目中添加单元测试。
- 在 Jenkins 中添加一个任务来构建和运行单元测试。
- 实现一个闭环流程,包括自动补丁构建、代码审查和测试结果反馈。
安装 Docker & Docker Compose
安装Docker
sudo apt-get update
#移除老版本的docker
sudo apt-get remove docker docker-engine docker.io containerd runc
#安装HTTPS相关包
sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
#添加Docker的官方GPG key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
#验证指纹
sudo apt-key fingerprint 0EBFCD88
#设置稳定版repo
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
#安装Docker Engine
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
#验证安装成功
sudo docker run hello-world
设置非root账户管理Docker
sudo groupadd docker
sudo usermod -aG docker $USER #$USER替换为ubuntu当前用户名
newgrp docker
#验证非root账户运行docker hello-world容器
docker run hello-world
安装Docker Compose
#下载稳定版的Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
#(因为下载慢等原因)安装失败时,可以参考 https://blog.csdn.net/alen_xiaoxin/article/details/104849962 解决
#设置权限
sudo chmod +x /usr/local/bin/docker-compose
#验证安装成功
docker-compose --version
Docker 镜像下载
#获取 jenkins & gerrit 镜像
docker pull jenkins/jenkins
docker pull openfrontier/gerrit
#检查镜像
docker images
Docker 启动 Gerrit 镜像容器并进行配置
使用 docker compose 配置方式启动 Gerrit
- 任意位置创建文件夹(如cicd),并在该目录下新建 docker-compose.yaml 文件
docker-compose.yaml
version: '3'
services:
gerrit:
#image: gerritcodereview/gerrit
image: openfrontier/gerrit
ports:
- "29418:29418"
- "8091:8091"
depends_on:
- ldap
volumes:
- /usr/local/docker/gerrit/review_site:/var/gerrit/review_site
- /usr/local/docker/gerrit/etc:/var/gerrit/etc
- /usr/local/docker/gerrit/git:/var/gerrit/git
- /usr/local/docker/gerrit/db:/var/gerrit/db
- /usr/local/docker/gerrit/index:/var/gerrit/index
- /usr/local/docker/gerrit/cache:/var/gerrit/cache
environment:
- CANONICAL_WEB_URL=http://localhost:8091
# entrypoint: /entrypoint.sh init
ldap:
image: osixia/openldap
ports:
- "389:389"
- "636:636"
environment:
- LDAP_ADMIN_PASSWORD=secret
volumes:
- /usr/local/docker/gerrit/ldap/var:/var/lib/ldap
- /usr/local/docker/gerrit/ldap/etc:/etc/ldap/slapd.d
ldap-admin:
image: osixia/phpldapadmin
ports:
- "6443:443"
environment:
- PHPLDAPADMIN_LDAP_HOSTS=ldap
- 终端进入 docker-compose.yaml 所在目录,执行 docker-compose up 启动 Gerrit 容器
- 浏览器打开http://localhost:8091,进入 Gerrit 站点
如果浏览器登录失败,可以尝试修改 gerrit.config 文件,将port 8080 修改为 8091
文件 gerrit.config 可通过 sudo find / -name “gerrit.config” 寻找
通过 docker run 启动 Gerrit
docker run \
--name mygerrit \
-v $PWD/gerrit_volume:/var/gerrit/review_site \
-p 9527:9527 -p 29418:29418 openfrontier/gerrit
# 其中9527为web访问端口,29418为ssh端口,执行该命令后review_site 总的内容将和gerrit_volume中内容同步;
# gerrit_volume中会产生一个gerrit.config (位置 gerrit_volume/etc/gerrit.config)的配置文件内容,该内容可以根据需要修改:
[gerrit]
basePath = git
serverId = 0871a228-bd59-4f69-a8b9-504f65b6ddb6
canonicalWebUrl = http://yourIP:9527/
[httpd]
listenUrl = http://*:9527/
# 默认生成的canoicalWebUrl是个Containor ID,必须要修改为自己的宿主机IP,否则 注册邮箱的时候,发送的验证位置前部分就是一个乱码WebUrl;
# 注:其他目录也会生成gerrit.config文件,除非清楚调用关系,建议都统一修改。
# 查找命令:sudo find / -name gerrit.config
# 如我的目录为:/var/lib/docker/volumes/1ffcae852b0225161ccb60c37252f9635da1c1d2fe0d7c0f0bc7c2cc10a5e4cb/_data/etc/gerrit.config
- 网页成功进入后点击登录,使用【Sign in with a Launchpad ID】登录 Gerrit(需要注册两个账号,admin 权限的账号以及 Jenkins 中要用到的账号
-
gerrit 默认第一个站点账号为管理员账号 1000000
注册完帐号之后点击Sign in with a Launchpad ID,进行登录,会跳转到ubuntu one第三方认证,输入注册的邮箱和密码,点击登录时会有以下提示:
You are logging in to http://bd886cda56b3:8080/
The site has requested some personal information, please choose what you would like to share:
》Full name: your_name
》Email address: your_email@xxxx.com
.注意到这里的服务器地址是个奇怪的地址,可以通过修改gerrit的配置文件gerrit.config进行修正。将canonicalWrbUrl改成 .>canonicalWebUrl = http://localhost:8091/。
如果不修改gerrit.config配置文件,也可以修改系统的/etc/hosts文件,添加该地址到localhost的映射。 -
配置ssh密钥
ssh-keygen -t rsa -C "yourEmail"
,连续三次回车键,会在~/.ssh下生成公钥 id_rsa.pub 和私钥 id_rsa,其中公钥需要添加到 gerrit 的SSH Keys 中。添加完成后就可以正确执行 git clone 命令,只要不删除更改 .ssh 文件夹中的内容就可以一次设置长期使用了。- 终端下 ssh -p 29418 admin@localhost 验证ssh连接,其中 admin 为 gerrit 管理员账号的 Username
-
注册用于 jenkins 的账号,然后网页登录 gerrit 管理员账号
- 进入 Browser->Repo->Groups->Non-Interactive Users->Members,将2个账户添加到 Non-Interactive 账户组中(注意:gerrit 3.3 版本以后 Non-Interactive Users 被命名为 Service Users
如果误操作,比如将 gerrit 的管理员权限删除了,可以通过删除 /usr/local/docker/gerrit/review_site 清除 gerrit 已有的数据, /usr/local/docker/gerrit/review_site 是 docker-compose.yaml 文件之指定的 gerrit 容器数据保存位置
-
在本机的 Gerrit 上创建软件仓库,并能成功上传和拉取代码
本地检出 All-Project (1)
git clone ssh://user@hostip:29418/All-Projects.git
如果提示错误为 agent fail,执行以下命令:
eval "$(ssh-agent -s)"
ssh-add
检查检出的目录,修改 project.config,新增以下脚本:
[label "Verified"]
function = MaxWithBlock
value = -1 Fails
value = 0 No score
value = +1 Verified
copyAllScoresIfNoCodeChange = true
提交更新,注意本地 git 邮件地址必须和 Gerrit 上的一致,一定不要 push 到错误的分支,要按照如下分支 push
git commit -am "add label verified"
git push origin HEAD:refs/meta/config
网页登录 gerrit 管理员,增加 All-Project 的 Label Verified 权限。
Browser->Repo->All-Projects->Access->Edit
,为 refs/for/ 和 refs/heads/ 增加 Label Verified,并添加 Non-Interactive Users 用户组
- 新建仓库并提交修改,看看是否出现了review
Browser->Repo->Create New
- 填入仓库名称 unit_test
clone 仓库并进行修改
- 使用如下命令 clone 仓库到本地,因为如果没有后面的 scp 拷贝 commit-msg,那么生产的 commit 是不带 Changed-Id 的,会造成 push 的时候报错(missing Change-Id in commit message footer)
git clone ssh://user@hostip:29418/project && scp -p -P 29418 user@hostip:hooks/commit-msg project/.git/hooks
修改 .git/config 文件,在 [remote “origin”] 下增加
push = refs/heads/*:refs/for/*
避免每次提交都需要执行 git push 远程地址 本地分支:refs/for/远程分支
替代方法:git config remote.origin.push refs/heads/:refs/for/ ,效果相同。
需要该修改的原因是gerrit默认不允许直接提交到master分支。
在仓库中增加 readme.md
提交修改
git add .
git commit -m "add readme.md"
git push origin master
最终结果:查看网页 Gerrit 主页,出现一个需要 Review 的 Change。
Docker 启动 Jenkins 并配置
启动命令
docker run -d --name jenkins -vjenkins_home:/var/jenkins_home-p 8092:8080 -p 50000:50000 jenkins/jenkins
查找 jenkins 容器位置
sudo find / -name "jenkins_home"
在浏览器中打开 http://localhost:8092
- 解锁Jenkins,插件安装选择 jenkins 的推荐安装
- 执行命令
docker exec -it jenkins /bin/bash
进入容器内部 - 执行命令
cat /var/jenkins_home/secrets/initialAdminPassword
查看 Jenkins 的 admin 密码
- 执行命令
- 进入Jenkins后,安装插件,主页 → Manage Jenkins → Manage Plugins → available plugins
- 安装 Gerrit-Trigger 插件
- 安装插件失败时的解决方案,参考
- https://www.cnblogs.com/ninefish/p/9818080.html
- http://localhost:9527/pluginManager/advanced
- http://mirror.esuni.jp/jenkins/updates/update-center.json
- 安装插件失败时的解决方案,参考
- 在 Gerrit Trigger 中配置一个用于构建的服务器
相关参数填写- HostName 中的ip:通过 ifconfig 查看 docker0 的ip
- SSH keyfile:进入 Jenkins 容器在~目录通过 ssh-keygen -t rsa -C xxxx@xx.com 命令生成,并将公钥(id_rsa.pud文件的内容)输入到前面注册的用于 jenkins 的 gerrit 账号
-
如果 jinkins 配置 gerrit_trigger 服务是提示: “/var/jenkins_home/.ssh/id_rsa” is not a valid key file.,可用 ssh-keygen -m PEM 重新生成密钥,修改文件后需要重启容器,不然 jenkin 流水线配置这里URL可能找不到
- 正确配置后可通过jenkins容器下 ssh -p 29418 cqh@172.17.0.1 验证 ssh 连接,其中 cqh 为用于 jenkins 的 gerrit 账号 Username
- 若出现 auth 错误,表明 user 信息和 gerrit 用于 jenkins 账户的不一致,应确保名字和邮箱均相同,且 ssh 已添加到 gerrit 中.
- 点击 Test Connection 测试是否正常连接
Jenkins 搭建自动构建流水线
- 下载 gtest 框架, jenkins 容器目录下:
git clone https://github.com/google/googletest
- 进入 gtest 框架目录,编译,这里需要root权限,以 root 权限进入 jenkins 容器:
docker exec -it --user root 容器 id /bin/bash
# 以root权限进入 jenkins 容器,执行
root@13161464c3fe:apt-get update
root@13161464c3fe:apt-get install g++
root@13161464c3fe:apt-get install cmake
- 进入gtest目录,执行
cmake CMakeList.txt
make
make install
- 添加 jenkins 构建任务,选择“流水线”,jenkins 网页站点 New iteam → pipeline
-
- 如果仓库存在但 repo url 提示 Failed to connect to repository : Command “git ls-remote -h – ssh://cqh@172.17.0.1:29418/unit_tests HEAD” returned status code 128: ,考虑重新生成ssh密钥并重启容器
-
添加 repo url 出现 Jenkins: stderr: Permission denied 权限问题参考 https://blog.csdn.net/lusyoe/article/details/52782368
测试自动触发构建
- 进入 gerrit 仓库目录,如我的 chenqinhu@chenqinhu:~/cicd/uint_test$
- 新建三个文件并提交 hello_gtest.c、 Jenkinsfile 、Makefile
hello_gtest.c
hello_gtest.c
#include <stdio.h>
int main(int argc,char** argv)
{
printf("hello world!\r\n\r\n");
}
Makefile
test:hello_gtest.o
gcc -o test hello_gtest.o
hello_gtest.o:
gcc -c hello_gtest.c
clean:
rm -f *.o test
Jenkins file
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'clean and bulid..'
sh 'make clean && make'
}
}
stage('Test') {
steps {
echo 'Testing...'
sh './test --gtest_output=xml:gtestreport.xml'
}
}
stage('Deploy') {
steps {
echo 'Deploy..'
}
}
}
}
- 最终执行效果:修改 gerrit 项目,提交触发 jenkins 构建,jenkins 构建结果反馈于 gerrit 的 verify 结果。
在 Gerrit 中,All-Projects 是一个特殊的项目,用于管理整个 Gerrit 实例的配置。你可以在 All-Projects 项目中设置全局访问权限、项目配置和其他重要设置。 ↩︎