使用 GitLab-Gitaly chart

gitaly 子 chart 提供了 Gitaly 服务器的可配置部署。

要求

此 chart 依赖于对 Workhorse 服务的访问,可以作为完成 GitLab chart 的一部分,或者作为从此 chart 部署到 Kubernetes 集群访问的外部服务。

设计选择

此 chart 中使用的 Gitaly 容器还包含 GitLab Shell 代码库,以便对尚未移植到 Gitaly 的 Git 仓库执行操作。

Gitaly 容器中包含 GitLab Shell 容器的副本,因此我们还需要在此 chart 中配置 GitLab Shell。

配置

gitaly chart 分为两部分配置:外部服务chart 设置

在部署 GitLab chart 时,Gitaly 默认部署为一个组件。如果单独部署 Gitaly,则需要将 global.gitaly.enabled 设置为 false,并且需要按照外部 Gitaly 文档进行额外配置。

安装命令行选项

下表包含可以使用 --set 标志提供给 helm install 命令的所有可能的 chart 配置。

参数 默认值 说明
annotations   Pod annotations
common.labels {} 应用于此 chart 创建的所有对象的补充标签。
podLabels   补充 Pod 标签。 不会用于选择器。
external[].hostname - "" 外部节点的主机名
external[].name - "" 外部节点存储的名称
external[].port - "" 外部节点的端口
extraContainers   包含的额外容器列表
extraInitContainers   包含的额外 init 容器列表
extraVolumeMounts   要添加的附加挂载卷列表
extraVolumes   要创建的附加卷列表
extraEnv   要暴露的附加环境变量列表
extraEnvFrom   要暴露的其它数据源的额外环境变量列表
gitaly.serviceName   生成的 Gitaly service 名称。优先于 global.gitaly.serviceName,默认为 <RELEASE-NAME>-gitaly
gpgSigning.enabled false 是否应该使用 Gitaly GPG 签名
gpgSigning.secret   用于 Gitaly GPG 签名的 secret 名称。
gpgSigning.key   在 GPG secret 中,包含 Gitaly 的 GPG 签名密钥的键。
image.pullPolicy Always Gitaly 镜像拉取策略
image.pullSecrets   用于镜像仓库的 Secrets
image.repository registry.com/gitlab-org/build/cng/gitaly Gitaly 镜像仓库
image.tag master Gitaly 镜像标签
init.image.repository   initContainer 镜像
init.image.tag   initContainer 镜像标签
init.containerSecurityContext   initContainer 容器特定 securityContext
internal.names[] - default StatefulSet 存储的有序名称
serviceLabels {} 补充的 service 标签
service.externalPort 8075 Gitaly service 暴露的端口
service.internalPort 8075 Gitaly 内部端口
service.name gitaly Gitaly 在 Service 对象后面的 Service 端口的名称。
service.type ClusterIP Gitaly service 类型
securityContext.fsGroup 1000 在其下启动 Pod 的 Group ID
securityContext.fsGroupChangePolicy   更改卷的所有权和权限的策略(需要 Kubernetes 1.23)
securityContext.runAsUser 1000 在其下启动 Pod 的 User ID
tolerations [] 分配给 Pod 的容忍标签
persistence.accessMode ReadWriteOnce Gitaly 持久化访问模式
persistence.annotations   Gitaly 持久化 annotations
persistence.enabled true Gitaly 启用持久化标记
persistence.matchExpressions   Label-expression 匹配绑定
persistence.matchLabels   Label-value 匹配绑定
persistence.size 50Gi Gitaly 持久化卷大小
persistence.storageClass   配置的 storageClassName
persistence.subPath   Gitaly 持久卷挂载路径
priorityClassName   Gitaly StatefulSet priorityClassName
logging.level   日志级别
logging.format json 日志格式
logging.sentryDsn   Sentry DSN URL - Go 服务器
logging.sentryEnvironment   用于日志记录的 Sentry 环境
shell.concurrency[]   使用 rpcmaxPerRepo 指定的每个 RPC 端点的并发性
packObjectsCache.enabled false 启用 Gitaly 包对象缓存
packObjectsCache.dir /home/git/repositories/+gitaly/PackObjectsCache 存储缓存文件的目录
packObjectsCache.max_age 5m 缓存条目寿命
git.catFileCacheSize   Git cat-file 进程使用的缓存大小
git.config[] [] 生成 Git 命令时 Gitaly 应设置的 Git 配置
prometheus.grpcLatencyBuckets   Gitaly 记录的使用 GRPC 方法调用直方图延迟相对应的存储桶。需要输入字符串形式的数组(例如,"[1.0, 1.5, 2.0]"
statefulset.strategy {} 允许配置 statefulset 使用的更新策略
statefulset.livenessProbe.initialDelaySeconds 30 启动 liveness 探测之前的延迟
statefulset.livenessProbe.periodSeconds 10 多久执行一次 liveness 探测
statefulset.livenessProbe.timeoutSeconds 3 Liveness 探测超时时间
statefulset.livenessProbe.successThreshold 1 Liveness 探测失败后,被认为成功的最小连续成功次数
statefulset.livenessProbe.failureThreshold 3 Liveness 探测成功后,被视为失败的最小连续失败次数
statefulset.readinessProbe.initialDelaySeconds 10 Readiness 探测启动前的延时
statefulset.readinessProbe.periodSeconds 10 多久执行一次 readiness 探测
statefulset.readinessProbe.timeoutSeconds 3 Readiness 探测超时时间
statefulset.readinessProbe.successThreshold 1 Readiness 探测失败后,被认为成功的最小连续成功次数
statefulset.readinessProbe.failureThreshold 3 Readiness 探测成功后,被视为失败的最小连续失败次数
metrics.enabled false 指标端点是否可用于抓取
metrics.port 9236 指标端点端口
metrics.path /metrics 指标端点路径
metrics.serviceMonitor.enabled false 是否创建 ServiceMonitor 使 Prometheus Operator 能够管理指标抓取,请注意启用此功能会删除 prometheus.io 抓取注释
metrics.serviceMonitor.additionalLabels {} 要添加到 ServiceMonitor 的其它标签
metrics.serviceMonitor.endpointConfig {} ServiceMonitor 的附加端点配置
metrics.metricsPort   已废弃 使用 metrics.port
gomemlimit.enabled true 这会将 Gitaly 容器的 GOMEMLIMIT 环境变量自动设置为 resources.limits.memory。用户可以通过将此值设为 false 并在 extraEnv 设置 GOMEMLIMIT 来进行覆写。但是这必须满足严格的文档格式
cgroups.enabled false Gitaly 内置的 cgroup 控制。如做了配置,Gitaly 会将在 Git 命令操作仓库上的 Git 进程分配给 cgroup。此参数会启用仓库 cgroup。请注意,启用的情况下只支持 cgroup v2。
cgroups.initContainer.image.repository registry.com/gitlab-org/build/cng/gitaly-init-cgroups Gitaly 镜像仓库
cgroups.initContainer.image.tag master Gitaly 镜像标签
cgroups.initContainer.image.pullPolicy IfNotPresent Gitaly 镜像拉取策略
cgroups.mountpoint /etc/gitlab-secrets/gitaly-pod-cgroup 父级 cgroup 目录挂载点。
cgroups.hierarchyRoot gitaly Gitaly cgroup 的父 cgroup,且该 cgroup 应由运行 Gitaly 的用户和组拥有。
cgroups.memoryBytes   Gitaly 生成的所有 Git 进程所需的总内存限制。0 代表没限制。
cgroups.cpuShares   Gitaly 生成的所有 Git 进程所需的 CPU 限制。0 代表没限制。最大为 1024,意味着 CPU 的使用为 100%。
cgroups.cpuQuotaUs   用以控制 cgroup 的进程数以防超过限额。我们将 cpuQuotaUs 设为 100ms,1 core 为 100000。0 意味着没有限制。
cgroups.repositories.count   cgroup 池中的 cgroup 数量。每次启动一个新的 Git 命令时,Gitaly 会根据命令所针对的仓库将其分配到这些 cgroup。 中的一个。一个循环哈希算法将 Git 命令分配给这些 cgroup。,因此针对某个仓库的 Git 命令总是被分配到同一个 cgroup。
cgroups.repositories.memoryBytes   仓库 cgroup 中所有 Git 进程所需要的总内存限制。 0 代表没限制。此值不能超过顶层 memoryBytes 的值。
cgroups.repositories.cpuShares   仓库 cgroup 中包含的所有 Git 京城所需的 CPU 限制。0 意味着没限制。最大为 1024 ,意味着 100% 的 CPU 分享。此值不能超过顶层 cpuShares 的值。
cgroups.repositories.cpuQuotaUs   对包含在仓库 cgroup 中的所有 Git 进程施加的 cpuQuotaUs。Git 进程不能使用超过给定配额的资源。我们将 cpuQuotaUs 设置为 100ms,因此 1 core 是100000。0表 示没有限制。
cgroups.repositories.maxCgroupsPerRepo 1 针对特定仓库的 Git 进程可以分布到的仓库 cgroup 的数量。这允许为仓库 cgroup 配置更为保守的 CPU 和内存限制,同时仍然允许突发性工作负载。例如,如果 maxCgroupsPerRepo 设置为 2,memoryBytes 限制设置为 10GB,那么针对特定仓库的独立 Git 操作可以消耗高达 20GB 的内存。
gracefulRestartTimeout 25 Gitaly 优雅关闭的周期,等待 in-flight 请求完成的时间。Pod terminationGracePeriodSeconds 会在此值的基础上 +5s。

Chart 配置示例

extraEnv

extraEnv 允许您在 Pod 的所有容器中暴露额外的环境变量。

extraEnv 示例如下:

extraEnv:
  SOME_KEY: some_value
  SOME_OTHER_KEY: some_other_value

当容器启动时,您可以确认环境变量是否暴露:

env | grep SOME
SOME_KEY=some_value
SOME_OTHER_KEY=some_other_value

extraEnvFrom

extraEnvFrom 允许您从 pod 中的所有容器中的其它数据源,暴露其它环境变量。

下面是一个使用 extraEnvFrom 的示例:

extraEnvFrom:
  MY_NODE_NAME:
    fieldRef:
      fieldPath: spec.nodeName
  MY_CPU_REQUEST:
    resourceFieldRef:
      containerName: test-container
      resource: requests.cpu
  SECRET_THING:
    secretKeyRef:
      name: special-secret
      key: special_token
      # optional: boolean
  CONFIG_STRING:
    configMapKeyRef:
      name: useful-config
      key: some-string
      # optional: boolean

image.pullSecrets

pullSecrets 允许您对私有仓库进行身份验证,以拉取 pod 的镜像。

有关私有仓库及其身份验证方法的其它详细信息,请参见 Kubernetes 文档

下面是一个使用 pullSecrets 的例子:

image:
  repository: my.gitaly.repository
  tag: latest
  pullPolicy: Always
  pullSecrets:
  - name: my-secret-name
  - name: my-secondary-secret-name

serviceAccount

此部分用来控制是否应该创建一个 ServiceAccount 并确定是否应该将默认访问令牌挂载到 pod 中。

名称 类型 默认值 描述
annotations Map {} ServiceAccount 注释。
automountServiceAccountToken Boolean false 用来控制默认的 ServiceAccount 访问令牌是否应该被挂载到 pod 中。您不应该启用它,除非有特殊的 sidecar 需求(比如在 istio 中)。
create Boolean false 是否应该创建 ServiceAccount。
enabled Boolean false 是否应该使用 ServiceAccount。
name String   ServiceAccount 名称。如未设置,将使用 chart 的完整名称。

tolerations

tolerations 允许您调度 Pod 到受污染的工作节点上。

下面是一个使用 tolerations 的例子:

tolerations:
- key: "node_label"
  operator: "Equal"
  value: "true"
  effect: "NoSchedule"
- key: "node_label"
  operator: "Equal"
  value: "true"
  effect: "NoExecute"

affinity

更多信息,查看 affinity

annotations

annotations 允许您向 registry pod 添加 annotation。

下面是 annotations 的一个使用示例:

annotations:
  kubernetes.io/example-annotation: annotation-value

priorityClassName

priorityClassName 允许您分配 PriorityClass 给 Gitaly Pods。

下面是 priorityClassName 的一个使用示例:

priorityClassName: persistence-enabled

git.config

git.config 允许您为 Gitaly 生成的所有 Git 命令添加配置。接受 git-config(1)key / value 对中记录的配置,如下所示。

git:
  config:
    - key: "pack.threads"
      value: 4
    - key: "fsck.missingSpaceBeforeDate"
      value: ignore

cgroups

为了防止资源耗尽,Gitaly 使用cgroups来分配 Git 进程到一个基于仓库的 cgroup。每个 cgroup 都有内存和 CPU 限制,以确保系统稳定,防止资源饱和。

请注意,在 Gitaly 启动之前运行的 initContainer 需要以 root 用户执行。此容器将配置权限,以便 Gitaly 可以管理 cgroups。因此,它将挂载一个卷到文件系统中,以具有对 /sys/fs/cgroup 的写权限。

Oversubscription 示例

cgroups:
  enabled: true
  # Total limit across all repository cgroups
  memoryBytes: 64424509440 # 60GiB
  cpuShares: 1024
  cpuQuotaUs: 1200000 # 12 cores
  # Per repository limits, 1000 repository cgroups
  repositories:
    count: 1000
    memoryBytes: 32212254720 # 30GiB
    cpuShares: 512
    cpuQuotaUs: 400000 # 4 cores

外部服务

Workhorse service 附在此 chart 中。

Workhorse

workhorse:
  host: workhorse.example.com
  serviceName: webservice
  port: 8181
名称 类型 默认值 说明
host String   Workhorse 服务器的主机名。可以省略,使用 serviceName 进行代替。
port Integer 8181 连接 Workhorse 服务器的端口
serviceName String webservice 运行 Workhorse 数据库的 service名称。如果该配置存在,且 host 的值不存在 , 则 chart 将服务的主机名替换 host 的值。这样使用 Workhorse 作为整个 chart 一部分时很方便。

Chart 设置

以下值用于配置 Gitaly Pods。

note Gitaly 使用身份验证令牌对 Workhorse 和 Sidekiq 服务进行身份验证。 Auth Token secret 和密钥源于 global.gitaly.authToken 值。此外,Gitaly 容器有一份 GitLab Shell 的副本,其中有一些可以设置的配置。 Shell authToken 源自global.shell.authToken 值。

Git 仓库持久化

此 chart 提供 PersistentVolumeClaim 并为 Git 仓库数据挂载相应的持久卷。您需要 Kubernetes 集群中有可用的物理存储才能使其工作。 如果您更愿意使用 emptyDir,请使用:persistence.enabled: false 禁用 PersistentVolumeClaim。

note Gitaly 的持久性设置用于应该对您的所有 Gitaly pod 有效的 volumeClaimTemplate。应包括旨在引用单个特定卷(例如 volumeName)的设置。如果要引用特定卷,需要手动创建 PersistentVolumeClaim。
note 部署后,您将无法通过我们的设置进行更改。 在 StatefulSet 中,VolumeClaimTemplate 是不可变的。
persistence:
  enabled: true
  storageClass: standard
  accessMode: ReadWriteOnce
  size: 50Gi
  matchLabels: {}
  matchExpressions: []
  subPath: "data"
  annotations: {}
名称 类型 默认值 说明
accessMode String ReadWriteOnce 设置 PersistentVolumeClaim 中请求的访问模式。 有关详细信息,请参阅 Kubernetes 访问模式文档
enabled Boolean true 设置是否对仓库数据使用 PersistentVolumeClaims。 如果为 false,则使用 emptyDir 卷。
matchExpressions Array   在选择要绑定的卷时,接受要匹配的标签条件对象数组。用于PersistentVolumeClaimselector部分。 请参阅 卷文档
matchLabels Map   在选择要绑定的卷时,接受要匹配的标签名称和标签值的映射。用于PersistentVolumeClaimselector 部分。 请参阅 卷文档
size String 50Gi 为数据持久化,请求的最小的卷大小
storageClass String   在 Volume Claim 上设置 storageClassName 以进行 dynamic provisioning。当未设置或为空时,将使用默认 provisioner。如果设置为连字符,禁用 dynamic provisioning。
subPath String   设置要挂载的卷中的路径,而不是卷的根路径。 如果子路径为空,则使用根路径。
annotations Map   为动态供应设置卷声明的 annotation。有关详细信息,请参阅 Kubernetes Annotations 文档

通过 TLS 运行 Gitaly

note 本节涉及使用 Helm chart 在集群内运行的 Gitaly。如果您使用外部 Gitaly 实例并希望使用 TLS 与之通信,请参阅 外部 Gitaly 文档

Gitaly 支持通过 TLS 与其他组件通信。设置 global.gitaly.tls.enabledglobal.gitaly.tls.secretName 进行控制。 按照以下步骤通过 TLS 运行 Gitaly:

  1. Helm chart 需要提供证书以通过 TLS 与 Gitaly 进行通信。此证书应适用于所有存在的 Gitaly 节点。 因此,每个 Gitaly 节点的所有主机名都应作为 Subject Alternate Name (SAN) 添加到证书中。

    要知道要使用的主机名,请检查 Toolbox pod 中的文件 /srv/gitlab/config/gitlab.yml,并检查其中的 repositories.storages 键下指定的各种 gitaly_address 字段。

    kubectl exec -it <Toolbox pod> -- grep gitaly_address /srv/gitlab/config/gitlab.yml
    
note 为内部 Gitaly pod 生成自定义签名证书的基础脚本,可以以此为例。用户可以使用或参考该脚本来生成具有适当 SAN 属性的证书。
  1. 使用创建的证书创建 k8s TLS 密钥。

    kubectl create secret tls gitaly-server-tls --cert=gitaly.crt --key=gitaly.key
    
  2. 通过传递 --set global.gitaly.tls.enabled=true 重新部署 Helm chart。

全局服务器 hooks

Gitaly StatefulSet 支持 全局服务器 hooks。钩子脚本在 Gitaly pod 上运行,因此仅限于 Gitaly 容器中可用的工具。

钩子是使用 ConfigMaps 填入的,可以通过适当设置以下值来使用:

  1. global.gitaly.hooks.preReceive.configmap
  2. global.gitaly.hooks.postReceive.configmap
  3. global.gitaly.hooks.update.configmap

要填写 ConfigMap, 您可以将 kubectl 指向一个脚本目录:

kubectl create configmap MAP_NAME --from-file /PATH/TO/SCRIPT/DIR

极狐GitLab 创建的 GPG 签名提交

Gitaly 能够对通过 UI 创建的所有提交进行 GPG 签名,例如使用 WebIDE,以及极狐GitLab 创建的提交,包括合并提交和压缩。

  1. 使用您的 GPG 私钥创建一个 k8s 密钥。

    kubectl create secret generic gitaly-gpg-signing-key --from-file=signing_key=/path/to/gpg_signing_key.gpg
    
  2. 在您的 values.yaml 中启用 GPG 签名。

    gitlab:
      gitaly:
        gpgSigning:
          enabled: true
          secret: gitaly-gpg-signing-key
          key: signing_key
    

服务器端备份

chart 支持 Gitaly 服务端备份。如要使用:

  1. 创建存储桶用以存储备份。
  2. 配置对象存储凭据以及存储 URL。

    gitlab:
      gitaly:
        extraEnvFrom:
           # Mount the exisitign object store secret to the expected environment variables.
           AWS_ACCESS_KEY_ID:
             secretKeyRef:
               name: <Rails object store secret>
               key: aws_access_key_id
           AWS_SECRET_ACCESS_KEY:
             secretKeyRef:
               name: <Rails object store secret>
               key: aws_secret_access_key
        backup:
          # This is the connection string for Gitaly server side backups.
          goCloudUrl: <object store connection URL>
    

    针对您存储后段的期望环境变量和存储 URL 格式详情,可以查看Gitaly 文档

  3. 使用 backup-utility 开启服务端备份