内网部署Gerrit服务器:从零搭建企业级代码审查平台
1. 项目概述为什么我们需要一个自己的Gerrit在团队协作开发中代码审查是保证代码质量、统一编码规范、促进知识共享的关键环节。你可能用过GitLab的Merge Request或者GitHub的Pull Request它们很好用但对于追求更严格、更流程化代码审查的团队尤其是遵循某些特定开发流程如AOSP Android开源项目的团队Gerrit往往是一个更专业的选择。简单来说Gerrit是一个基于Git版本控制的Web代码审查和项目管理工具。它最核心的特点是**“提交即审查”**的工作流。与常见的“先提交到特性分支再发起合并请求”的模式不同Gerrit引入了“Change”的概念。开发者直接将代码推送到Gerrit服务器的一个特殊引用refs/for/branch这会自动创建一个待审查的Change。只有经过审查、验证如CI构建通过并最终被项目维护者批准后代码才会被合入目标分支。这种模式强制了审查前置确保了主分支的洁净与稳定。那么为什么要在内网搭建一个Gerrit服务器呢原因很直接安全、可控、高性能。将代码仓库和审查平台部署在内网环境意味着你的核心资产与外网隔离访问速度极快并且你可以完全自定义用户权限、插件和工作流使其完美契合团队内部的开发规范。无论是中小型创业团队还是大型企业的内部项目一个自托管的Gerrit服务器都能提供企业级的代码管理能力。接下来我将手把手带你完成从零开始搭建Gerrit服务器并配置内网访问的全过程。整个过程基于主流的Linux发行版我会解释每一个步骤背后的意图并分享我在多次部署中积累的实操技巧和避坑指南。2. 环境准备与核心组件解析在开始安装之前我们需要明确Gerrit的运行依赖和架构。Gerrit本质上是一个Java Web应用程序它通常运行在一个Servlet容器如Jetty中并使用数据库如PostgreSQL、H2或MySQL来存储元数据用户、权限、Change信息等。Git仓库则直接存储在服务器的文件系统上。2.1 系统与软件要求我选择Ubuntu 22.04 LTS作为演示系统因为它拥有良好的社区支持和稳定的软件包。其他Linux发行版步骤类似主要区别在于包管理命令。基础依赖Java运行时环境 (JRE)Gerrit 3.x 版本需要 Java 11 或更高版本。我们将安装OpenJDK 11。Git这是Gerrit的基石必须安装。数据库为了生产环境的稳定性和性能强烈推荐使用PostgreSQL。虽然Gerrit内置了H2数据库用于快速入门但它不适合多用户生产环境。我们将使用PostgreSQL。Web服务器可选但推荐虽然Gerrit内置了Jetty但在生产环境中我们通常会在其前面放置一个反向代理服务器如Nginx或Apache用于处理SSL终止、静态文件缓存、负载均衡等这能让Gerrit更安全、高效。2.2 安装与配置基础环境首先更新系统并安装必要的工具。sudo apt update sudo apt upgrade -y sudo apt install -y wget curl vim git安装OpenJDK 11sudo apt install -y openjdk-11-jre-headless安装后验证Java版本java -version应该能看到类似openjdk version 11.0.22的输出。安装与配置PostgreSQL安装PostgreSQL服务器和客户端sudo apt install -y postgresql postgresql-client启动并设置PostgreSQL开机自启sudo systemctl start postgresql sudo systemctl enable postgresql切换到postgres系统用户为Gerrit创建专用的数据库和用户sudo -i -u postgres进入PostgreSQL交互终端psql执行以下SQL命令请将‘your_strong_password‘替换为一个强密码CREATE USER gerrit WITH PASSWORD ‘your_strong_password‘; CREATE DATABASE gerritdb OWNER gerrit; ALTER DATABASE gerritdb SET timezone TO ‘UTC‘; -- 统一时区 \q然后输入exit返回普通用户。注意数据库用户和密码安全这里创建的密码将写入Gerrit配置文件。请务必使用强密码并确保配置文件 (gerrit.config) 的权限设置为仅所有者可读chmod 600。3. Gerrit服务器安装与初始化配置我们将从Gerrit官方下载最新的稳定版war包进行安装。这种方式比使用系统包管理器更灵活易于升级和管理。3.1 下载与安装Gerrit创建一个专用的系统用户来运行Gerrit服务这符合安全最小权限原则sudo adduser --system --shell /bin/bash --group gerrit切换到gerrit用户并进入其家目录sudo -i -u gerrit cd ~从Gerrit官方镜像下载最新的稳定版war包。你可以访问 Gerrit Releases 查看最新版本。以3.9.0版本为例wget https://gerrit-releases.storage.googleapis.com/gerrit-3.9.0.war初始化Gerrit站点。这将创建一个目录例如gerrit_site其中包含所有配置文件、Git仓库和插件。java -jar gerrit-3.9.0.war init --batch --dev -d ~/gerrit_site--batch批处理模式使用默认配置避免交互式提问。--dev启用开发模式这会放宽一些安全限制如允许使用OpenID便于初次设置。生产环境应移除此选项。-d ~/gerrit_site指定Gerrit站点目录的路径。执行后会在~/gerrit_site目录下生成初始结构。3.2 核心配置文件详解与修改初始化生成的配置可能不完全符合我们的需求尤其是数据库和连接设置。我们需要编辑gerrit_site/etc/gerrit.config文件。cd ~/gerrit_site vim etc/gerrit.config以下是一个针对内网部署、使用PostgreSQL数据库的基础配置示例。你需要根据实际情况修改database.password、auth.gitBasicAuthPolicy以及http.listenUrl。[gerrit] basePath git serverId 随机生成的UUID首次启动会自动生成 canonicalWebUrl http://your-server-internal-ip:8080/ # 内网访问地址 [database] type postgresql hostname localhost database gerritdb username gerrit password your_strong_password # 替换为之前设置的密码 [index] type lucene [auth] type DEVELOPMENT_BECOME_ANY_ACCOUNT # 开发模式方便测试。生产环境需改为 HTTP/LDAP/OAuth等 gitBasicAuthPolicy HTTP # 允许使用HTTP密码进行Git操作 [receive] enableSignedPush false [sendemail] smtpServer localhost smtpServerPort 25 from MIXED [container] user gerrit javaHome /usr/lib/jvm/java-11-openjdk-amd64 javaOptions -Dflogger.backend_factorycom.google.common.flogger.backend.log4j.Log4jBackendFactory#getInstance [httpd] listenUrl http://*:8080/ # 监听所有IP的8080端口 [sshd] listenAddress *:29418 # Git SSH协议端口默认为29418 [cache] directory cache关键配置解析canonicalWebUrl这是Gerrit认为的自己的访问地址。邮件通知中的链接、Git远程仓库地址生成都基于此。在内网中通常设置为服务器的内网IP和端口。[database]确保这里的连接信息与之前创建的PostgreSQL数据库一致。[auth].typeDEVELOPMENT_BECOME_ANY_ACCOUNT是开发模式无需登录即可操作任何账户仅用于初次搭建测试。生产环境必须更换例如HTTP与Web服务器结合、LDAP连接公司AD域或OAUTH使用GitHub/Google等登录。[auth].gitBasicAuthPolicy设置为HTTP后用户可以使用在Gerrit Web界面设置的HTTP密码来执行git push等操作这比配置SSH密钥对新手更友好。[httpd].listenUrl定义了Gerrit内置Jetty监听的地址和端口。http://*:8080表示监听所有网络接口的8080端口。[sshd].listenAddressGerrit内置的SSH服务器端口用于Git的SSH协议克隆和推送。3.3 启动Gerrit服务并验证配置完成后可以首次启动Gerrit。cd ~/gerrit_site bin/gerrit.sh start使用tail命令查看日志确认启动无错误tail -f logs/gerrit.log当你看到类似Gerrit Code Review 3.9.0 ready的日志时说明启动成功。现在你可以在内网的另一台机器上打开浏览器访问http://你的服务器内网IP:8080。你应该能看到Gerrit的Web界面。由于我们使用了开发模式认证点击右上角的“Sign in”可能会直接以管理员身份登录或者允许你以任意用户名登录。实操心得初次启动的常见问题端口冲突如果8080或29418端口被占用Gerrit会启动失败。检查端口占用sudo netstat -tlnp | grep :8080并修改gerrit.config中的端口号。数据库连接失败日志中会出现Connection refused或Authentication failed。请仔细检查gerrit.config中的[database]配置特别是密码是否正确以及PostgreSQL服务是否正在运行 (sudo systemctl status postgresql)。文件权限问题确保整个gerrit_site目录及其子文件的所有者是gerrit用户。可以使用sudo chown -R gerrit:gerrit /home/gerrit/gerrit_site来修正。4. 配置内网访问与反向代理Nginx虽然现在可以通过IP:端口直接访问但这并不友好也不安全HTTP明文传输。我们通过Nginx配置反向代理实现以下目标使用域名访问例如http://gerrit.internal.company.com。SSL加密可选但推荐即使在内网使用HTTPS也能防止流量被嗅探更安全。我们可以使用自签名证书或内部CA颁发的证书。性能优化Nginx可以高效处理静态文件减轻Gerrit Jetty的负担。4.1 安装与配置Nginx首先在服务器上安装Nginxsudo apt install -y nginx创建一个新的Nginx配置文件例如/etc/nginx/sites-available/gerritsudo vim /etc/nginx/sites-available/gerrit写入以下配置。这里我们假设你有一个内网域名gerrit.internal并且暂时使用HTTP。后续会补充HTTPS配置。upstream gerrit { server 127.0.0.1:8080 max_fails3 fail_timeout30s; keepalive 32; } server { listen 80; server_name gerrit.internal; # 替换为你的内网域名或IP # 禁用iframe嵌入增强安全性 add_header X-Frame-Options SAMEORIGIN; add_header X-Content-Type-Options nosniff; location / { proxy_pass http://gerrit; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port; # 以下配置对Gerrit的WebSocket和事件流支持很重要 proxy_set_header Connection ; proxy_http_version 1.1; chunked_transfer_encoding off; proxy_buffering off; proxy_cache off; proxy_read_timeout 3600s; # 长连接超时设置 } # 缓存静态资源提升性能 location ~ ^/(plugins|static)/ { proxy_pass http://gerrit; proxy_cache my_cache; proxy_cache_valid 200 302 12h; expires 12h; add_header Cache-Control public; } }配置关键点解释upstream定义了后端Gerrit服务Jetty的地址和连接池设置。proxy_set_header这几行至关重要它们将客户端的真实信息如IP、协议传递给Gerrit。否则Gerrit日志里看到的全是来自Nginx127.0.0.1的请求。proxy_buffering off;和chunked_transfer_encoding off;对于Gerrit的实时事件流Event Stream功能是必须的否则用户界面无法实时收到代码审查的更新通知。静态资源缓存对/plugins和/static路径开启缓存能显著减少后端压力加快页面加载。启用该配置并重启Nginxsudo ln -s /etc/nginx/sites-available/gerrit /etc/nginx/sites-enabled/ sudo nginx -t # 测试配置文件语法 sudo systemctl reload nginx4.2 配置HTTPS使用自签名证书在内网使用HTTPS也是一个好习惯。我们可以快速生成一个自签名证书。创建证书存放目录并生成证书sudo mkdir -p /etc/nginx/ssl/gerrit.internal cd /etc/nginx/ssl/gerrit.internal sudo openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \ -keyout gerrit.key -out gerrit.crt \ -subj /CCN/STBeijing/LBeijing/OYourCompany/CNgerrit.internal-nodes生成无密码的私钥避免Nginx每次启动都要输入密码。-days 3650证书有效期10年。-subj证书主题信息CN必须填写你的内网域名。修改Nginx配置启用SSL 编辑之前的配置文件将listen 80;部分改为server { listen 443 ssl http2; server_name gerrit.internal; ssl_certificate /etc/nginx/ssl/gerrit.internal/gerrit.crt; ssl_certificate_key /etc/nginx/ssl/gerrit.internal/gerrit.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # ... 其余location配置保持不变 ... } # 强制将HTTP重定向到HTTPS server { listen 80; server_name gerrit.internal; return 301 https://$server_name$request_uri; }再次测试并重载Nginxsudo nginx -t sudo systemctl reload nginx重要更新Gerrit的canonicalWebUrl。 由于我们现在通过https://gerrit.internal访问必须修改gerrit.config否则Git远程地址和邮件链接会是错误的。sudo -i -u gerrit cd ~/gerrit_site vim etc/gerrit.config将canonicalWebUrl修改为canonicalWebUrl https://gerrit.internal/保存后重启Gerrit服务bin/gerrit.sh restart现在内网用户访问http://gerrit.internal会被自动重定向到https://gerrit.internal。浏览器会提示证书不安全因为是自签名的在内网环境中你可以将生成的gerrit.crt文件分发给团队成员导入到系统的受信任根证书颁发机构这样警告就会消失。5. 基础管理与使用入门服务器搭建好后我们需要进行一些基础设置并了解如何开始使用。5.1 管理员账户与基础设置注册首个管理员账户首次通过Web界面登录开发模式下可以直接输入任意用户名第一个登录的用户会自动成为管理员。创建新项目点击顶部导航栏的 “Projects” - “List” - “Create New Project”。输入项目名称例如my-awesome-project。“Submit Type” 选择Cherry Pick或Merge if Necessary这决定了代码合入的方式。Cherry Pick更清晰推荐使用。点击 “Create” 即可。配置项目权限这是Gerrit强大也稍复杂的地方。进入项目页面点击 “Access”。你可以为不同的分支refs/heads/*、标签refs/tags/*和Changerefs/for/*设置不同的权限组。常见的权限组有Anonymous Users匿名用户Registered Users所有登录用户Project Owners项目所有者。例如你可以给Registered Users组赋予refs/for/*的Push和Label Code-Review权限允许他们推送代码和参与评审。5.2 开发者工作流示例假设开发者Alice要向刚创建的my-awesome-project提交一个功能。克隆仓库git clone https://gerrit.internal/my-awesome-project cd my-awesome-project如果配置了SSH也可以用git clone ssh://alicegerrit.internal:29418/my-awesome-project创建特性分支并开发git checkout -b feature-awesome # ... 进行代码修改 ... git add . git commit -m “Implement an awesome feature”推送到Gerrit进行审查这是关键区别不是推送到远程分支而是推送到Gerrit的特殊引用refs/for/branch。git push origin HEAD:refs/for/main这条命令会在Gerrit上为main分支创建一个新的Change。审查流程Alice和同事Bob可以在Gerrit的Web界面上查看这个Change进行行内评论Inline Comments。评审者可以给出 Code-Review 标签2(批准)1(倾向于同意)0(无意见)-1(需要修改)-2(拒绝)。通常项目会设置规则比如需要至少一个2且没有-2才能合入。如果Alice需要根据反馈修改代码她可以在本地同一个分支上继续提交然后使用--amend修改上一次提交再次推送Gerrit会自动识别这是同一个Change的新补丁集Patch Set。合入代码 当Change满足所有合入条件评审通过、CI验证通过等具有合入权限的维护者点击 “Submit” 按钮代码就会被合入目标分支如main。5.3 配置邮件通知为了让团队成员及时收到评审请求和评论通知需要配置邮件服务器。编辑gerrit_site/etc/gerrit.config中的[sendemail]部分。[sendemail] smtpServer smtp.your-company.com # 公司内部SMTP服务器 smtpServerPort 587 smtpEncryption tls sslVerify false # 如果使用自签名证书可能需要设为false smtpUser gerrit-noreplyyour-company.com smtpPass your_email_password from Code Review gerrit-noreplyyour-company.com然后重启Gerrit服务。你可以在项目或用户的设置中订阅邮件通知。6. 生产环境加固与高级配置将Gerrit用于正式团队协作前还需要进行一些加固和优化。6.1 更换认证方式移除开发模式开发模式 (DEVELOPMENT_BECOME_ANY_ACCOUNT) 毫无安全性可言必须更换。方案一HTTP认证与反向代理结合这是较简单的内部系统认证方式。Nginx负责基础认证然后将认证用户名传递给Gerrit。在Nginx配置中启用基础认证sudo apt install -y apache2-utils sudo htpasswd -c /etc/nginx/.gerrit-htpasswd alice # 创建文件并添加第一个用户 sudo htpasswd /etc/nginx/.gerrit-htpasswd bob # 添加第二个用户在Nginx的location /块中添加auth_basic “Gerrit Code Review“; auth_basic_user_file /etc/nginx/.gerrit-htpasswd;修改gerrit.config[auth] type HTTP logoutUrl https://gerrit.internal/logout # 指向一个自定义的登出页面 httpHeader X-Forwarded-User # 这是Nginx传递给Gerrit的头部名在Nginx的proxy_set_header部分添加proxy_set_header X-Forwarded-User $remote_user;重启Nginx和Gerrit。现在用户需要通过Nginx的弹窗登录Gerrit会信任Nginx传递过来的用户名。方案二LDAP/Active Directory认证企业常用如果你的公司有AD域这是最理想的统一认证方式。配置较为复杂需要在gerrit.config中详细配置[ldap]部分指定服务器、绑定DN、用户查询基准等。建议参考Gerrit官方LDAP文档进行配置。6.2 性能调优与监控JVM堆内存设置编辑gerrit_site/bin/gerrit.sh找到JAVA_OPTIONS或GERRIT_ARGS部分调整堆内存大小。对于中小型团队-Xmx4g -Xms2g可能是个起点。监控logs/gerrit_logs/error_log中的GC日志根据实际情况调整。数据库连接池在gerrit.config的[database]部分可以配置poolLimit和poolMaxIdle等参数优化与PostgreSQL的连接。Git仓库GC定期对Git仓库进行垃圾回收可以节省磁盘空间并提升性能。可以配置定时任务Cron Job来执行git gc。# 例如每周日凌晨3点对所有仓库执行增量GC 0 3 * * 0 sudo -u gerrit find /home/gerrit/gerrit_site/git -name “*.git“ -type d -exec git --git-dir{} gc --auto \;日志轮转Gerrit的日志文件会越来越大。可以使用系统的logrotate工具来管理。创建一个配置文件/etc/logrotate.d/gerrit。6.3 备份策略必须为Gerrit站点制定备份策略。数据库备份定期使用pg_dump备份PostgreSQL数据库。sudo -u postgres pg_dump gerritdb /path/to/backup/gerritdb_$(date %Y%m%d).sql站点目录备份备份整个gerrit_site目录但可以排除cache,index,logs这些可以重建的临时目录。tar --exclude‘./cache‘ --exclude‘./index‘ --exclude‘./logs‘ -czf /path/to/backup/gerrit_site_$(date %Y%m%d).tar.gz /home/gerrit/gerrit_siteGit仓库备份gerrit_site/git目录包含了所有项目的裸仓库。它是备份的核心。确保备份命令以gerrit用户身份运行避免权限问题。一个完整的备份脚本应该包含以上步骤并最好能传输到远程存储。7. 常见问题排查与维护技巧即使按照步骤操作也可能会遇到问题。这里记录一些典型问题的排查思路。7.1 服务启动失败症状执行bin/gerrit.sh start后很快退出status显示未运行。排查首要查看日志tail -n 100 ~/gerrit_site/logs/gerrit.log。错误信息通常非常明确。检查端口占用sudo netstat -tlnp | grep -E ‘:(8080|29418)‘。检查Java版本java -version确认是Java 11。检查数据库确认PostgreSQL服务正在运行且gerrit.config中的连接信息正确。可以尝试用psql命令行工具手动连接测试。检查文件权限确保gerrit_site目录下所有文件的所有者是gerrit用户。7.2 网页可以访问但Git操作失败症状git clone或git push失败。排查HTTP推送失败检查gerrit.config中[auth].gitBasicAuthPolicy是否设置为HTTP或HTTP_LDAP。确保用户已在Web界面设置了自己的HTTP密码Settings - HTTP Password。SSH推送失败检查Gerrit SSH端口默认29418是否在防火墙中开放。检查用户是否将公钥上传到GerritSettings - SSH Keys。测试SSH连接ssh -p 29418 usernamegerrit.internal应该看到Gerrit的欢迎横幅而不是shell提示符。如果超时或拒绝检查网络和Gerrit的[sshd]配置。权限错误错误信息如PROJECT_CREATE权限不足。说明该用户没有对应Git引用如refs/for/*的Push权限。需要项目管理员在项目的Access页面配置。7.3 邮件通知不发送症状代码提交或评审后收不到邮件。排查检查gerrit.config中[sendemail]部分的配置特别是SMTP服务器地址、端口和认证信息。查看Gerrit的邮件发送日志grep sendmail ~/gerrit_site/logs/gerrit.log。测试SMTP服务器是否可用可以使用swaks或telnet命令手动测试SMTP连接和认证。检查用户是否在通知设置中屏蔽了邮件Settings - Notifications。7.4 性能缓慢症状页面加载慢Git操作延迟高。排查与优化检查服务器资源使用top,htop,iostat查看CPU、内存、磁盘I/O使用率。Gerrit对磁盘I/O比较敏感尤其是Git操作频繁时。考虑使用SSD硬盘。检查数据库性能可能是数据库瓶颈。检查PostgreSQL的慢查询日志。确保为gerritdb数据库创建了适当的索引Gerrit通常会自动创建。可以考虑调整PostgreSQL的shared_buffers,work_mem等参数。调整Gerrit缓存在gerrit.config的[cache]部分可以调整缓存大小和类型。参考官方文档进行调优。优化Nginx缓存确保静态资源缓存配置生效检查Nginx的访问和错误日志。7.5 升级Gerrit版本升级前务必完整备份数据库和站点目录。停止当前Gerrit服务bin/gerrit.sh stop。下载新版本的war包。运行升级命令仍在原站点目录下java -jar gerrit-new-version.war init -d ~/gerrit_site。Gerrit会检测到现有版本并执行升级脚本。仔细阅读升级过程的输出特别是需要手动干预的步骤如果有。升级完成后启动服务bin/gerrit.sh start。详细检查所有核心功能是否正常。搭建和维护一个Gerrit服务器需要一些耐心和细致的配置但一旦稳定运行它将为团队的代码质量提供强大的保障。从简单的代码推送到复杂的权限模型和集成工作流Gerrit提供了极大的灵活性。建议从小团队、少数项目开始试用逐步熟悉其概念和配置再推广到更复杂的场景。