Help us learn about your current experience with the documentation. Take the survey.

配置 Gitaly 集群(Praefect)

使用以下方式之一配置 Gitaly 集群(Praefect):

较小的 GitLab 安装可能只需要 Gitaly 本身

Gitaly 集群(Praefect)目前不支持在 Kubernetes、Amazon ECS 或类似的容器环境中运行。有关更多信息,请参见 epic 6127

要求

Gitaly 集群(Praefect)的最小推荐配置要求如下:

  • 1 个负载均衡器
  • 1 个 PostgreSQL 服务器(支持的版本
  • 3 个 Praefect 节点
  • 3 个 Gitaly 节点(1 个主节点,2 个次节点)

您应该配置奇数个 Gitaly 节点,这样在其中一个 Gitaly 节点发生变更型 RPC 调用时失败的情况下,事务可以有决胜者。

有关实现细节,请参见 设计文档

如果在 GitLab 中未设置,控制台会将功能标志读取为 false,Praefect 会使用其默认值。默认值取决于 GitLab 版本。

网络延迟与连通性

Gitaly 集群(Praefect)的网络延迟理想情况下应能以个位数毫秒衡量。延迟对以下方面尤其重要:

  • Gitaly 节点健康检查。节点必须在 1 秒内响应。
  • 强制执行 强一致性 的引用事务。较低的延迟意味着 Gitaly 节点可以更快地就更改达成一致。

实现可接受的 Gitaly 节点间延迟:

  • 在物理网络上通常意味着高带宽、单一位置连接。
  • 在云端通常意味着同一区域内,包括允许跨可用区复制。这些链路专为这种同步类型设计。对于 Gitaly 集群(Praefect),少于 2 毫秒的延迟应该足够了。

如果您无法为复制提供低网络延迟(例如,在不同地理位置之间),请考虑 Geo。有关更多信息,请参见 与 Geo 的比较

Gitaly 集群(Praefect)组件 通过多种路由相互通信。您的防火墙规则必须允许以下流量,才能使 Gitaly 集群(Praefect)正常工作:

来源 目标 默认端口 TLS 端口
GitLab Praefect 负载均衡器 2305 3305
Praefect 负载均衡器 Praefect 2305 3305
Praefect Gitaly 8075 9999
Praefect GitLab(内部 API) 80 443
Gitaly GitLab(内部 API) 80 443
Gitaly Praefect 负载均衡器 2305 3305
Gitaly Praefect 2305 3305
Gitaly Gitaly 8075 9999

Gitaly 不会直接连接到 Praefect。但是,来自 Gitaly 到 Praefect 负载均衡器的请求仍可能被阻止,除非 Praefect 节点上的防火墙允许来自 Gitaly 节点的流量。

Praefect 数据库存储

需求相对较低,因为数据库仅包含元数据,包括:仓库的位置、一些排队的工作。这取决于仓库的数量,但一个良好的最小值是 5-10 GB,类似于主 GitLab 应用程序数据库。

设置说明

如果你通过 安装 GitLab 使用了 Linux 包(强烈推荐),请按照以下步骤操作:

  1. 准备
  2. 配置 Praefect 数据库
  3. 配置 Praefect 代理/路由器
  4. 配置每个 Gitaly 节点(每个 Gitaly 节点执行一次)
  5. 配置负载均衡器
  6. 更新 GitLab 服务器配置
  7. 配置 Grafana

准备

开始之前,你应该已经有一个可用的 GitLab 实例。了解如何安装 GitLab

provision 一个 PostgreSQL 服务器。你应该使用随 Linux 包提供的 PostgreSQL,并使用它来配置 PostgreSQL 数据库。你可以使用外部 PostgreSQL 服务器,但你必须手动设置它 #手动数据库设置

通过 安装 GitLab 为所有新节点做准备。你需要:

  • 1 个 PostgreSQL 节点
  • 1 个 PgBouncer 节点(可选)
  • 至少 1 个 Praefect 节点(需最小存储空间)
  • 3 个 Gitaly 节点(高 CPU、大内存、快速存储)
  • 1 个 GitLab 服务器

你还需要每个节点的 IP/主机地址:

  1. PRAEFECT_LOADBALANCER_HOST:Praefect 负载均衡器的 IP/主机地址
  2. POSTGRESQL_HOST:PostgreSQL 服务器的 IP/主机地址
  3. PGBOUNCER_HOST:PgBouncer 节点的 IP/主机地址
  4. PRAEFECT_HOST:Praefect 服务器的 IP/主机地址
  5. GITALY_HOST_*:每个 Gitaly 服务器的 IP 或主机地址
  6. GITLAB_HOST:GitLab 服务器的 IP/主机地址

如果你使用 Google Cloud Platform、SoftLayer 或其他提供虚拟私有云(VPC)的供应商,你可以对每个云实例使用私有地址(对应 Google Cloud Platform 的“内部地址”)作为 PRAEFECT_HOSTGITALY_HOST_*GITLAB_HOST

密钥

组件之间的通信通过不同的密钥 securing,如下所述。开始前,为每个密钥生成一个唯一密钥,并记录下来。这样你就可以在完成设置过程中将这些占位符替换为安全令牌。

  1. GITLAB_SHELL_SECRET_TOKEN:此密钥由 Git 钩子使用,当接受 Git 推送时向 GitLab 发出回调 HTTP API 请求。由于历史原因,此密钥与 GitLab Shell 共享。
  2. PRAEFECT_EXTERNAL_TOKEN:托管在 Praefect 集群上的仓库只能被携带此令牌的 Gitaly 客户端访问。
  3. PRAEFECT_INTERNAL_TOKEN:此令牌用于 Praefect 集群内的复制流量。此令牌与 PRAEFECT_EXTERNAL_TOKEN 不同,因为 Gitaly 客户端不能直接访问 Praefect 集群的内部节点;这可能导致数据丢失。
  4. PRAEFECT_SQL_PASSWORD:此密码用于 Praefect 连接到 PostgreSQL。
  5. PRAEFECT_SQL_PASSWORD_HASH:Praefect 用户的密码哈希。使用 gitlab-ctl pg-password-md5 praefect 生成哈希。该命令会要求输入 praefect 用户的密码。输入 PRAEFECT_SQL_PASSWORD 的明文密码。默认情况下,Praefect 使用 praefect 用户,但你可以更改它。
  6. PGBOUNCER_SQL_PASSWORD_HASH:PgBouncer 用户的密码哈希。PgBouncer 使用此密码连接到 PostgreSQL。更多细节请参见 捆绑的 PgBouncer 文档。

我们在下文的说明中指出这些密钥在哪里需要用到。

Linux 包安装可以使用 gitlab-secrets.json 来配置 GITLAB_SHELL_SECRET_TOKEN

自定义时间服务器设置

默认情况下,Gitaly 和 Praefect 节点使用位于 pool.ntp.org 的时间服务器进行时间同步检查。你可以通过在每个节点的 gitlab.rb 中添加以下内容来自定义此设置:

  • gitaly['env'] = { "NTP_HOST" => "ntp.example.com" },适用于 Gitaly 节点。
  • praefect['env'] = { "NTP_HOST" => "ntp.example.com" },适用于 Praefect 节点。

PostgreSQL

如果使用 Geo,请不要将 GitLab 应用数据库和 Praefect 数据库存储在同一台 PostgreSQL 服务器上。复制状态是每个 GitLab 实例内部的,不应被复制。

这些说明帮助设置单个 PostgreSQL 数据库,这会创建单点故障。为了避免这种情况,您可以配置自己的集群化 PostgreSQL。

其他数据库(例如 Praefect 和 Geo 数据库)的集群数据库支持已在 issue 7292 中提出。

以下选项可用:

设置 PostgreSQL 会创建空的 Praefect 表。有关更多信息,请参阅 相关故障排除部分

在同一服务器上运行 GitLab 和 Praefect 数据库

GitLab 应用数据库和 Praefect 数据库可以在同一台服务器上运行。但是,当使用 Linux 包提供的 PostgreSQL 时,Praefect 应该有自己的数据库服务器。如果有故障转移,Praefect 无法感知并开始失败,因为它尝试使用的数据库可能会:

  • 不可用。
  • 处于只读模式。

手动数据库设置

要完成本节,您需要:

  • 一个 Praefect 节点
  • 一个 PostgreSQL 节点
    • 具有管理数据库服务器权限的 PostgreSQL 用户

在本节中,我们配置 PostgreSQL 数据库。此操作可用于外部和 Linux 包提供的 PostgreSQL 服务器。

要运行以下指令,您可以使用 Praefect 节点,其中 psql 由 Linux 包安装(/opt/gitlab/embedded/bin/psql)。如果您使用的是 Linux 包提供的 PostgreSQL,则可以在 PostgreSQL 节点上改用 gitlab-psql

  1. 创建新用户 praefect 以供 Praefect 使用:

    CREATE ROLE praefect WITH LOGIN PASSWORD 'PRAEFECT_SQL_PASSWORD';

    PRAEFECT_SQL_PASSWORD 替换为您在准备步骤中生成的强密码。

  2. 创建由 praefect 用户拥有的新数据库 praefect_production

    CREATE DATABASE praefect_production WITH OWNER praefect ENCODING UTF8;

当使用 Linux 包提供的 PgBouncer 时,您需要执行以下额外步骤。我们强烈建议使用随 Linux 包一起提供的 PostgreSQL 作为后端。以下指令仅适用于 Linux 包提供的 PostgreSQL:

  1. 对于 Linux 包提供的 PgBouncer,您需要使用 praefect 密码的哈希值而不是实际密码:

    ALTER ROLE praefect WITH PASSWORD 'md5<PRAEFECT_SQL_PASSWORD_HASH>';

    <PRAEFECT_SQL_PASSWORD_HASH> 替换为您在准备步骤中生成的密码哈希值。它以 md5 字面量作为前缀。

  2. 创建新用户 pgbouncer 以供 PgBouncer 使用:

    CREATE ROLE pgbouncer WITH LOGIN;
    ALTER USER pgbouncer WITH password 'md5<PGBOUNCER_SQL_PASSWORD_HASH>';

    PGBOUNCER_SQL_PASSWORD_HASH 替换为您在准备步骤中生成的强密码哈希值。

  3. 随 Linux 包一起提供的 PgBouncer 配置为使用 auth_query 并使用 pg_shadow_lookup 函数。您需要在 praefect_production 数据库中创建此函数:

    CREATE OR REPLACE FUNCTION public.pg_shadow_lookup(in i_username text, out username text, out password text) RETURNS record AS $$
    BEGIN
        SELECT usename, passwd FROM pg_catalog.pg_shadow
        WHERE usename = i_username INTO username, password;
        RETURN;
    END;
    $$ LANGUAGE plpgsql SECURITY DEFINER;
    
    REVOKE ALL ON FUNCTION public.pg_shadow_lookup(text) FROM public, pgbouncer;
    GRANT EXECUTE ON FUNCTION public.pg_shadow_lookup(text) TO pgbouncer;

Praefect 使用的数据库现已配置完毕。

现在可以配置 Praefect 使用该数据库:

praefect['configuration'] = {
   # ...
   database: {
      # ...
      host: POSTGRESQL_HOST,
      user: 'praefect',
      port: 5432,
      password: PRAEFECT_SQL_PASSWORD,
      dbname: 'praefect_production',
   }
}

如果在配置 PostgreSQL 后看到 Praefect 数据库错误,请参阅 故障排除步骤

读取分发缓存

通过额外配置 session_pooled 设置,可以提升 Praefect 的性能:

praefect['configuration'] = {
   # ...
   database: {
      # ...
      session_pooled: {
         # ...
         host: POSTGRESQL_HOST,
         port: 5432

         # 使用以下参数覆盖直接数据库连接的参数。
         # 若两个连接的参数相同,请将其注释掉。
         user: 'praefect',
         password: PRAEFECT_SQL_PASSWORD,
         dbname: 'praefect_production',
         # sslmode: '...',
         # sslcert: '...',
         # sslkey: '...',
         # sslrootcert: '...',
      }
   }
}

配置后,该连接会自动用于 SQL LISTEN 功能,允许 Praefect 接收来自 PostgreSQL 的缓存失效通知。

通过在 Praefect 日志中查找以下日志条目,验证此功能是否正常工作:

reads distribution caching is enabled by configuration

使用 PgBouncer

为了降低 PostgreSQL 资源消耗,你应在 PostgreSQL 实例前设置并配置 PgBouncer。然而,由于 Praefect 建立的连接数量较少,因此无需使用 PgBouncer。如果选择使用 PgBouncer,可为 GitLab 应用数据库和 Praefect 数据库使用同一个 PgBouncer 实例。

若要在 PostgreSQL 实例前配置 PgBouncer,需通过设置 Praefect 配置中的数据库参数,将 Praefect 指向 PgBouncer:

praefect['configuration'] = {
   # ...
   database: {
      # ...
      host: PGBOUNCER_HOST,
      port: 6432,
      user: 'praefect',
      password: PRAEFECT_SQL_PASSWORD,
      dbname: 'praefect_production',
      # sslmode: '...',
      # sslcert: '...',
      # sslkey: '...',
      # sslrootcert: '...',
   }
}

Praefect 需要一个额外的 PostgreSQL 连接来支持 LISTEN 功能。在使用 PgBouncer 时,仅当 pool_mode = session 时此功能才可用;在 pool_mode = transaction 模式下不受支持。

若要配置额外的连接,必须执行以下操作之一:

  • 配置一个新的 PgBouncer 数据库,该数据库指向相同的 PostgreSQL 数据库端点,但使用不同的池模式(pool_mode = session)。
  • 直接将 Praefect 连接到 PostgreSQL,绕过 PgBouncer。
配置新的 PgBouncer 数据库,使用 pool_mode = session

应使用 session 池模式的 PgBouncer。你可使用 捆绑的 PgBouncer,或使用外部 PgBouncer 并 手动配置

以下示例使用了捆绑的 PgBouncer,并在 PostgreSQL 主机上设置了两个独立的连接池,一个采用 session 池模式,另一个采用 transaction 池模式。要使本示例生效,需按照 设置说明 准备 PostgreSQL 服务器。

然后在 PgBouncer 主机上配置独立的连接池:

pgbouncer['databases'] = {
  # 其他数据库配置,包括 gitlabhq_production
  ...

  praefect_production: {
    host: POSTGRESQL_HOST,
    # 使用 `pgbouncer` 用户连接到数据库后端。
    user: 'pgbouncer',
    password: PGBOUNCER_SQL_PASSWORD_HASH,
    pool_mode: 'transaction'
  },
  praefect_production_direct: {
    host: POSTGRESQL_HOST,
    # 使用 `pgbouncer` 用户连接到数据库后端。
    user: 'pgbouncer',
    password: PGBOUNCER_SQL_PASSWORD_HASH,
    dbname: 'praefect_production',
    pool_mode: 'session'
  },

  ...
}

允许 praefect 用户连接到 PgBouncer

pgbouncer[‘users’] = { ‘praefect’: { ‘password’: PRAEFECT_SQL_PASSWORD_HASH, } }


`praefect_production` 和 `praefect_production_direct` 使用相同的数据库端点(`praefect_production`),但池模式不同。这对应于 PgBouncer 的以下 `databases` 部分:

```ini
[databases]
praefect_production = host=POSTGRESQL_HOST auth_user=pgbouncer pool_mode=transaction
praefect_production_direct = host=POSTGRESQL_HOST auth_user=pgbouncer dbname=praefect_production pool_mode=session

现在你可以配置 Praefect 同时使用 PgBouncer 进行两种连接:

praefect['configuration'] = {
   # ...
   database: {
      # ...
      host: PGBOUNCER_HOST,
      port: 6432,
      user: 'praefect',
      # `PRAEFECT_SQL_PASSWORD` 是 Praefect 用户的明文密码。
      # 不要与 `PRAEFECT_SQL_PASSWORD_HASH` 混淆。
      password: PRAEFECT_SQL_PASSWORD,
      dbname: 'praefect_production',
      session_pooled: {
         # ...
         dbname: 'praefect_production_direct',
         # 无需重复以下内容。直接数据库连接的参数会回退到
         # database 块中指定的值。
         #
         # host: PGBOUNCER_HOST,
         # port: 6432,
         # user: 'praefect',
         # password: PRAEFECT_SQL_PASSWORD,
      },
   },
}

通过此配置,Praefect 对两种连接类型均使用 PgBouncer。

Linux 包安装会处理认证要求(使用 auth_query),但如果手动准备数据库并配置外部 PgBouncer,则必须在 PgBouncer 使用的文件中包含 praefect 用户及其密码。例如,如果设置了 auth_file 配置选项,则为 userlist.txt。更多详情请参阅 PgBouncer 文档。

配置 Praefect 直接连接到 PostgreSQL

作为配置 PgBouncer 使用 session 池模式的替代方案,Praefect 可以配置为使用不同的连接参数直接访问 PostgreSQL。此连接支持 LISTEN 功能。

以下是绕过 PgBouncer 并直接连接到 PostgreSQL 的 Praefect 配置示例:

praefect['configuration'] = {
   # ...
   database: {
      # ...
      session_pooled: {
         # ...
         host: POSTGRESQL_HOST,
         port: 5432,

         # 使用以下内容覆盖直接数据库连接的参数。
         # 如果两个连接的参数相同,请注释掉相应行。
         #
         user: 'praefect',
         password: PRAEFECT_SQL_PASSWORD,
         dbname: 'praefect_production',
         # sslmode: '...',
         # sslcert: '...',
         # sslkey: '...',
         # sslrootcert: '...',
      },
   },
}

Praefect

在配置Praefect前,请参考示例Praefect配置文件熟悉相关内容。若通过Linux包安装GitLab,示例文件中的设置需转换为Ruby。

若有多个Praefect节点:

  1. 指定一个节点作为部署节点,按以下步骤配置。
  2. 为每个额外节点完成以下步骤。

完成此部分需具备已配置的PostgreSQL服务器,包含:

Praefect应在专用节点上运行。勿在应用服务器或Gitaly节点上运行Praefect。

在Praefect节点上:

  1. 编辑/etc/gitlab/gitlab.rb禁用所有其他服务:
# 避免在Praefect服务器运行多余服务
gitaly['enable'] = false
postgresql['enable'] = false
redis['enable'] = false
nginx['enable'] = false
puma['enable'] = false
sidekiq['enable'] = false
gitlab_workhorse['enable'] = false
prometheus['enable'] = false
alertmanager['enable'] = false
gitlab_exporter['enable'] = false
gitlab_kas['enable'] = false

# 仅启用Praefect服务
praefect['enable'] = true

# 防止升级时自动运行数据库迁移
praefect['auto_migrate'] = false
gitlab_rails['auto_migrate'] = false
  1. 编辑/etc/gitlab/gitlab.rb配置Praefect监听网络接口:

    praefect['configuration'] = {
       # ...
       listen_addr: '0.0.0.0:2305',
    }
  2. 编辑/etc/gitlab/gitlab.rb配置Prometheus指标:

    praefect['configuration'] = {
       # ...
       #
       # 启用Prometheus指标访问Praefect。需用防火墙限制此地址/端口访问。
       # 默认指标端点为/metrics
       prometheus_listen_addr: '0.0.0.0:9652',
       # 部分指标会查询数据库。开启独立数据库指标后,
       # 这些指标可在单独的/db_metrics端点被采集时收集。
       prometheus_exclude_database_from_default_metrics: true,
    }
  3. 编辑/etc/gitlab/gitlab.rb配置Praefect强认证令牌,集群外客户端(如GitLab Shell)需此令牌与Praefect集群通信:

    praefect['configuration'] = {
       # ...
       auth: {
          # ...
          token: 'PRAEFECT_EXTERNAL_TOKEN',
       },
    }
  4. 配置Praefect以连接PostgreSQL数据库。强烈建议同时使用PgBouncer

    若需使用TLS客户端证书,可选用以下选项:

    praefect['configuration'] = {
       # ...
       database: {
          # ...
          #
          # 用TLS客户端证书连接PostgreSQL
          # sslcert: '/path/to/client-cert',
          # sslkey: '/path/to/client-key',
          #
          # 信任自定义CA证书
          # sslrootcert: '/path/to/rootcert',
       },
    }

    默认情况下,Praefect采用Opportunistic TLS连接PostgreSQL,即尝试以sslmode=prefer方式连接。可通过取消注释以下行覆盖:

    praefect['configuration'] = {
       # ...
       database: {
          # ...
          # sslmode: 'disable',
       },
    }
  5. 编辑/etc/gitlab/gitlab.rb配置Praefect集群连接集群内各Gitaly节点。

    虚拟存储名需与GitLab配置的存储名一致。后续步骤中将存储名设为default,故此处也用default。该集群含三个Gitaly节点gitaly-1gitaly-2gitaly-3,旨在互为副本。

    若已有名为default的现存存储数据,需用其他名称配置虚拟存储,随后将数据迁移至Gitaly集群(Praefect)存储

    PRAEFECT_INTERNAL_TOKEN替换为强密钥,Praefect与集群内Gitaly节点通信时使用此密钥。该密钥与PRAEFECT_EXTERNAL_TOKEN不同。

    GITALY_HOST_*替换为各Gitaly节点的IP或主机地址。

    可向集群添加更多Gitaly节点以扩容。

replicas. 对于非常大的 GitLab 实例,还可以添加更多集群。

当向虚拟存储中添加额外的 Gitaly 节点时,该虚拟存储中的所有存储名称必须唯一。此外,Praefect 配置中引用的所有 Gitaly 节点地址也必须唯一。

# 存储哈希的名称必须与 GitLab 服务器上 gitlab_rails['repositories_storages'] 中的存储名称('default')
# 以及 Gitaly 节点上 gitaly['configuration'][:storage][INDEX][:name] 中的名称('gitaly-1')匹配
praefect['configuration'] = {
   # ...
   virtual_storage: [
      {
         # ...
         name: 'default',
         node: [
            {
               storage: 'gitaly-1',
               address: 'tcp://GITALY_HOST_1:8075',
               token: 'PRAEFECT_INTERNAL_TOKEN'
            },
            {
               storage: 'gitaly-2',
               address: 'tcp://GITALY_HOST_2:8075',
               token: 'PRAEFECT_INTERNAL_TOKEN'
            },
            {
               storage: 'gitaly-3',
               address: 'tcp://GITALY_HOST_3:8075',
               token: 'PRAEFECT_INTERNAL_TOKEN'
            },
         ],
      },
   ],
}
  1. 将更改保存到 /etc/gitlab/gitlab.rb重新配置 Praefect

    gitlab-ctl reconfigure
  2. 对于:

    • “部署节点”:

      1. 通过在 /etc/gitlab/gitlab.rb 中设置 praefect['auto_migrate'] = true 来再次启用 Praefect 数据库自动迁移。

      2. 为确保数据库迁移仅在重新配置期间运行,而不是在升级时自动运行,请执行:

        sudo touch /etc/gitlab/skip-auto-reconfigure
    • 其他节点可以保留当前设置。虽然 /etc/gitlab/skip-auto-reconfigure 不是必需的,但您可能希望设置它以防止 GitLab 在运行诸如 apt-get update 之类的命令时自动重新配置。这样任何额外的配置更改都可以完成,然后手动运行重新配置。

  3. 将更改保存到 /etc/gitlab/gitlab.rb重新配置 Praefect

    gitlab-ctl reconfigure
  4. 为确保 Praefect 已更新其 Prometheus 监听地址(https://gitlab.com/gitlab-org/gitaly/-/issues/2734),请重启 Praefect (../../restart_gitlab.md#reconfigure-a-linux-package-installation):

    gitlab-ctl restart praefect
  5. 验证 Praefect 能否连接到 PostgreSQL:

    sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml sql-ping

    如果检查失败,请确保您已正确遵循步骤。如果您编辑了 /etc/gitlab/gitlab.rb,请在尝试 sql-ping 命令之前再次运行 sudo gitlab-ctl reconfigure

启用TLS支持

Praefect 支持TLS加密。若要与监听安全连接的Praefect实例通信,您必须:

  • 确保 Gitaly 已配置TLS,并在 GitLab 配置中相应存储条目的 gitaly_address 中使用 tls:// URL 方案。
  • 自行提供证书,因为系统不会自动生成。每个Praefect服务器的证书必须安装在对应服务器上。

此外,证书或其证书颁发机构必须安装在所有 Gitaly 服务器及与Praefect通信的所有客户端上,具体操作请遵循GitLab 自定义证书配置(下方重复说明)。

请注意以下几点:

  • 证书必须指定访问Praefect服务器的地址。您必须在证书中添加主机名或IP地址作为主题备用名称(SAN)。

  • 当通过命令行运行 dial-nodeslist-untracked-repositories 等Praefect子命令且Gitaly TLS已启用时,必须设置 SSL_CERT_DIRSSL_CERT_FILE 环境变量以信任Gitaly证书。例如:

    SSL_CERT_DIR=/etc/gitlab/trusted-certs sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dial-nodes
  • 您可以同时为Praefect服务器配置未加密的监听地址 listen_addr 和加密的监听地址 tls_listen_addr。这允许必要时逐步从未加密流量过渡到加密流量。

    若要禁用未加密监听器,请设置:

    praefect['configuration'] = {
      # ...
      listen_addr: nil,
    }

配置Praefect启用TLS。

对于Linux软件包安装:

  1. 为Praefect服务器创建证书。

  2. 在Praefect服务器上,创建 /etc/gitlab/ssl 目录并将密钥和证书复制至此处:

    sudo mkdir -p /etc/gitlab/ssl
    sudo chmod 755 /etc/gitlab/ssl
    sudo cp key.pem cert.pem /etc/gitlab/ssl/
    sudo chmod 644 key.pem cert.pem
  3. 编辑 /etc/gitlab/gitlab.rb 并添加:

    praefect['configuration'] = {
       # ...
       tls_listen_addr: '0.0.0.0:3305',
       tls: {
          # ...
          certificate_path: '/etc/gitlab/ssl/cert.pem',
          key_path: '/etc/gitlab/ssl/key.pem',
       },
    }
  4. 保存文件并执行重新配置

  5. 在Praefect客户端(包括各Gitaly服务器),将证书或其证书颁发机构复制至 /etc/gitlab/trusted-certs

    sudo cp cert.pem /etc/gitlab/trusted-certs/
  6. 在Praefect客户端(除Gitaly服务器外),编辑 /etc/gitlab/gitlab.rb 中的 gitlab_rails['repositories_storages'] 如下:

    gitlab_rails['repositories_storages'] = {
      "default" => {
        "gitaly_address" => 'tls://PRAEFECT_LOADBALANCER_HOST:3305',
        "gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
      }
    }
  7. 保存文件并执行重新配置GitLab

对于自编译安装:

  1. 为Praefect服务器创建证书。

  2. 在Praefect服务器上,创建 /etc/gitlab/ssl 目录并将密钥和证书复制至此处:

    sudo mkdir -p /etc/gitlab/ssl
    sudo chmod 755 /etc/gitlab/ssl
    sudo cp key.pem cert.pem /etc/gitlab/ssl/
    sudo chmod 644 key.pem cert.pem
  3. 在Praefect客户端(包括各Gitaly服务器),将证书或其证书颁发机构复制至系统受信证书:

    sudo cp cert.pem /usr/local/share/ca-certificates/praefect.crt
    sudo update-ca-certificates
  4. 在Praefect客户端(除Gitaly服务器外),编辑 /home/git/gitlab/config/gitlab.yml 中的 storages 如下:

    gitlab:
      repositories:
        storages:
          default:
            gitaly_address: tls://PRAEFECT_LOADBALANCER_HOST:3305
  5. 保存文件并执行重启GitLab

  6. 将所有Praefect服务器证书或其证书颁发机构复制至各Gitaly服务器的系统受信证书,使Praefect服务器在被Gitaly调用时信任该证书:

    sudo cp cert.pem /usr/local/share/ca-certificates/praefect.crt
    sudo update-ca-certificates
  7. 编辑 /home/git/praefect/config.toml 并添加:

    tls_listen_addr = '0.0.0.0:3305'
    
    [tls]
    certificate_path = '/etc/gitlab/ssl/cert.pem'
    key_path = '/etc/gitlab/ssl/key.pem'
  8. 保存文件并执行重启GitLab

服务发现

前提条件:

  • 一个DNS服务器。

GitLab使用服务发现来获取Praefect主机的列表。服务发现涉及对DNS的A或AAAA记录进行周期性检查,从记录中检索到的IP地址作为目标节点的地址。Praefect不支持通过SRV记录进行服务发现。

默认情况下,两次检查之间的最短时间是5分钟,无论记录的TTL是多少。Praefect不支持自定义此间隔。当客户端收到更新时,它们会:

  • 建立与新IP地址的连接。
  • 保持与完整IP地址的现有连接。
  • 断开已移除IP地址的连接。

正在进行的、即将被移除的连接上的请求仍会被处理,直到它们完成。Workhorse有一个10分钟的 timeout,而其他客户端则未指定优雅的 timeout。

DNS服务器应返回所有IP地址,而不是自行进行负载均衡。客户端可以以轮询方式向这些IP地址分发请求。

在更新客户端配置之前,请确保DNS服务发现能正常工作。它应正确返回IP地址列表。dig 是用于验证的好工具。

❯ dig A praefect.service.consul @127.0.0.1

; <<>> DiG 9.10.6 <<>> A praefect.service.consul @127.0.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29210
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;praefect.service.consul.                     IN      A

;; ANSWER SECTION:
praefect.service.consul.              0       IN      A       10.0.0.3
praefect.service.consul.              0       IN      A       10.0.0.2
praefect.service.consul.              0       IN      A       10.0.0.1

;; Query time: 0 msec
;; SERVER: ::1#53(::1)
;; WHEN: Wed Dec 14 12:53:58 +07 2022
;; MSG SIZE  rcvd: 86
配置服务发现

默认情况下,Praefect 将 DNS 解析委托给操作系统。在这种情况下,Gitaly 地址可以设置为以下任一格式:

  • dns:[host]:[port]
  • dns:///[host]:[port](注意三个斜杠)

你也可以通过以下格式指定权威名称服务器:

  • dns://[authority_host]:[authority_port]/[host]:[port]
  1. 为每个 Praefect 节点添加 IP 地址到 DNS 服务发现地址中。

  2. 在 Praefect 客户端(除了 Gitaly 服务器)上,编辑 /etc/gitlab/gitlab.rb 中的 gitlab_rails['repositories_storages'] 如下所示。将 PRAEFECT_SERVICE_DISCOVERY_ADDRESS 替换为 Praefect 服务发现地址,例如 praefect.service.consul

    gitlab_rails['repositories_storages'] = {
      "default" => {
        "gitaly_address" => 'dns:PRAEFECT_SERVICE_DISCOVERY_ADDRESS:2305',
        "gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
      }
    }
  3. 保存文件并 重新配置 GitLab

  1. 安装 DNS 服务发现服务。将所有 Praefect 节点注册到该服务中。

  2. 在 Praefect 客户端(除了 Gitaly 服务器)上,编辑 /home/git/gitlab/config/gitlab.yml 中的 storages 如下所示:

    gitlab:
      repositories:
        storages:
          default:
            gitaly_address: dns:PRAEFECT_SERVICE_DISCOVERY_ADDRESS:2305
  3. 保存文件并 重启 GitLab

配置使用Consul的服务发现

如果您的架构中已有Consul服务器,则可以在每个Praefect节点上添加Consul代理并将praefect服务注册到其中。这会将每个节点的IP地址注册到praefect.service.consul,以便通过服务发现找到它。

先决条件:

  • 一个或多个Consul服务器来跟踪Consul代理的状态。
  1. 在每个Praefect服务器上,将以下内容添加到您的/etc/gitlab/gitlab.rb中:

    consul['enable'] = true
    praefect['consul_service_name'] = 'praefect'
    
    # 以下内容也必须添加,直到此问题得到解决:
    # https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/8321
    consul['monitoring_service_discovery'] = true
    praefect['configuration'] = {
      # ...
      #
      prometheus_listen_addr: '0.0.0.0:9652',
    }
  2. 保存文件并重新配置GitLab

  3. 在每个Praefect服务器上重复之前的步骤以用于服务发现。

  4. 在Praefect客户端(除Gitaly服务器外),编辑/etc/gitlab/gitlab.rb中的gitlab_rails['repositories_storages']如下所示。将CONSUL_SERVER替换为Consul服务器的IP或地址。默认的Consul DNS端口是8600

    gitlab_rails['repositories_storages'] = {
      "default" => {
        "gitaly_address" => 'dns://CONSUL_SERVER:8600/praefect.service.consul:2305',
        "gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
      }
    }
  5. 使用Praefect客户端上的dig命令确认每个IP地址已注册到praefect.service.consul,使用dig A praefect.service.consul @CONSUL_SERVER -p 8600。将CONSUL_SERVER替换为之前配置的值,输出中应包含所有Praefect节点的IP地址。

  6. 保存文件并重新配置GitLab

Gitaly

为每个Gitaly节点完成以下步骤。

要完成此部分,您需要:

  • 已配置的Praefect节点
  • 3个(或更多)安装了GitLab的服务器,用于配置为Gitaly节点。这些应为专用节点,不要在这些节点上运行其他服务。

分配给Praefect集群的每个Gitaly服务器都需要进行配置。该配置与标准的独立Gitaly服务器相同,除了:

  • 存储名称暴露给Praefect,而非GitLab
  • 密钥令牌与Praefect共享,而非GitLab

Praefect集群中所有Gitaly节点的配置可以完全相同,因为我们依靠Praefect来正确路由操作。

需特别注意以下几点:

  • 本节中配置的gitaly['configuration'][:auth][:token]必须与Praefect节点上praefect['configuration'][:virtual_storage][<index>][:node][<index>][:token]下的token值匹配。该值已在上一节中设置。本文档始终使用占位符PRAEFECT_INTERNAL_TOKEN
  • 本节中配置的gitaly['configuration'][:storage]中的物理存储名称必须与Praefect节点上praefect['configuration'][:virtual_storage]下的物理存储名称匹配。这已在上一节中设置。本文档使用gitaly-1gitaly-2gitaly-3作为物理存储名称。

有关Gitaly服务器配置的更多信息,请参阅我们的Gitaly文档

  1. 通过SSH连接到Gitaly节点并以root身份登录:

    sudo -i
  2. 通过编辑/etc/gitlab/gitlab.rb禁用所有其他服务:

    # 禁用Gitaly节点上的所有其他服务
    postgresql['enable'] = false
    redis['enable'] = false
    nginx['enable'] = false
    puma['enable'] = false
    sidekiq['enable'] = false
    gitlab_workhorse['enable'] = false
    prometheus_monitoring['enable'] = false
    gitlab_kas['enable'] = false
    
    # 仅启用Gitaly服务
    gitaly['enable'] = true
    
    # 如有需要,启用Prometheus
    prometheus['enable'] = true
    
    # 禁用数据库迁移,防止在'gitlab-ctl reconfigure'期间建立数据库连接
    gitlab_rails['auto_migrate'] = false
  3. 通过编辑/etc/gitlab/gitlab.rb配置Gitaly以监听网络接口:

    gitaly['configuration'] = {
       # ...
       #
       # 使Gitaly接受所有网络接口的连接。
       # 使用防火墙限制对此地址/端口的访问。
       listen_addr: '0.0.0.0:8075',
       # 启用Prometheus对Gitaly指标的访问。您必须使用防火墙
       # 限制对此地址/端口的访问。
       prometheus_listen_addr: '0.0.0.0:9236',
    }
  4. 通过编辑/etc/gitlab/gitlab.rb为Gitaly配置强auth_token,客户端需要此令牌才能与此Gitaly节点通信。通常,所有Gitaly节点的此令牌相同。

    gitaly['configuration'] = {
       # ...
       auth: {
          # ...
          token: 'PRAEFECT_INTERNAL_TOKEN',
       },
    }
  5. 配置GitLab Shell密钥令牌,这是git push操作所需的。有两种方法:

    • 方法1:

      1. /etc/gitlab/gitlab-secrets.json从Gitaly客户端复制到Gitaly服务器及其他Gitaly客户端的同一路径。
      2. 在Gitaly服务器上重新配置GitLab
    • 方法2:

      1. 编辑/etc/gitlab/gitlab.rb
      2. GITLAB_SHELL_SECRET_TOKEN替换为实际密钥。
      • GitLab 17.5及更高版本:

        gitaly['gitlab_secret'] = 'GITLAB_SHELL_SECRET_TOKEN'
      • GitLab 17.4及更早版本:

        gitlab_shell['secret_token'] = 'GITLAB_SHELL_SECRET_TOKEN'
  6. 配置internal_api_url,这也是git push操作所需的:

    # 配置gitlab-shell API回调URL。如果没有此配置,`git push`将会失败。这可以是您的入口GitLab URL或内部负载均衡器。
    # 示例:'https://gitlab.example.com', 'http://10.0.2.2'
    gitlab_rails['internal_api_url'] = 'https://gitlab.example.com'
  7. 通过在/etc/gitlab/gitlab.rb中设置gitaly['configuration'][:storage]来配置Git数据的存储位置。每个Gitaly节点应具有唯一的存储名称(例如gitaly-1),且不应在其他Gitaly节点上重复。

    gitaly['configuration'] = {
       # ...
       storage: [
         # 替换为每个Gitaly节点的适当名称。
         {
           name: 'gitaly-1',
           path: '/var/opt/gitlab/git-data/repositories',
         },
       ],
    }
  8. 保存对/etc/gitlab/gitlab.rb的更改,并

重新配置Gitaly:

gitlab-ctl reconfigure
  1. 为确保Gitaly已更新其Prometheus监听地址(相关 issue),请重启Gitaly
gitlab-ctl restart gitaly

前面的步骤必须在每个Gitaly节点上完成!

在所有Gitaly节点配置完成后,运行Praefect连接检查器以验证Praefect能否连接到Praefect配置中的所有Gitaly服务器。

  1. 通过SSH进入每个Praefect节点并运行Praefect连接检查器:
sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dial-nodes

负载均衡器

在具有容错能力的Gitaly配置中,需要一个负载均衡器来将内部流量从GitLab应用程序路由到Praefect节点。具体使用哪种负载均衡器或确切配置超出了GitLab文档的范围。

负载均衡器必须配置为接受来自Gitaly节点的流量,以及GitLab节点的流量。

我们希望如果您正在管理像GitLab这样的容错系统,您已经有一个首选的负载均衡器了。一些示例包括 HAProxy(开源)、Google 内部负载均衡器AWS 弹性负载均衡器、F5 Big-IP LTM 和 Citrix NetScaler。本文档概述了您需要配置的端口和协议。

您应使用等效于 HAProxy 的 leastconn 负载均衡策略,因为长时间运行的操作(例如克隆)会使某些连接保持打开状态很长时间。

负载均衡器端口 后端端口 协议
2305 2305 TCP

您必须使用 TCP 负载均衡器。使用 HTTP/2 或 gRPC 负载均衡器与 Praefect 配合无法工作,因为 Gitaly 侧通道。这个优化会拦截 gRPC 握手过程。它将所有繁重的 Git 操作重定向到一个比 gRPC 更高效的“通道”,但 HTTP/2 或 gRPC 负载均衡器无法正确处理此类请求。

如果启用了 TLS,某些版本的 Praefect 要求根据 RFC 7540 使用应用层协议协商(ALPN)扩展。TCP 负载均衡器直接传递 ALPN 而无需额外配置:

sequenceDiagram
    autonumber
    participant Client as 客户端
    participant LB as TCP 负载均衡器
    participant Praefect as Praefect

    Client->>LB: 建立TLS会话(带ALPN扩展)
    LB->>Praefect: 建立TLS会话(带ALPN扩展)
    Client->>LB: 加密TCP包
    LB->>Praefect: 加密TCP包
    Praefect->>LB: 加密响应
    LB->>Client: 加密响应

有些 TCP 负载均衡器可以配置为接受 TLS 客户端连接,并将连接代理到 Praefect,建立新的 TLS 连接。但是,这仅在两个连接都支持 ALPN 时才有效。

出于这个原因,NGINX 的 ngx_stream_proxy_module 在启用 proxy_ssl 配置选项时不工作:

sequenceDiagram
    autonumber
    participant Client as 客户端
    participant NGINX as NGINX 流代理
    participant Praefect as Praefect

    Client->>NGINX: 建立TLS会话(带ALPN扩展)
    NGINX->>Praefect: 建立新TLS会话
    Praefect->>NGINX: 连接失败:缺少选定的ALPN属性

在第 2 步,未使用 ALPN,因为 NGINX 不支持此功能。有关更多信息,请 关注 NGINX 问题 406 以获取更多细节。

ALPN 强制执行

ALPN 强制执行在某些版本的 GitLab 中被启用。然而,ALPN 强制执行破坏了部署,因此被禁用以 提供迁移路径。以下版本的 GitLab 启用了 ALPN 强制执行:

  • GitLab 17.7.0
  • GitLab 17.6.0 - 17.6.2
  • GitLab 17.5.0 - 17.5.4
  • GitLab 17.4.x

通过 GitLab 17.5.5、17.6.3 和 17.7.1,ALPN 强制执行再次被禁用。GitLab 17.4 及更早版本从未启用过 ALPN 强制执行。

GitLab

要完成本节,您需要:

Praefect集群需要作为存储位置暴露给GitLab应用,这通过更新gitlab_rails['repositories_storages']来实现。

需特别注意以下事项:

  • 本节添加到gitlab_rails['repositories_storages']中的存储名称必须与Praefect节点上praefect['configuration'][:virtual_storage]下的存储名称一致。此设置已在本文档的Praefect部分完成。本文档中使用default作为Praefect存储名称。
  1. 通过SSH连接到GitLab节点并登录为root用户:

    sudo -i
  2. 编辑/etc/gitlab/gitlab.rb配置external_url,使GitLab能通过正确端点访问提供文件:

    您需要将GITLAB_SERVER_URL替换为当前GitLab实例提供服务的实际对外URL:

    external_url 'GITLAB_SERVER_URL'
  3. 禁用GitLab主机上运行的默认Gitaly服务。由于GitLab连接到已配置的集群,因此不需要该服务。

    如果您在默认Gitaly存储中有现有数据,应先将数据迁移到您的Gitaly集群(Praefect)存储

    gitaly['enable'] = false
  4. 编辑/etc/gitlab/gitlab.rb,将Praefect集群添加为存储位置。

    您需要将:

    • PRAEFECT_LOADBALANCER_HOST替换为负载均衡器的IP地址或主机名。
    • PRAEFECT_EXTERNAL_TOKEN替换为真实密钥

    如果使用TLS:

    • gitaly_address应以tls://开头。
    • 端口应更改为3305
    gitlab_rails['repositories_storages'] = {
      "default" => {
        "gitaly_address" => "tcp://PRAEFECT_LOADBALANCER_HOST:2305",
        "gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
      }
    }
  5. 配置GitLab Shell密钥令牌,以便在git push期间Gitaly节点的回调能被正确认证。可选择以下任一方式:

    • 方法1:

      1. 将Gitaly客户端上的/etc/gitlab/gitlab-secrets.json复制到Gitaly服务器及其他Gitaly客户端的同一路径。
      2. 在Gitaly服务器上重新配置GitLab
    • 方法2:

      1. 编辑/etc/gitlab/gitlab.rb

      2. GITLAB_SHELL_SECRET_TOKEN替换为真实密钥:

        • GitLab 17.5及更高版本:

          gitaly['gitlab_secret'] = 'GITLAB_SHELL_SECRET_TOKEN'
        • GitLab 17.4及更早版本:

          gitlab_shell['secret_token'] = 'GITLAB_SHELL_SECRET_TOKEN'
  6. 编辑/etc/gitlab/gitlab.rb添加Prometheus监控设置。如果在其他节点启用了Prometheus,则在该节点上进行编辑。

    您需要将:

    • PRAEFECT_HOST替换为Praefect节点的IP地址或主机名。
    • GITALY_HOST_*替换为每个Gitaly节点的IP地址或主机名。
    prometheus['scrape_configs'] = [
      {
        'job_name' => 'praefect',
        'static_configs' => [
          'targets' => [
            'PRAEFECT_HOST:9652', # praefect-1
            'PRAEFECT_HOST:9652', # praefect-2
            'PRAEFECT_HOST:9652', # praefect-3
          ]
        ]
      },
      {
        'job_name' => 'praefect-gitaly',
        'static_configs' => [
          'targets' => [
            'GITALY_HOST_1:9236', # gitaly-1
            'GITALY_HOST_2:9236', # gitaly-2
            'GITALY_HOST_3:9236', # gitaly-3
          ]
        ]
      }
    ]
  7. 保存对/etc/gitlab/gitlab.rb的更改,并重新配置GitLab

    gitlab-ctl reconfigure
  8. 在每个Gitaly节点上运行以下命令,验证Git Hooks能否访问GitLab:

    sudo -u git -- /opt/gitlab/embedded/bin/gitaly check /var/opt/gitlab/gitaly/config.toml
  9. 运行以下命令验证GitLab能否访问Praefect:

    gitlab-rake gitlab:gitaly:check
  10. 检查Praefect存储是否配置为存储新仓库:

    1. 在左侧边栏底部选择管理
    2. 在左侧边栏中选择设置 > 仓库
    3. 展开仓库存储部分。

    按照本指南,default存储的权重应为100,用于存储所有新仓库。

  11. 通过创建新项目来验证一切是否正常工作。勾选“用README初始化仓库”复选框,以便仓库中有可查看的内容。如果项目成功创建且能看到README文件,则表示工作正常!

为现有 GitLab 实例使用 TCP

当向现有的 Gitaly 实例添加 Gitaly 集群(Praefect)时,现有的 Gitaly 存储必须监听 TCP/TLS。如果未指定 gitaly_address,则使用 Unix 套接字,这会阻止与集群的通信。

例如:

gitlab_rails['repositories_storages'] = {
  'default' => { 'gitaly_address' => 'tcp://old-gitaly.internal:8075' },
  'cluster' => {
    'gitaly_address' => 'tls://<PRAEFECT_LOADBALANCER_HOST>:3305',
    'gitaly_token' => '<praefect_external_token>'
  }
}

有关运行多个 Gitaly 存储的更多信息,请参阅 混合配置

Grafana

Grafana 包含在 GitLab 中,可用于监控您的 Praefect 集群。详细文档请参见 Grafana 仪表板服务

若要快速开始:

  1. 通过 SSH 连接到 GitLab 节点(或启用了 Grafana 的任意节点),并以 root 身份登录:

    sudo -i
  2. 编辑 /etc/gitlab/gitlab.rb 以启用 Grafana 登录表单:

    grafana['disable_login_form'] = false
  3. 保存对 /etc/gitlab/gitlab.rb 的更改,并 重新配置 GitLab

    gitlab-ctl reconfigure
  4. 设置 Grafana 管理员密码。此命令会提示您输入新密码:

    gitlab-ctl set-grafana-password
  5. 在 Web 浏览器中,打开 GitLab 服务器上的 /-/grafana(例如 https://gitlab.example.com/-/grafana)。

    使用您设置的密码和用户名 admin 登录。

  6. 进入 Explore 并查询 gitlab_build_info,以验证您是否从所有机器获取了指标。

恭喜!您已配置了一个可观测的高可用 Praefect 集群。

配置复制因子

Praefect 支持按仓库为基础配置复制因子,通过分配特定的存储节点来托管仓库。

可配置的复制因子需要 仓库特定的主节点

Praefect 不存储实际的复制因子,而是分配足够的存储以满足所需的复制因子。如果后续某个存储节点从虚拟存储中被移除,分配给该存储的仓库的复制因子也会相应降低。

您可以配置以下任一方式:

  • 为每个虚拟存储设置默认复制因子,应用于新建仓库。
  • 使用 set-replication-factor 子命令为现有仓库设置复制因子。

配置默认复制因子

如果 default_replication_factor 未设置,仓库会始终复制到 virtual_storages 中定义的所有存储节点上。如果向虚拟存储中引入新的存储节点,新仓库和现有仓库都会自动复制到该节点。

对于包含大量存储节点的 Gitaly 集群(Praefect)部署,将仓库复制到每个存储节点通常不合理且可能引发问题。复制因子为 3 通常足够(即即使有更多存储可用,也仅复制到三个存储)。更高的复制因子会增加主存储的压力。

要配置默认复制因子,请在 /etc/gitlab/gitlab.rb 文件中添加配置:

praefect['configuration'] = {
   # ...
   virtual_storage: [
      {
         # ...
         name: 'default',
         default_replication_factor: 3,
      },
   ],
}

配置现有仓库的复制因子

set-replication-factor 子命令会自动分配或取消分配随机存储节点,以达成所需的复制因子。仓库的主节点总是被优先分配且不会被取消分配。

sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml set-replication-factor -virtual-storage <virtual-storage> -repository <relative-path> -replication-factor <replication-factor>
  • -virtual-storage 是仓库所在的虚拟存储。
  • -repository 是仓库在存储中的相对路径。
  • -replication-factor 是仓库所需的复制因子。最小值为 1,因为主节点需要一份仓库副本。最大复制因子是虚拟存储中的存储节点数量。

操作成功后,会打印出已分配的主机存储。例如:

$ sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml set-replication-factor -virtual-storage default -repository @hashed/3f/db/3fdba35f04dc8c462986c992bcf875546257113072a909c162f7e470e581e278.git -replication-factor 2

current assignments: gitaly-1, gitaly-2

仓库存储建议

所需存储的大小因实例而异,并取决于设定的复制因子。你可能需要考虑实现仓库存储冗余。

对于复制因子:

  • 1 时:Gitaly 和 Gitaly Cluster(Praefect)的存储需求大致相同。
  • 大于 1 时:所需存储量为 已用空间 × 复制因子已用空间 应包含任何计划内的未来增长。

仓库验证

Praefect 将仓库的元数据存储在数据库中。如果仓库在磁盘上的修改未通过 Praefect 进行,元数据可能会变得不准确。例如,若 Gitaly 节点被重建而非替换为新节点,仓库验证可检测到这种情况。

元数据用于复制和路由决策,因此任何不准确都可能引发问题。Praefect 包含一个后台工作进程,会定期将元数据与磁盘上的实际状态进行对比验证。该工作进程:

  1. 在健康的存储上选取一批待验证的副本。这些副本要么未被验证过,要么超过了配置的验证间隔。从未被验证过的副本会被优先处理,其余副本则按自上次成功验证以来的最长时间排序。
  2. 检查这些副本是否存在于各自的存储中。若:
    • 副本存在,则更新其最后一次成功验证的时间。
    • 副本不存在,则删除其元数据记录。
    • 检查失败,该副本会在下一次工作进程取出更多任务时再次被验证。

工作进程会在即将验证的每个副本上获取独占验证租约。这避免了多个工作进程同时验证同一个副本。工作进程完成检查后会释放租约。若有工作进程因某种原因终止而未释放租约,Praefect 会运行一个后台 goroutine,每 10 秒清理一次过期的租约。

工作进程会在执行删除前记录每次元数据的移除操作。perform_deletions 键表示无效的元数据记录是否真的被删除。例如:

{
  "level": "info",
  "msg": "removing metadata records of non-existent replicas",
  "perform_deletions": false,
  "replicas": {
    "default": {
      "@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b.git": [
        "praefect-internal-0"
      ]
    }
  }
}

配置验证工作进程

该工作进程默认启用,每七天验证一次元数据记录。验证间隔可通过任意有效的 Go duration 字符串 进行配置。

若要每三天验证一次元数据:

praefect['configuration'] = {
   # ...
   background_verification: {
      # ...
      verification_interval: '72h',
   },
}

值为 0 或更小则会禁用后台验证器。

praefect['configuration'] = {
   # ...
   background_verification: {
      # ...
      verification_interval: '0',
   },
}

启用删除

在 GitLab 15.9 之前,删除操作因与仓库重命名的竞态条件而默认禁用——该问题可能导致错误删除,在 Geo 实例中尤为突出(因 Geo 执行的重命名操作比非 Geo 实例更多)。在 GitLab 15.0 至 15.5 版本中,仅当 gitaly_praefect_generated_replica_paths 功能标志 启用时才应启用删除。该功能标志已在 GitLab 15.6 中移除,此后删除操作可安全启用。

默认情况下,工作进程会删除无效元数据记录,同时记录已删除记录并输出 Prometheus 指标。

你可以通过以下配置禁用删除无效元数据记录:

praefect['configuration'] = {
   # ...
   background_verification: {
      # ...
      delete_invalid_records: false,
   },
}

手动优先验证

你可提前对某些副本执行验证(即使其尚未到计划验证时间)。例如磁盘故障后,管理员已知磁盘内容可能变更时,需主动触发验证。Praefect 最终会重新验证这些副本,但期间用户可能遇到错误。

若要手动优先重新验证某些副本,使用 praefect verify 子命令。该子命令会将副本标记为“未验证”。背景验证工作进程会优先处理未验证副本;需确保验证工作进程已启用,副本才会被验证。

优先验证特定仓库的副本:

sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml verify -repository-id=<repository-id>

优先验证某虚拟存储上的所有副本:

sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml verify -virtual-storage=<virtual-storage>

优先验证某存储上的所有副本:

sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml verify -virtual-storage=<virtual-storage> -storage=<storage>

输出结果包含被标记为未验证的副本数量。

自动故障转移与主节点选举策略

Praefect 定期检查每个 Gitaly 节点健康状况,若当前主 Gitaly 节点被判定为异常,则会自动故障转移到新选举出的主 Gitaly 节点。

按仓库指定主节点 是唯一支持的选举策略。

按仓库指定主节点

Gitaly 集群(Praefect)会为每个仓库单独选举主 Gitaly 节点。结合可配置复制因子,可实现存储容量横向扩展,并将写负载分散至各 Gitaly 节点。

主节点选举以惰性方式运行:若当前主节点异常,Praefect 不会立即选举新主节点;只有当请求需处理而当前主节点不可用时,才会触发新主节点选举。

有效的主节点候选需满足:

  • 健康状态:若过去十秒内 ≥50% 的 Praefect 节点成功对该 Gitaly 节点完成健康检查,则视为健康。
  • 拥有完整的仓库副本。

若有多个主节点候选,Praefect 会:

  • 随机选取其中一个。
  • 优先提升分配给该仓库的 Gitaly 节点作为主节点;若无分配的节点可选,Praefect 可能临时选举未分配的节点为主。待分配节点可用时,未分配主节点会被降级,由分配节点接替。

若某仓库无有效主节点候选:

  • 异常主节点被降级,该仓库暂无主节点。
  • 需主节点的操作会失败,直至新主节点成功选举。