零停机升级
- Tier: Free, Premium, Ultimate
- Offering: GitLab Self-Managed
通过零停机升级,可以在不中断服务的情况下升级正在运行的 GitLab 环境。本指南将带你了解执行此类升级的核心流程。
总体而言,这个过程通过按特定顺序依次升级 GitLab 节点来实现,结合使用负载均衡、高可用系统和平滑重载,以最小化中断。
本指南仅适用于相关的核心 GitLab 组件。对于第三方服务(如 AWS RDS)的升级或管理,请参考相应的文档。
开始之前
作为升级过程的一部分实现真正的零停机,对于任何分布式应用来说都相当困难。本指南中描述的流程已针对我们的高可用 参考架构 进行了测试,结果表明实际上没有可观察到的停机时间,但请注意,根据具体系统配置的不同,您的体验可能会有所差异。
为了增加信心,一些客户发现通过使用特定的负载均衡器或基础设施功能手动排空节点等技术取得了成功。这些技术很大程度上依赖于底层基础设施功能,因此不在本指南中涵盖。如需更多信息,请联系您的 GitLab 代表或 支持团队。
要求和注意事项
零停机升级流程有以下要求:
- 零停机升级仅支持在多节点 GitLab 环境上,该环境使用 Linux 包构建,并配置了负载均衡和可用的高可用机制,具体如下:
- 为 Rails 节点配置外部负载均衡器,并启用对 Readiness (
/-/readiness) 端点的健康检查。 - 为任何 PgBouncer 和 Praefect 组件配置内部负载均衡器,并启用 TCP 健康检查。
- 如果存在 Consul、Postgres、Redis 组件,则为其配置高可用机制。
- 任何未以高可用方式部署的组件都需要单独进行停机升级。
- 对于数据库,Linux 包仅支持主 GitLab 数据库的高可用。对于任何其他数据库,如 Praefect 数据库,需要第三方数据库解决方案来实现高可用,从而避免停机。
- 为 Rails 节点配置外部负载均衡器,并启用对 Readiness (
- 您一次只能升级一个小版本。例如从
16.1升级到16.2,而不是直接升级到16.3。如果跳过版本,数据库修改可能会以错误的顺序运行 并导致数据库架构损坏。 - 您必须使用部署后迁移。
- GitLab Charts 不支持零停机升级。GitLab Operator 提供支持,但此部署方法存在已知限制,因此目前不在本指南中涵盖。
除了上述内容,还需注意以下事项:
- 大多数情况下,如果补丁版本不是最新的,您可以安全地从补丁版本升级到下一个次要版本。例如,即使
16.3.3已经发布,从16.3.2升级到16.4.1也应该是安全的。您应该验证与您的 升级路径 相关的特定版本升级说明,并注意任何必需的升级步骤: - 某些版本可能包含 后台迁移。这些迁移由 Sidekiq 在后台执行,通常用于数据迁移。后台迁移仅在月度版本中添加。
- 某些主要或次要版本可能需要完成一组后台迁移。虽然这不需要停机(如果满足之前的条件),但您需要在每个主要或次要版本升级之间等待后台迁移完成。
- 通过增加能够处理
background_migration队列中作业的 Sidekiq 工作进程数量,可以减少完成这些迁移所需的时间。要查看此队列的大小,请在升级前检查后台迁移。
- 当 Gitaly 设置为集群或分片配置时,由于具有平滑重载机制,可以进行零停机升级。对于 Gitaly 集群 (Praefect) 组件,也可以直接进行零停机升级,但 GitLab Linux 包不为其数据库提供高可用支持,因此需要第三方数据库解决方案来避免停机。
- PostgreSQL 主要版本升级 是一个独立的过程,不属于零停机升级的范围(较小的升级则涵盖)。
- 零停机升级支持您使用 GitLab Linux 包部署的指定 GitLab 组件。如果您通过支持的第三方服务部署了某些组件,例如 AWS RDS 中的 PostgreSQL 或 GCP Memorystore 中的 Redis,这些服务的升级需要按照其标准流程单独执行。
- 作为一般指导原则,数据量越大,升级完成所需的时间就越长。在测试中,任何小于 10 GB 的数据库通常不会超过一小时,但您的体验可能会有所不同。
如果您想升级多个版本或不满足这些要求,应该考虑使用 停机升级。
升级顺序
我们建议采用"从后到前"的方法来确定零停机升级组件的顺序。通常这应该是先升级有状态的后端,然后是它们的依赖项,最后是前端。虽然部署顺序可以更改,但最好一起部署运行 GitLab 应用程序代码(Rails、Sidekiq)的组件。如果可能,单独升级支持基础设施(PostgreSQL、PgBouncer、Consul、Gitaly、Praefect、Redis),因为这些组件不依赖于主要版本更新中引入的变更。
因此,我们通常建议以下顺序:
- Consul
- PostgreSQL
- PgBouncer
- Redis
- Gitaly
- Praefect
- Rails
- Sidekiq
多节点/高可用部署
在本节中,我们将介绍通过按 升级顺序 依次处理每个节点,并让负载均衡器/高可用机制相应处理每个节点下线,来升级多节点 GitLab 环境的核心流程。
在本指南中,我们将升级使用 Linux 包构建的 200 RPS 或 10,000 用户参考架构。
Consul、PostgreSQL、PgBouncer 和 Redis
Consul、PostgreSQL、PgBouncer 和 Redis 组件都遵循相同的基本流程进行零停机升级。
在每个组件的节点上依次运行以下步骤来执行升级:
-
在
/etc/gitlab/skip-auto-reconfigure创建一个空文件。这可以防止升级运行gitlab-ctl reconfigure,该命令默认会自动停止 GitLab,运行所有数据库迁移,然后重新启动 GitLab:sudo touch /etc/gitlab/skip-auto-reconfigure -
重新配置并重启以获取最新代码:
sudo gitlab-ctl reconfigure先重启 Consul 客户端,然后重启所有其他服务,以确保 PostgreSQL 故障转移能够平滑进行:
sudo gitlab-ctl restart consul sudo gitlab-ctl restart-except consulsudo gitlab-ctl restart
Gitaly
Gitaly 在升级时遵循相同的核心流程,但有一个关键区别:Gitaly 进程本身不会重启,因为它内置了在最早机会平滑重载的机制。其他组件仍需要重启。
升级过程尝试将控制权平稳地移交给新的 Gitaly 进程。在升级开始前启动的现有长时间运行的 Git 请求可能会在此移交过程中最终被丢弃。将来此功能可能会改变,更多信息请参阅此 史诗。
此流程适用于 Gitaly 分片和集群配置。在每个 Gitaly 节点上依次运行以下步骤来执行升级:
-
在
/etc/gitlab/skip-auto-reconfigure创建一个空文件。这可以防止升级运行gitlab-ctl reconfigure,该命令默认会自动停止 GitLab,运行所有数据库迁移,然后重新启动 GitLab:sudo touch /etc/gitlab/skip-auto-reconfigure -
运行
reconfigure命令以获取最新代码,并指示 Gitaly 在下一个机会平滑重载:sudo gitlab-ctl reconfigure -
最后,虽然 Gitaly 会平滑重载,但其他已部署的组件仍需要重启:
# 获取除 Gitaly 外已部署的其他组件列表 sudo gitlab-ctl status # 重启除 Gitaly 外的每个组件。以下示例针对 Consul、Node Exporter 和 Logrotate sudo gitlab-ctl restart consul node-exporter logrotate
Gitaly 集群 (Praefect)
对于 Gitaly 集群 (Praefect) 配置,您必须通过使用平滑重载以类似方式部署和升级 Praefect。
升级过程尝试将控制权平稳地移交给新的 Praefect 进程。在升级开始前启动的现有长时间运行的 Git 请求可能会在此移交过程中最终被丢弃。将来此功能可能会改变,更多信息请参阅此 史诗。
本节专门关注 Praefect 组件,不包括其必需的 PostgreSQL 数据库。GitLab Linux 包不提供高可用支持,因此也不支持 Praefect 数据库的零停机。需要第三方数据库解决方案来避免停机。
Praefect 还必须执行数据库迁移来升级现有数据。为了避免冲突,迁移应该只在单个 Praefect 节点上运行。为此,将特定节点指定为运行迁移的部署节点。在以下步骤中,这被称为 Praefect 部署节点:
-
在 Praefect 部署节点上:
-
在
/etc/gitlab/skip-auto-reconfigure创建一个空文件。这可以防止升级运行gitlab-ctl reconfigure,该命令默认会自动停止 GitLab,运行所有数据库迁移,然后重新启动 GitLab:sudo touch /etc/gitlab/skip-auto-reconfigure -
确保
/etc/gitlab/gitlab.rb中设置了praefect['auto_migrate'] = true,以便运行数据库迁移。 -
运行
reconfigure命令以获取最新代码,应用 Praefect 数据库迁移并平滑重启:sudo gitlab-ctl reconfigure
-
-
在所有 其他 Praefect 节点上:
-
在
/etc/gitlab/skip-auto-reconfigure创建一个空文件。这可以防止升级运行gitlab-ctl reconfigure,该命令默认会自动停止 GitLab,运行所有数据库迁移,然后重新启动 GitLab:sudo touch /etc/gitlab/skip-auto-reconfigure -
确保
/etc/gitlab/gitlab.rb中设置了praefect['auto_migrate'] = false,以防止reconfigure自动运行数据库迁移。 -
运行
reconfigure命令以获取最新代码并平滑重启:sudo gitlab-ctl reconfigure
-
-
最后,虽然 Praefect 会平滑重载,但其他已部署的组件仍需要重启。在所有 Praefect 节点上:
# 获取除 Praefect 外已部署的其他组件列表 sudo gitlab-ctl status # 重启除 Praefect 外的每个组件。以下示例针对 Consul、Node Exporter 和 Logrotate sudo gitlab-ctl restart consul node-exporter logrotate
Rails
Rails 作为 Web 服务器主要由 Puma、Workhorse 和 NGINX 组成。
这些组件在执行实时升级时具有不同的行为。虽然 Puma 允许平滑重载,但 Workhorse 不允许。最好的方法是通过其他方式(例如使用负载均衡器)平滑排空节点。您也可以通过使用节点上的 NGINX 及其平滑关闭功能来实现。本节介绍 NGINX 方法。
除了上述内容,Rails 是需要执行主数据库迁移的地方。与 Praefect 类似,最好的方法是使用部署节点。如果当前使用 PgBouncer,也需要绕过它,因为 Rails 在尝试运行迁移时使用咨询锁来防止在同一数据库上并发运行迁移。这些锁不会在事务间共享,导致在使用 PgBouncer 的事务池模式运行数据库迁移时出现 ActiveRecord::ConcurrentMigrationError 和其他问题。
-
在 Rails 部署节点上:
-
平滑排空节点流量。您可以通过多种方式实现,但一种方法是使用 NGINX,向其发送
QUIT信号,然后停止服务。例如,您可以使用以下 shell 脚本:# 向 NGINX 主进程发送 QUIT 信号以排空并退出 NGINX_PID=$(cat /var/opt/gitlab/nginx/nginx.pid) kill -QUIT $NGINX_PID # 等待排空完成 while kill -0 $NGINX_PID 2>/dev/null; do sleep 1; done # 停止 NGINX 服务以防止自动重启 gitlab-ctl stop nginx -
在
/etc/gitlab/skip-auto-reconfigure创建一个空文件。这可以防止升级运行gitlab-ctl reconfigure,该命令默认会自动停止 GitLab,运行所有数据库迁移,然后重新启动 GitLab:sudo touch /etc/gitlab/skip-auto-reconfigure -
通过在
/etc/gitlab/gitlab.rb配置文件中设置gitlab_rails['auto_migrate'] = true来配置运行常规迁移。- 如果部署节点当前通过 PgBouncer 连接到数据库,则必须在运行迁移前绕过它并直接连接到数据库主节点。
- 要查找数据库主节点,您可以在任何数据库节点上运行以下命令 -
sudo gitlab-ctl patroni members。
-
运行常规迁移并获取最新代码:
sudo SKIP_POST_DEPLOYMENT_MIGRATIONS=true gitlab-ctl reconfigure -
暂时保持此节点不变,稍后您将回来运行部署后迁移。
-
-
在每个 其他 Rails 节点上依次:
-
平滑排空节点流量。您可以通过多种方式实现,但一种方法是使用 NGINX,向其发送
QUIT信号,然后停止服务。例如,您可以使用以下 shell 脚本:# 向 NGINX 主进程发送 QUIT 信号以排空并退出 NGINX_PID=$(cat /var/opt/gitlab/nginx/nginx.pid) kill -QUIT $NGINX_PID # 等待排空完成 while kill -0 $NGINX_PID 2>/dev/null; do sleep 1; done # 停止 NGINX 服务以防止自动重启 gitlab-ctl stop nginx -
在
/etc/gitlab/skip-auto-reconfigure创建一个空文件。这可以防止升级运行gitlab-ctl reconfigure,该命令默认会自动停止 GitLab,运行所有数据库迁移,然后重新启动 GitLab:sudo touch /etc/gitlab/skip-auto-reconfigure -
确保
/etc/gitlab/gitlab.rb中设置了gitlab_rails['auto_migrate'] = false,以防止reconfigure自动运行数据库迁移。 -
运行
reconfigure命令以获取最新代码并重启:sudo gitlab-ctl reconfigure sudo gitlab-ctl restart
-
-
在 Rails 部署节点上运行部署后迁移:
-
确保部署节点仍然直接指向数据库主节点。如果节点当前通过 PgBouncer 连接到数据库,则必须在运行迁移前绕过它并直接连接到数据库主节点。
- 要查找数据库主节点,您可以在任何数据库节点上运行以下命令 -
sudo gitlab-ctl patroni members。
- 要查找数据库主节点,您可以在任何数据库节点上运行以下命令 -
-
运行部署后迁移:
sudo gitlab-rake db:migrate -
通过在
/etc/gitlab/gitlab.rb配置文件中设置gitlab_rails['auto_migrate'] = false来恢复配置。- 如果使用 PgBouncer,确保将数据库配置再次指向它
-
再次运行 reconfigure 以重新应用正常配置并重启:
sudo gitlab-ctl reconfigure sudo gitlab-ctl restart
-
Sidekiq
Sidekiq 在零停机升级时遵循与其他组件相同的基本流程。
在每个组件节点上依次运行以下步骤来执行升级:
-
在
/etc/gitlab/skip-auto-reconfigure创建一个空文件。这可以防止升级运行gitlab-ctl reconfigure,该命令默认会自动停止 GitLab,运行所有数据库迁移,然后重新启动 GitLab:sudo touch /etc/gitlab/skip-auto-reconfigure -
运行
reconfigure命令以获取最新代码并重启:sudo gitlab-ctl reconfigure sudo gitlab-ctl restart
带 Geo 的多节点/高可用部署
- Tier: Premium, Ultimate
- Offering: GitLab Self-Managed
本节描述了升级带有 Geo 的正在运行的 GitLab 环境所需的步骤。
总体而言,方法与正常过程基本相同,但每个次要站点需要一些额外步骤。必需的顺序是先升级主站点,然后升级次要站点。您还必须在所有次要站点更新后,在主站点上运行任何部署后迁移。
相同的 要求和注意事项 适用于升级带有 Geo 的正在运行的 GitLab 环境。
主站点
主站点的升级过程与正常过程相同,不同之处在于在所有次要站点更新之前不要运行部署后迁移。
运行与主站点相同的步骤,但在 Rails 节点步骤中停止在运行部署后迁移。
次要站点
任何次要站点的升级过程与正常过程相同,除了 Rails 节点。主站点和次要站点的升级过程相同。但是,您必须对次要站点上的 Rails 节点执行以下额外步骤。
Rails
-
在 Rails 部署节点上:
-
平滑排空节点流量。您可以通过多种方式实现,但一种方法是使用 NGINX,向其发送
QUIT信号,然后停止服务。例如,您可以使用以下 shell 脚本:# 向 NGINX 主进程发送 QUIT 信号以排空并退出 NGINX_PID=$(cat /var/opt/gitlab/nginx/nginx.pid) kill -QUIT $NGINX_PID # 等待排空完成 while kill -0 $NGINX_PID 2>/dev/null; do sleep 1; done # 停止 NGINX 服务以防止自动重启 gitlab-ctl stop nginx -
停止 Geo 日志游标进程以确保它故障转移到另一个节点:
gitlab-ctl stop geo-logcursor -
在
/etc/gitlab/skip-auto-reconfigure创建一个空文件。这可以防止升级运行gitlab-ctl reconfigure,该命令默认会自动停止 GitLab,运行所有数据库迁移,然后重新启动 GitLab:sudo touch /etc/gitlab/skip-auto-reconfigure -
如果主站点 Rails 节点和次要站点 Rails 节点的
/etc/gitlab/gitlab-secrets.json文件不同,请将其从主站点复制到次要站点。站点的所有节点上的文件必须相同。 -
确保
/etc/gitlab/gitlab.rb配置文件中设置了gitlab_rails['auto_migrate'] = false和geo_secondary['auto_migrate'] = false,以防止配置自动运行迁移。 -
运行
reconfigure命令以获取最新代码并重启:sudo gitlab-ctl reconfigure sudo gitlab-ctl restart -
运行常规 Geo 追踪迁移并获取最新代码:
sudo SKIP_POST_DEPLOYMENT_MIGRATIONS=true gitlab-rake db:migrate:geo
-
-
在每个 其他 Rails 节点上依次:
-
平滑排空节点流量。您可以通过多种方式实现,但一种方法是使用 NGINX,向其发送
QUIT信号,然后停止服务。例如,您可以使用以下 shell 脚本:# 向 NGINX 主进程发送 QUIT 信号以排空并退出 NGINX_PID=$(cat /var/opt/gitlab/nginx/nginx.pid) kill -QUIT $NGINX_PID # 等待排空完成 while kill -0 $NGINX_PID 2>/dev/null; do sleep 1; done # 停止 NGINX 服务以防止自动重启 gitlab-ctl stop nginx -
停止 Geo 日志游标进程以确保它故障转移到另一个节点:
gitlab-ctl stop geo-logcursor -
在
/etc/gitlab/skip-auto-reconfigure创建一个空文件。这可以防止升级运行gitlab-ctl reconfigure,该命令默认会自动停止 GitLab,运行所有数据库迁移,然后重新启动 GitLab:sudo touch /etc/gitlab/skip-auto-reconfigure -
确保
/etc/gitlab/gitlab.rb配置文件中设置了gitlab_rails['auto_migrate'] = false和geo_secondary['auto_migrate'] = false,以防止配置自动运行迁移。 -
运行
reconfigure命令以获取最新代码并重启:sudo gitlab-ctl reconfigure sudo gitlab-ctl restart
-
Sidekiq
遵循主过程,剩下的就是升级 Sidekiq。
以主部分中描述的相同方式升级 Sidekiq。
部署后迁移
最后,返回主站点,通过运行部署后迁移来完成升级:
-
在主站点的 Rails 部署节点上运行部署后迁移:
-
确保部署节点仍然直接指向数据库主节点。如果节点当前通过 PgBouncer 连接到数据库,则必须在运行迁移前绕过它并直接连接到数据库主节点。
- 要查找数据库主节点,您可以在任何数据库节点上运行以下命令 -
sudo gitlab-ctl patroni members。
- 要查找数据库主节点,您可以在任何数据库节点上运行以下命令 -
-
运行部署后迁移:
sudo gitlab-rake db:migrate -
验证 Geo 配置和依赖项
sudo gitlab-rake gitlab:geo:check -
通过在
/etc/gitlab/gitlab.rb配置文件中设置gitlab_rails['auto_migrate'] = false来恢复配置。- 如果使用 PgBouncer,确保将数据库配置再次指向它
-
再次运行 reconfigure 以重新应用正常配置并重启:
sudo gitlab-ctl reconfigure sudo gitlab-ctl restart
-
-
在次要站点的 Rails 部署节点上运行部署后 Geo 追踪迁移:
-
运行部署后 Geo 追踪迁移:
sudo gitlab-rake db:migrate:geo -
验证 Geo 状态:
sudo gitlab-rake geo:status
-