1. 项目概述为什么是JenkinsGitlabGerrit这个“铁三角”如果你正在搭建一个对代码质量要求极高、需要严格评审流程的持续集成环境那么“Jenkins Gitlab Gerrit”这个组合绝对是你绕不开的经典架构。这不仅仅是三个工具的简单堆砌而是一个经过大量生产环境验证的、职责分明的自动化协作体系。我见过不少团队一开始图省事只用JenkinsGitlab结果在代码准入环节全靠人工自觉和口头约定时间一长合并到主分支的代码质量就开始参差不齐技术债越堆越高。而这个“铁三角”组合正是为了解决这个核心痛点而生的。简单来说这套环境搭建起来后你的工作流会变得非常清晰Gerrit充当代码评审的“守门员”所有推送到集成分支的代码都必须先经过它创建的评审任务Change由同事Review2后才能合入。Gitlab作为强大的源码管理和协作平台承载着项目仓库、Issue跟踪、Wiki文档等。而Jenkins则是整个流程的“自动化引擎”它监听Gerrit或Gitlab的事件比如有新的评审提交或者代码合入了主分支然后自动触发对应的构建、测试、甚至部署任务。最终实现的效果是任何一行代码想要进入产品主干都必须先通过自动化测试的验证和同伴的代码审查这为软件质量提供了双重保障。接下来我就带你从零开始手把手搭建这套环境并分享一些只有踩过坑才知道的配置细节和避坑指南。2. 环境规划与前置准备在动手安装之前合理的规划能避免后期大量的返工。这套系统对资源有一定要求别想着用一个1核1G的虚拟机就能跑顺畅。2.1 硬件与软件资源规划首先你需要准备至少两台服务器虚拟机或物理机均可。我强烈建议将它们分开部署这不仅是为了性能更是为了隔离和稳定性。服务器ACI/CD主节点运行Jenkins和Gerrit。推荐配置4核CPU8GB内存100GB SSD硬盘。Jenkins本身不重但它的构建任务尤其是并行任务和Gerrit服务会比较吃内存。操作系统Ubuntu 22.04 LTS 或 CentOS 7/8。本文将以Ubuntu 22.04为例因为其软件源较新安装依赖更便捷。服务器B代码仓库与协作平台运行Gitlab。推荐配置4核CPU8GB内存200GB SSD硬盘。Gitlab非常消耗资源尤其是当仓库变大、用户增多时。内存越大越好。操作系统同上Ubuntu 22.04 LTS。注意如果你资源实在有限或者只是想快速体验也可以使用Docker在一台机器上部署所有服务。但这仅限于学习和测试环境生产环境务必分开部署。使用Docker Compose可以简化这一过程但需要你对Docker网络和存储卷有基本了解。2.2 系统基础环境配置在每台服务器上我们都需要进行一些基础的配置。更新系统与安装必要工具sudo apt update sudo apt upgrade -y sudo apt install -y curl wget vim git net-tools openjdk-11-jdkJava是Jenkins和Gerrit的运行依赖必须提前安装。确保java -version命令能正确输出OpenJDK 11的信息。配置主机名与Hosts可选但推荐 为每台服务器设置一个易记的主机名并在所有服务器的/etc/hosts文件中添加解析记录。这样在后续配置中你就可以使用jenkins.yourcompany.com这样的域名而不是难记的IP地址。# 在服务器A上 sudo hostnamectl set-hostname jenkins-gerrit # 在服务器B上 sudo hostnamectl set-hostname gitlab-server # 然后在所有服务器的 /etc/hosts 文件中添加假设IP分别为192.168.1.10和192.168.1.11 echo 192.168.1.10 jenkins-gerrit | sudo tee -a /etc/hosts echo 192.168.1.11 gitlab-server | sudo tee -a /etc/hosts防火墙配置 根据你使用的操作系统防火墙如ufw或firewalld开放必要的端口。Jenkins默认端口8080。Gerrit默认HTTP端口8080SSH端口29418。Gitlab默认HTTP端口80HTTPS端口443SSH端口22。 例如在Ubuntu上使用ufwsudo ufw allow 22/tcp sudo ufw allow 8080/tcp sudo ufw allow 29418/tcp # 在Gitlab服务器上额外允许80和443 sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw enable3. Gitlab安装与深度配置我们将首先部署Gitlab因为它是代码的源头。3.1 使用官方脚本安装GitlabGitlab提供了极简的安装脚本。在服务器B上执行curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash sudo apt install gitlab-ce -y安装完成后你需要编辑Gitlab的配置文件设定访问它的URL。sudo vim /etc/gitlab/gitlab.rb找到external_url这一行将其修改为你的服务器地址例如http://gitlab-server或http://192.168.1.11。如果你有域名并配置了SSL可以设置为https://git.yourdomain.com。保存后重新配置并启动Gitlabsudo gitlab-ctl reconfigure这个过程会持续几分钟请耐心等待。完成后在浏览器访问你设置的external_url首次访问会强制你为root用户设置密码。3.2 关键配置与项目初始化关闭不必要的服务提升性能对于内存紧张的机器可以在gitlab.rb中禁用一些内置服务如prometheus、node_exporter、grafana等将它们的enable设置为false然后再次sudo gitlab-ctl reconfigure。创建项目与访问令牌登录后创建一个新的群组例如dev-team然后在群组下创建一个项目例如my-awesome-app。为CI/CD流程生成一个访问令牌Access Token。点击右上角用户头像 -Preferences-Access Tokens。创建一个具有api和read_repository权限的令牌并妥善保存。这个令牌将用于Jenkins从Gitlab拉取代码。配置SSH密钥为了让Jenkins服务器能通过SSH协议拉取代码需要在Jenkins服务器上生成SSH密钥对并将公钥添加到Gitlab。在**服务器AJenkins**上执行ssh-keygen -t rsa -b 4096 -C jenkinsjenkins-gerrit # 一路回车使用默认路径 cat ~/.ssh/id_rsa.pub复制输出的公钥内容进入Gitlab网页点击右上角头像 -Preferences-SSH Keys粘贴并添加。3.3 常见安装问题与排查问题gitlab-ctl reconfigure运行极慢或卡住。排查可能是服务器资源不足尤其是内存。使用top或htop命令查看内存使用情况。如果内存耗尽可能会触发系统的OOM Killer终止进程。解决增加服务器交换空间Swap或直接升级服务器配置。对于测试环境可以尝试增加Swapsudo fallocate -l 4G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile。问题访问页面出现502错误。排查最常见的原因是端口冲突或服务未完全启动。运行sudo gitlab-ctl status检查所有服务是否都是run状态。解决确保80或8080端口没有被其他程序如Nginx, Apache占用。可以运行sudo netstat -tlnp | grep :80查看。等待几分钟让服务完全启动或尝试sudo gitlab-ctl restart。4. Gerrit安装与核心概念解析Gerrit是这个流程中的关键一环它的代码评审模型与Gitlab/Github的Pull Request有所不同需要先理解其核心概念。4.1 安装与初始化Gerrit在服务器A上我们安装Gerrit。下载与安装wget https://gerrit-releases.storage.googleapis.com/gerrit-3.8.3.war # 创建一个Gerrit专用用户和目录 sudo adduser --system --shell /bin/bash --group gerrit sudo mkdir /var/gerrit sudo chown gerrit:gerrit /var/gerrit初始化切换到gerrit用户进行初始化。sudo su - gerrit cd /var/gerrit java -jar /path/to/gerrit-3.8.3.war init -d review_site初始化是一个交互式过程以下是一些关键选项的选择建议Authentication method选择HTTP方便与Gitlab集成或LDAP如果有企业目录。我们选HTTP。Get username from custom HTTP header留空。SSH Daemon选[Y]端口默认29418。HTTP Daemon选[Y]监听地址默认*:8080。注意这里端口是8080可能会和Jenkins冲突。我们可以在下一步通过配置文件修改。Behind reverse proxy选[N]。Use SSL选[N]生产环境建议Y并配置证书。Run as用户保持gerrit。Java heap size根据机器内存设置例如4096m。Listen on默认*。Copy gerrit.war选[Y]。Plugins直接回车安装默认插件。修改配置以避让端口初始化后Gerrit默认会在8080端口启动HTTP服务。由于Jenkins也常用8080我们需要修改。编辑/var/gerrit/review_site/etc/gerrit.config[httpd] listenUrl http://*:8081/同时修改/var/gerrit/review_site/etc/jetty.xml如果存在或确保配置一致。然后启动Gerritcd /var/gerrit/review_site bin/gerrit.sh start访问http://服务器A IP:8081你应该能看到Gerrit的登录页面。第一次需要以初始化时设置的管理员账号登录。4.2 Gerrit工作流与关键配置Gerrit的核心是Change。开发者不是直接推送到分支如master而是推送到一个特殊的引用refs/for/branch-name这会在Gerrit上创建一个待评审的Change。创建第一个项目登录Gerrit网页点击Projects-Create New Project。输入项目名例如my-awesome-app权限模板可以先选Read-only后续再调整。配置Gitlab集成HTTP密码认证 为了让用户能用Gitlab账号登录Gerrit我们需要配置HTTP认证。在Gerrit的review_site/etc/gerrit.config中确保[auth]部分如下[auth] type HTTP httpHeader GITLAB_USER httpEmailHeader GITLAB_EMAIL httpExternalIdHeader GITLAB_EXTERNAL_ID这告诉Gerrit从HTTP头部读取用户信息。接下来我们需要在反向代理如Nginx中设置这些头部。假设我们在同一台服务器用Nginx代理Gerrit和Jenkins。配置Nginx反向代理推荐 在生产环境我们通常会用Nginx作为前端统一端口如80/443并处理认证转发。安装Nginxsudo apt install nginx -y。创建一个Nginx配置文件例如/etc/nginx/sites-available/gerritserver { listen 80; server_name gerrit.yourcompany.com; # 或你的IP location / { auth_request /auth; # 将认证后的用户信息传递给Gerrit proxy_set_header GITLAB_USER $remote_user; proxy_set_header GITLAB_EMAIL $remote_useryourcompany.com; # 需要根据实际调整 proxy_set_header GITLAB_EXTERNAL_ID $remote_user; proxy_pass http://localhost:8081; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; } location /auth { internal; # 这里需要指向一个能验证Gitlab Token的认证端点 # 这是一个简化示例实际需要编写一个小的认证服务或使用lua脚本 # proxy_pass http://your-auth-service; # 为了简化初期可以先注释掉auth_request使用Gerrit自带的登录 return 200; } }这是一个高级配置完整的Gitlab OAuth2集成需要额外的开发工作。对于初期搭建你可以暂时使用Gerrit自带的数据库密码认证让团队手动注册账号。4.3 Gerrit权限模型浅析Gerrit的权限系统非常精细但略显复杂。它基于群组Group和项目Project的访问控制列表ACL。核心权限包括Read克隆/拉取代码。Push推送代码到refs/for/*创建Change。Label Code-Review给予-2到2的评审分数。2是合入Change的必要条件之一。Submit将Change合并到目标分支。通常你会创建Developers、Reviewers、Integrators等群组并为他们分配不同的权限。建议从简单的配置开始随着团队熟悉再逐步细化。5. Jenkins安装与插件生态配置Jenkins是整个自动化的枢纽它的强大离不开丰富的插件。5.1 安装Jenkins在服务器A上与Gerrit一起添加仓库并安装curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee /usr/share/keyrings/jenkins-keyring.asc /dev/null echo deb [signed-by/usr/share/keyrings/jenkins-keyring.asc] https://pkg.jenkins.io/debian-stable binary/ | sudo tee /etc/apt/sources.list.d/jenkins.list /dev/null sudo apt update sudo apt install jenkins -y修改端口避免与Gerrit冲突 Jenkins默认也使用8080端口我们需要修改。编辑/etc/default/jenkinsHTTP_PORT8080将其修改为另一个端口例如8082。然后重启Jenkinssudo systemctl restart jenkins。初始解锁 访问http://服务器A IP:8082你会看到解锁页面。按照提示在服务器上执行sudo cat /var/lib/jenkins/secrets/initialAdminPassword获取密码填入后继续。安装推荐插件在初始化向导中选择“安装推荐的插件”。这会安装最常用的一批插件如Git、Pipeline等。5.2 必须安装的核心插件初始化后我们需要安装与Gitlab和Gerrit集成的关键插件。进入Manage Jenkins-Plugins-Available plugins。GitLab Plugin用于触发Jenkins构建基于Gitlab的事件如Merge Request。搜索并安装。Gerrit Trigger这是与Gerrit集成的核心插件。它允许Jenkins监听Gerrit的事件有新的Patch Set推送到Change。搜索并安装。SSH Agent Plugin让Jenkins能够使用SSH密钥进行认证如拉取Gitlab私有库。Pipeline和Blue Ocean用于定义和可视化流水线。推荐安装。Role-based Authorization Strategy如果需要更精细的用户权限管理可以安装此插件。安装后重启Jenkins。5.3 系统基础配置配置Git路径进入Manage Jenkins-Global Tool Configuration找到Git部分确保Path to Git executable正确通常是/usr/bin/git。配置SSH密钥为了让Jenkins能拉取Gitlab代码需要将之前生成的私钥~/.ssh/id_rsa添加到Jenkins。进入Manage Jenkins-Credentials-System-Global credentials-Add Credentials。类型选择SSH Username with private key。Username填写你在Gitlab上使用的用户名如root。在Private Key处选择Enter directly然后粘贴Jenkins服务器上~/.ssh/id_rsa文件的内容注意是整个文件内容包括-----BEGIN RSA PRIVATE KEY-----和-----END RSA PRIVATE KEY-----。保存记下这个凭证的ID如gitlab-ssh-key。配置Gitlab API Token同样在Credentials里添加一个新的Username with password类型的凭证。Username可以填gitlab。Password填入你在Gitlab生成的Access Token。保存记下ID如gitlab-api-token。6. 连接三者构建自动化流水线现在三个系统各自独立运行起来了。最关键的一步是让它们联动起来。6.1 配置Jenkins与Gerrit的联动在Jenkins中配置Gerrit Server进入Manage Jenkins-Configure System找到Gerrit Trigger部分。点击Add Gerrit Server输入一个名称如MyGerrit。Frontend URL填写Gerrit的网页访问地址如http://192.168.1.10:8081。Backend URL填写Gerrit的SSH访问地址格式为ssh://gerrit-username192.168.1.10:29418。这里的用户名是你在Gerrit上有SSH权限的用户通常是管理员初始账号。SSH Keyfile你需要为Jenkins生成一对新的SSH密钥或使用已有的并将私钥路径填写在这里如/var/lib/jenkins/.ssh/id_rsa将公钥添加到Gerrit用户的SSH Keys设置中。测试连接配置好后点击Test Connection。如果成功你会看到Gerrit的版本信息。在Gerrit中配置Trigger实际上更常见的模式是在Jenkins项目中配置“Gerrit event”触发器。我们稍后在创建Job时配置。6.2 配置Jenkins与Gitlab的联动在Jenkins中配置GitLab进入Manage Jenkins-Configure System找到GitLab部分。GitLab host URL填写你的Gitlab地址如http://gitlab-server。Credentials选择之前创建的包含Gitlab API Token的凭证gitlab-api-token。点击Test Connection应该显示Success。在Gitlab中配置Webhook进入你的Gitlab项目 -Settings-Webhooks。URL格式http://jenkins-user:jenkins-api-tokenjenkins-server:port/project/your-job-name。例如http://admin:11a2b3c4d5e6f7g8h9i0j192.168.1.10:8082/project/my-awesome-app-ci。admin:11a2b3c4d5e6f7g8h9i0j其中admin是Jenkins用户名后面一串是用户的API Token在Jenkins用户设置里生成。project是固定路径my-awesome-app-ci是你的Jenkins任务名。Trigger选择Push events和Merge request events。点击Add webhook然后点击Test-Push events查看是否返回200 OK。6.3 创建第一个Pipeline Job我们将创建一个Pipeline任务它由Jenkinsfile定义存储在Gitlab仓库根目录实现代码即配置。在Jenkins上创建任务点击New Item输入任务名如my-awesome-app-pipeline选择Pipeline点击OK。在配置页面的Pipeline部分选择Pipeline script from SCM。SCM选择Git。Repository URL填写你的Gitlab项目SSH地址如gitgitlab-server:dev-team/my-awesome-app.git。Credentials选择之前添加的SSH密钥凭证gitlab-ssh-key。分支指定为*/main或你的主分支名。Script Path填写Jenkinsfile。编写Jenkinsfile 在你的Gitlab项目根目录创建Jenkinsfile。一个基础的、与Gerrit联动的示例pipeline { agent any // 使用任何可用的代理节点执行 triggers { // 当Gerrit上有新的patchset被推送到refs/for/main时触发 gerrit( events: [ changeMerged(), patchsetCreated( excludeDrafts: false, excludeTrivialRebase: false, excludeNoCodeChange: false ) ], project: my-awesome-app, // Gerrit上的项目名 branches: [ [compareType: PLAIN, pattern: main] ] ) } stages { stage(Checkout) { steps { // 从Gerrit拉取代码。GERRIT_REFSPEC和GERRIT_PATCHSET_REVISION是Gerrit Trigger插件提供的环境变量 checkout([ $class: GitSCM, branches: [[name: $GERRIT_REFSPEC]], extensions: [], userRemoteConfigs: [[ url: ssh://gerrit-user192.168.1.10:29418/my-awesome-app, credentialsId: gerrit-ssh-key // Jenkins中配置的访问Gerrit的SSH密钥凭证 ]] ]) } } stage(Build Test) { steps { script { // 这里根据你的项目语言和构建工具来写例如Maven、Gradle、npm等 sh echo 开始构建... // 假设是Maven项目 // sh mvn clean compile // sh mvn test } } post { success { // 构建成功可以通知Gerrit进行验证 step([$class: GerritReview, message: Build Successful, verified: [score: 1]]) } failure { // 构建失败通知Gerrit验证失败 step([$class: GerritReview, message: Build Failed! Please check the Jenkins logs., verified: [score: -1]]) } } } // 可以添加更多阶段如代码质量扫描、打包、部署等 } }这个流水线做了两件事1. 监听Gerrit事件2. 构建后向Gerrit回写验证结果1或-1。这实现了自动化验证与人工代码评审的结合。配置Gerrit Trigger 在刚才创建的Jenkins任务配置页面找到Build Triggers勾选Gerrit event。这里可以图形化地配置监听哪些Gerrit事件如Patchset Created, Change Merged等以及针对哪些项目和分支。配置应与Jenkinsfile中的triggers块一致。7. 权限整合与安全加固一个可用的系统还需要考虑权限和安全。7.1 统一账户与单点登录SSO思路维护三套账户Jenkins, Gitlab, Gerrit非常麻烦。理想状态是使用Gitlab账户通用于三者。Gitlab作为OAuth2提供方可以配置Jenkins和Gerrit使用Gitlab进行OAuth认证。这需要分别在Jenkins安装GitLab Authentication插件在Gerrit配置OAuth插件。这是一个相对高级的配置需要仔细阅读官方文档。使用LDAP/AD如果公司有统一的LDAP或Active Directory可以将三者都对接至LDAP这是企业级最规范的方案。7.2 Jenkins权限管理使用Role-based Authorization Strategy插件可以精细控制。在Manage Jenkins-Configure Global Security中启用Role-Based Strategy。进入Manage Jenkins-Manage and Assign Roles。Manage Roles可以定义全局角色如admin,read和项目角色如dev-.*匹配所有以dev-开头的项目。Assign Roles将用户或用户组分配给这些角色。7.3 网络与访问安全使用HTTPS为Gitlab、Jenkins、Gerrit的对外服务配置SSL证书可以使用Let‘s Encrypt免费证书。防火墙最小化原则只开放必要的端口到必要的IP段如公司内网。定期备份制定备份策略定期备份Jenkins的JENKINS_HOME目录、Gitlab的数据使用gitlab-rake gitlab:backup:create、Gerrit的review_site目录。8. 日常运维与问题排查实录系统跑起来后日常维护和问题排查才是真正的挑战。8.1 服务监控与日志查看Jenkins日志位置/var/log/jenkins/jenkins.log。使用sudo tail -f /var/log/jenkins/jenkins.log实时查看。监控构建队列和执行器状态避免任务堆积。Gitlab服务状态sudo gitlab-ctl status。日志各类日志在/var/log/gitlab/目录下如nginx/gitlab_access.log,sidekiq/current。检查资源sudo gitlab-ctl tail可以跟踪所有日志。Gerrit日志在/var/gerrit/review_site/logs/目录下如error_log,httpd_log。启动/停止bin/gerrit.sh start/stop/restart。8.2 常见问题速查表问题现象可能原因排查步骤与解决方案Jenkins无法从Gitlab拉取代码1. SSH密钥未正确配置。2. Jenkins凭证配置错误。3. Gitlab仓库URL错误或权限不足。1. 在Jenkins服务器上手动执行ssh -T gitgitlab-server测试连接。2. 检查Jenkins中SSH凭证的私钥内容是否正确、用户名是否匹配Gitlab。3. 确认仓库URL并在Gitlab检查该SSH密钥是否有项目访问权限。Gerrit Trigger不触发Jenkins构建1. Gerrit Server配置错误。2. Jenkins Job中Gerrit Trigger配置的项目/分支不匹配。3. Gerrit插件版本与Gerrit服务器不兼容。1. 在Jenkins系统配置中测试Gerrit连接。2. 检查Gerrit Trigger配置的Project和Branch模式是否与提交的Change匹配。可以使用Pattern如my-project或RegExp如^my-project$。3. 查看Jenkins日志搜索Gerrit相关错误。Gitlab Webhook测试返回4031. Jenkins API Token错误或用户权限不足。2. Jenkins的CSRF保护跨站请求伪造可能阻止了请求。1. 在Jenkins用户设置中重新生成API Token并在Webhook中更新。2. 进入Manage Jenkins-Configure Global Security检查CSRF Protection设置可以尝试暂时禁用测试或确保在请求头中包含了正确的Crumb。更佳实践是在Jenkins安装Strict Crumb Issuer插件并配置。Pipeline中checkout阶段失败1. 指定的$GERRIT_REFSPEC环境变量为空或格式错误。2. 用于Gerrit克隆的SSH凭证错误。1. 确保此Pipeline确实是由Gerrit事件触发的。可以在Pipeline开始加一句sh envGerrit无法通过HTTP认证登录1. Nginx反向代理配置中传递的HTTP头部不正确。2. Gerrit的gerrit.config中[auth]部分配置错误。1. 检查Nginx配置中的proxy_set_header指令是否正确设置了用户信息头部。2. 对比Gerrit官方文档的HTTP认证配置示例。一个简单的调试方法是在Nginx配置中将用户头部写死如proxy_set_header GITLAB_USER testuser;看是否能以testuser身份登录Gerrit。8.3 性能调优与备份策略Jenkins增加执行器在Manage Jenkins-Manage Nodes and Clouds-Master-Configure中可以增加# of executors但不要超过CPU核心数。清理旧数据安装Workspace Cleanup插件在构建后清理工作空间。定期进入Manage Jenkins-Manage Old Data清理旧的构建记录。Gitlab调整Sidekiq进程对于内存较大的服务器可以编辑/etc/gitlab/gitlab.rb增加sidekiq[max_concurrency]和puma[worker_processes]的值。使用对象存储将仓库备份、大型文件存储到外部对象存储如S3兼容服务减轻本地磁盘压力。备份Jenkins直接备份/var/lib/jenkins默认目录整个文件夹。可以使用thinBackup插件进行定期备份。Gitlab使用sudo gitlab-rake gitlab:backup:create创建备份备份文件默认在/var/opt/gitlab/backups/。务必同时备份配置文件/etc/gitlab/gitlab.rb和/etc/gitlab/gitlab-secrets.json。Gerrit备份/var/gerrit/review_site目录。可以使用gerrit.war的init命令进行迁移和恢复。搭建和维护这样一个持续集成环境初期确实会花费不少精力尤其是权限和网络配置的细节。但一旦这套流程稳定运行它所带来的代码质量提升、团队协作效率的改进是非常显著的。最关键的是要让团队理解和接受“代码在合入前必须经过自动化验证和同伴评审”这一工作流这比工具本身更重要。在实际操作中建议先在一个小型的试点项目上跑通整个流程让团队成员熟悉Gerrit的Change提交、评审流程以及Jenkins Pipeline的编写然后再逐步推广到更大的项目中去。