InfoGrab DocsInfoGrab Docs

Gitaly Cluster(Praefect) 구성

요약

다음 중 하나를 사용하여 Gitaly Cluster(Praefect)를 구성합니다. 소규모 GitLab 설치에는 Gitaly 자체만 필요할 수 있습니다. Gitaly Cluster(Praefect)는 아직 Kubernetes, Amazon ECS 또는 이와 유사한 컨테이너 환경에서 지원되지 않습니다.

다음 중 하나를 사용하여 Gitaly Cluster(Praefect)를 구성합니다.

소규모 GitLab 설치에는 Gitaly 자체만 필요할 수 있습니다.

Note

Gitaly Cluster(Praefect)는 아직 Kubernetes, Amazon ECS 또는 이와 유사한 컨테이너 환경에서 지원되지 않습니다. 자세한 내용은 에픽 6127을 참고합니다.

요구 사항#

Gitaly Cluster(Praefect)의 최소 권장 구성에는 다음이 필요합니다.

  • 로드 밸런서 1대
  • PostgreSQL 서버 1대(지원되는 버전)
  • Praefect 노드 3대
  • Gitaly 노드 3대(기본 1대, 보조 2대)
Note

디스크 요구 사항은 Gitaly 노드에 적용됩니다.

Gitaly 노드 중 하나가 변경 RPC 호출 중에 실패하더라도 트랜잭션에 결정권을 가진 표가 남도록, Gitaly 노드는 홀수 개로 구성해야 합니다.

구현 세부 사항은 설계 문서를 참고합니다.

Note

GitLab에서 기능 플래그를 설정하지 않으면 콘솔에서는 false로 읽히고, Praefect는 해당 플래그의 기본값을 사용합니다. 기본값은 GitLab 버전에 따라 다릅니다.

네트워크 지연 시간과 연결#

Gitaly Cluster(Praefect)의 네트워크 지연 시간은 이상적으로 한 자릿수 밀리초 단위로 측정될 수 있어야 합니다. 지연 시간은 특히 다음 경우에 중요합니다.

  • Gitaly 노드 상태 확인. 노드는 1초 이내에 응답할 수 있어야 합니다.
  • 강한 일관성을 강제하는 참조 트랜잭션. 지연 시간이 낮을수록 Gitaly 노드가 변경 사항에 더 빠르게 합의할 수 있습니다.

Gitaly 노드 간에 허용 가능한 지연 시간을 확보하는 방법은 다음과 같습니다.

  • 물리 네트워크에서는 일반적으로 대역폭이 높은 단일 위치 연결을 의미합니다.
  • 클라우드에서는 일반적으로 가용 영역 간 복제를 허용하는 것을 포함해 같은 리전 안에 두는 것을 의미합니다. 이러한 링크는 이런 유형의 동기화를 위해 설계되었습니다. Gitaly Cluster(Praefect)에는 2ms 미만의 지연 시간이면 충분합니다.

복제를 위한 낮은 네트워크 지연 시간을 제공할 수 없는 경우(예: 멀리 떨어진 위치 사이) Geo를 고려합니다. 자세한 내용은 Geo와의 비교를 참고합니다.

Gitaly Cluster(Praefect)의 구성 요소는 여러 경로로 서로 통신합니다. Gitaly Cluster(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
Note

Gitaly는 Praefect에 직접 연결하지 않습니다. 그러나 Praefect 노드의 방화벽이 Gitaly 노드의 트래픽을 허용하지 않으면 Gitaly에서 Praefect 로드 밸런서로 가는 요청이 여전히 차단될 수 있습니다.

Praefect 데이터베이스 스토리지#

데이터베이스에는 다음 메타데이터만 들어 있으므로 요구 사항이 비교적 낮습니다.

  • 리포지터리가 위치한 곳
  • 대기열에 있는 일부 작업

리포지터리 수에 따라 다르지만, 메인 GitLab 애플리케이션 데이터베이스와 마찬가지로 최소 5-10GB가 적절합니다.

설정 지침#

Linux 패키지를 사용하여 GitLab을 설치한 경우(강력히 권장), 다음 단계를 따릅니다.

  1. 준비
  2. Praefect 데이터베이스 구성
  3. Praefect 프록시/라우터 구성
  4. 각 Gitaly 노드 구성(Gitaly 노드마다 한 번씩)
  5. 로드 밸런서 구성
  6. GitLab 서버 구성 업데이트
  7. Grafana 구성

준비#

시작하기 전에 이미 작동하는 GitLab 인스턴스가 있어야 합니다. GitLab 설치 방법을 참고합니다.

PostgreSQL 서버를 프로비저닝합니다. Linux 패키지에 포함된 PostgreSQL을 사용하여 PostgreSQL 데이터베이스를 구성하는 것을 권장합니다. 외부 PostgreSQL 서버를 사용할 수도 있지만 수동으로 설정해야 합니다.

모든 새 노드에 GitLab을 설치하여 준비합니다. 다음이 필요합니다.

  • PostgreSQL 노드 1대
  • PgBouncer 노드 1대(선택 사항)
  • Praefect 노드 최소 1대(필요한 스토리지 최소)
  • Gitaly 노드 3대(높은 CPU, 높은 메모리, 빠른 스토리지)
  • GitLab 서버 1대

각 노드의 IP/호스트 주소도 필요합니다.

  1. PRAEFECT_LOADBALANCER_HOST: Praefect 로드 밸런서의 IP/호스트 주소
  2. POSTGRESQL_HOST: PostgreSQL 서버의 IP/호스트 주소
  3. PGBOUNCER_HOST: PostgreSQL 서버의 IP/호스트 주소
  4. PRAEFECT_HOST: Praefect 서버의 IP/호스트 주소
  5. GITALY_HOST_*: 각 Gitaly 서버의 IP 또는 호스트 주소
  6. GITLAB_HOST: GitLab 서버의 IP/호스트 주소

Google Cloud Platform, SoftLayer 또는 가상 사설 클라우드(VPC)를 제공하는 다른 공급업체를 사용하는 경우, PRAEFECT_HOST, GITALY_HOST_*, GITLAB_HOST에 각 클라우드 인스턴스의 사설 주소(Google Cloud Platform의 "내부 주소"에 해당)를 사용할 수 있습니다.

시크릿#

구성 요소 간 통신은 서로 다른 시크릿으로 보호되며, 아래에 설명되어 있습니다. 시작하기 전에 각 항목에 고유한 시크릿을 생성하고 기록해 둡니다. 이렇게 하면 설정 과정을 완료하면서 자리 표시자 토큰을 안전한 토큰으로 교체할 수 있습니다.

  1. GITLAB_SHELL_SECRET_TOKEN: Git 훅이 Git 푸시를 수락할 때 GitLab에 콜백 HTTP API 요청을 보내는 데 사용합니다. 이 시크릿은 기존 방식과의 호환을 위해 GitLab Shell과 공유됩니다.
  2. PRAEFECT_EXTERNAL_TOKEN: Praefect 클러스터에 호스팅된 리포지터리는 이 토큰을 가진 Gitaly 클라이언트만 접근할 수 있습니다.
  3. PRAEFECT_INTERNAL_TOKEN: Praefect 클러스터 내부의 복제 트래픽에 사용하는 토큰입니다. Gitaly 클라이언트가 Praefect 클러스터의 내부 노드에 직접 접근해서는 안 되고, 접근하면 데이터 손실로 이어질 수 있으므로 이 토큰은 PRAEFECT_EXTERNAL_TOKEN과 구분됩니다.
  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 문서를 참고합니다.

아래 지침에서 이러한 시크릿이 필요한 위치를 표시합니다.

Note

Linux 패키지 설치는 GITLAB_SHELL_SECRET_TOKEN에 gitlab-secrets.json을 사용할 수 있습니다.

시간 서버 설정 사용자 지정#

기본적으로 Gitaly 노드와 Praefect 노드는 시간 동기화 확인에 pool.ntp.org의 시간 서버를 사용합니다. 각 노드의 gitlab.rb에 다음을 추가하여 이 설정을 사용자 지정할 수 있습니다.

  • Gitaly 노드: gitaly['env'] = { "NTP_HOST" => "ntp.example.com" }
  • Praefect 노드: praefect['env'] = { "NTP_HOST" => "ntp.example.com" }

PostgreSQL#

Note

Praefect는 GitLab 애플리케이션 데이터베이스와 별개의 데이터베이스를 사용하여 Gitaly 리포지터리 복제 상태를 관리합니다. Geo와 Gitaly Cluster(Praefect)를 함께 사용하면 Praefect 복제 상태는 각 사이트마다 고유합니다. 각 Geo 사이트에는 Praefect 데이터베이스를 담을 별도의 읽기-쓰기 PostgreSQL 데이터베이스 인스턴스가 있어야 합니다.

  • GitLab 애플리케이션 데이터베이스와 Praefect 데이터베이스를 같은 PostgreSQL 서버에 저장하지 않습니다.
  • Geo 기본 사이트의 Praefect Postgres 데이터베이스가 Geo 보조 사이트로 복제되도록 구성하지 않습니다.

이 지침은 단일 장애 지점이 되는 단일 PostgreSQL 데이터베이스를 설정하는 방법을 안내합니다. 이를 피하려면 자체 클러스터형 PostgreSQL을 구성할 수 있습니다. 다른 데이터베이스(예: Praefect 및 Geo 데이터베이스)에 대한 클러스터형 데이터베이스 지원은 이슈 7292에서 제안되어 있습니다.

다음 옵션을 사용할 수 있습니다.

  • Geo를 사용하지 않는 설치의 경우 다음 중 하나를 선택합니다.
    • 문서화된 PostgreSQL 설정 중 하나를 사용합니다.
    • 자체 서드 파티 데이터베이스 설정을 사용합니다. 이 경우 수동 설정이 필요합니다.
  • Geo 인스턴스의 경우 다음 중 하나를 선택합니다.

PostgreSQL을 설정하면 비어 있는 Praefect 테이블이 생성됩니다. 자세한 내용은 관련 문제 해결 섹션을 참고합니다.

같은 서버에서 GitLab 및 Praefect 데이터베이스 실행#

GitLab 애플리케이션 데이터베이스와 Praefect 데이터베이스는 같은 서버에서 실행할 수 있습니다. 그러나 Linux 패키지의 PostgreSQL을 사용하는 경우 Praefect에는 자체 데이터베이스 서버를 두어야 합니다. 장애 조치가 발생하면 Praefect는 이를 인식하지 못하고, 사용하려는 데이터베이스가 다음 상태가 되어 실패하기 시작합니다.

  • 사용할 수 없음
  • 읽기 전용 모드

수동 데이터베이스 설정#

이 섹션을 완료하려면 다음이 필요합니다.

  • Praefect 노드 1대
  • PostgreSQL 노드 1대
    • 데이터베이스 서버를 관리할 권한이 있는 PostgreSQL 사용자

이 섹션에서는 PostgreSQL 데이터베이스를 구성합니다. 이 방법은 외부 PostgreSQL 서버와 Linux 패키지에서 제공하는 PostgreSQL 서버 모두에 사용할 수 있습니다.

다음 지침을 실행하려면 Linux 패키지가 psql을 설치해 둔 Praefect 노드(/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';
    

    를 준비 단계에서 생성한 비밀번호의 해시로 바꿉니다. 앞에 md5 리터럴이 붙습니다.

  2. PgBouncer가 사용할 새 사용자 pgbouncer를 만듭니다.

    CREATE ROLE pgbouncer WITH LOGIN;
    ALTER USER pgbouncer WITH password 'md5';
    

    PGBOUNCER_SQL_PASSWORD_HASH를 준비 단계에서 생성한 강력한 비밀번호 해시로 바꿉니다.

  3. pg_shadow_lookup 함수를 praefect_production 데이터베이스에 생성합니다.

이제 Praefect가 사용하는 데이터베이스가 구성되었습니다.

이제 Praefect가 이 데이터베이스를 사용하도록 구성할 수 있습니다.

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

PostgreSQL을 구성한 후 Praefect 데이터베이스 오류가 표시되면 문제 해결 단계를 참고합니다.

자체 관리 Patroni 클러스터로 자동 장애 조치 구성#

수동 데이터베이스 설정을 완료한 후, Patroni와 같은 장애 조치 도구가 관리하는 PostgreSQL 클러스터를 Praefect가 직접 가리키도록 할 수 있습니다. Praefect는 pgx를 사용하여 PostgreSQL에 연결하며, pgx는 libpq와 동일한 다중 호스트 연결 동작을 지원합니다. Praefect는 주소 목록의 모든 호스트를 확인하여 현재 쓰기를 수락하는 호스트에 연결하고, 장애 조치 후에는 자동으로 다시 연결합니다.

이 구성에서는 PostgreSQL 클러스터 앞에 프록시를 두지 않습니다. 이 클라이언트 측 장애 조치 감지는 GitLab 애플리케이션 데이터베이스에 사용하는 설정과 다릅니다. 해당 설정에서는 PgBouncer나 Consul 기반 라우팅 같은 프록시가 클러스터 앞에 위치하여 자체적으로 서버 측 전환을 수행합니다. 두 방식을 결합하면 프록시가 개별 클러스터 노드를 Praefect로부터 숨기므로 pgx가 각 노드를 직접 확인할 수 없게 되거나, 프록시 자체의 장애 조치가 Praefect의 클라이언트 측 감지와 경합하게 됩니다.

GitLab은 이 구성을 GitLab.com 또는 Dedicated 환경에 배포하거나 테스트하지 않았습니다. 이 구성에 의존하기 전에 비프로덕션 환경에서 철저히 검증해야 합니다.

Warning

클러스터가 동기식 복제를 사용하도록 구성합니다. 비동기식 복제를 사용하면 기본 노드를 잃는 장애 조치에서 커밋되었지만 아직 복제되지 않은 트랜잭션도 손실될 수 있으며, 이로 인해 Praefect 데이터베이스가 Gitaly가 예상하지 못하는 상태가 될 수 있습니다.

사전 요구 사항:

  • 클러스터에 대해 수동 데이터베이스 설정을 완료했습니다.
  • Patroni 또는 새 기본 노드를 자동으로 승격하는 동등한 도구가 관리하는 PostgreSQL 클러스터가 Praefect 데이터베이스 전용 서버에 있고, 동기식 복제로 구성되어 있습니다. 이 클러스터는 GitLab 애플리케이션 데이터베이스에 사용하는 것과 동일한 Patroni, Consul, PostgreSQL 구성 요소를 별도의 노드 집합에 구성하여 구축할 수 있습니다.
  • Praefect 노드에서 클러스터의 모든 노드로의 네트워크 접근

Praefect를 구성하려면 다음을 수행합니다.

  1. Praefect 구성에서 database.host를 클러스터 노드 주소의 쉼표로 구분된 목록으로 설정하고, database.port를 모든 노드가 공유하는 포트로 설정합니다.

    praefect['configuration'] = {
       # ...
       database: {
          # ...
          host: 'POSTGRESQL_HOST_1,POSTGRESQL_HOST_2,POSTGRESQL_HOST_3',
          port: 5432,
          user: 'praefect',
          password: PRAEFECT_SQL_PASSWORD,
          dbname: 'praefect_production',
       }
    }
    
  2. Praefect 프로세스가 현재 기본 노드에 연결되도록 PGTARGETSESSIONATTRS 환경 변수를 read-write로 설정합니다. Praefect 구성에는 PGTARGETSESSIONATTRS 전용 설정이 없으므로 Praefect 환경을 통해 변수를 설정합니다. Praefect의 기존 기본 환경 변수가 제거되지 않도록 env 해시 전체를 할당하지 말고 키를 직접 설정합니다.

    praefect['env']['PGTARGETSESSIONATTRS'] = 'read-write'
    
  3. 변경 사항이 적용되도록 재구성합니다.

    gitlab-ctl reconfigure
    

이 구성은 Praefect와 PostgreSQL 사이의 직접 연결만 다룹니다. PgBouncer를 사용하도록 session_pooled 설정도 구성하는 경우 PgBouncer의 고가용성은 별도로 확보해야 합니다. session_pooled 설정은 호스트를 하나만 허용하므로 PgBouncer 연결은 이 장애 조치 메커니즘에 참여하지 않습니다.

읽기 분산 캐싱#

추가로 session_pooled 설정을 구성하면 Praefect 성능을 개선할 수 있습니다.

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

         # Use the following to override parameters of direct database connection.
         # Comment out where the parameters are the same for both connections.
         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를 설정하고 구성하는 것이 좋습니다. 그러나 PgBouncer는 필수가 아닙니다. Praefect는 연결 수가 적기 때문입니다. 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에는 LISTEN 기능을 지원하는 PostgreSQL에 대한 추가 연결이 필요합니다. PgBouncer에서 이 기능은 session 풀 모드(pool_mode = session)에서만 사용할 수 있습니다. transaction 풀 모드(pool_mode = transaction)에서는 지원되지 않습니다.

추가 연결을 구성하려면 다음 중 하나를 수행해야 합니다.

  • 동일한 PostgreSQL 데이터베이스 엔드포인트에 연결하되 풀 모드가 다른(pool_mode = session) 새 PgBouncer 데이터베이스를 구성합니다.
  • PgBouncer를 우회하여 Praefect를 PostgreSQL에 직접 연결합니다.
pool_mode = session으로 새 PgBouncer 데이터베이스 구성#

PgBouncer는 session 풀 모드로 사용해야 합니다. 번들 PgBouncer를 사용하거나 외부 PgBouncer를 사용하여 수동으로 구성할 수 있습니다.

다음 예시는 번들 PgBouncer를 사용하며, PostgreSQL 호스트에 session 풀 모드와 transaction 풀 모드 각각의 연결 풀을 별도로 두 개 설정합니다. 이 예시가 작동하려면 설정 지침에 설명된 대로 PostgreSQL 서버를 준비해야 합니다.

그런 다음 PgBouncer 호스트에서 별도의 연결 풀을 구성합니다.

pgbouncer['databases'] = {
  # Other database configuration including gitlabhq_production
  ...

  praefect_production: {
    host: POSTGRESQL_HOST,
    # Use `pgbouncer` user to connect to database backend.
    user: 'pgbouncer',
    password: PGBOUNCER_SQL_PASSWORD_HASH,
    pool_mode: 'transaction'
  },
  praefect_production_direct: {
    host: POSTGRESQL_HOST,
    # Use `pgbouncer` user to connect to database backend.
    user: 'pgbouncer',
    password: PGBOUNCER_SQL_PASSWORD_HASH,
    dbname: 'praefect_production',
    pool_mode: 'session'
  },

  ...
}

# Allow the praefect user to connect to PgBouncer
pgbouncer['users'] = {
  'praefect': {
    'password': PRAEFECT_SQL_PASSWORD_HASH,
  }
}

praefect_production과 praefect_production_direct는 같은 데이터베이스 엔드포인트 (praefect_production)를 사용하지만 풀 모드가 다릅니다. 이는 PgBouncer의 다음 databases 섹션으로 변환됩니다.

[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

이제 두 연결 모두에 PgBouncer를 사용하도록 Praefect를 구성할 수 있습니다.

praefect['configuration'] = {
   # ...
   database: {
      # ...
      host: PGBOUNCER_HOST,
      port: 6432,
      user: 'praefect',
      # `PRAEFECT_SQL_PASSWORD` is the plain-text password of
      # Praefect user. Not to be confused with `PRAEFECT_SQL_PASSWORD_HASH`.
      password: PRAEFECT_SQL_PASSWORD,
      dbname: 'praefect_production',
      session_pooled: {
         # ...
         dbname: 'praefect_production_direct',
         # There is no need to repeat the following. Parameters of direct
         # database connection will fall back to the values specified in the
         # database block.
         #
         # host: PGBOUNCER_HOST,
         # port: 6432,
         # user: 'praefect',
         # password: PRAEFECT_SQL_PASSWORD,
      },
   },
}

이 구성에서 Praefect는 두 연결 유형 모두에 PgBouncer를 사용합니다.

Note

Linux 패키지 설치는 (auth_query를 사용하여) 인증 요구 사항을 처리합니다. 다만 데이터베이스를 수동으로 준비하고 외부 PgBouncer를 구성하는 경우, PgBouncer가 사용하는 파일에 praefect 사용자와 해당 비밀번호를 포함해야 합니다. 예를 들어 auth_file 구성 옵션이 설정되어 있다면 userlist.txt입니다. 자세한 내용은 PgBouncer 문서를 참고합니다.

PostgreSQL에 직접 연결하도록 Praefect 구성#

session 풀 모드로 PgBouncer를 구성하는 대신, PostgreSQL에 직접 접근할 때 사용할 서로 다른 연결 매개변수를 Praefect에 구성할 수 있습니다. 이 연결은 LISTEN 기능을 지원합니다.

PgBouncer를 우회하여 PostgreSQL에 직접 연결하는 Praefect 구성 예시는 다음과 같습니다.

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

         # Use the following to override parameters of direct database connection.
         # Comment out where the parameters are the same for both connections.
         #
         user: 'praefect',
         password: PRAEFECT_SQL_PASSWORD,
         dbname: 'praefect_production',
         # sslmode: '...',
         # sslcert: '...',
         # sslkey: '...',
         # sslrootcert: '...',
      },
   },
}

Praefect#

Praefect를 구성하기 전에 Praefect 구성 파일 예시를 참고하여 익혀 둡니다. Linux 패키지를 사용하여 GitLab을 설치한 경우, 예시 파일의 설정을 Ruby로 변환해야 합니다.

Praefect 노드가 여러 개인 경우 다음을 수행합니다.

  1. 노드 하나를 배포 노드로 지정하고, 다음 단계를 사용하여 구성합니다.
  2. 나머지 각 노드에서 다음 단계를 완료합니다.

이 섹션을 완료하려면 다음을 포함하는 구성된 PostgreSQL 서버가 필요합니다.

Warning

Praefect는 전용 노드에서 실행해야 합니다. 애플리케이션 서버나 Gitaly 노드에서 Praefect를 실행하지 않습니다.

Praefect 노드에서 다음을 수행합니다.

  1. /etc/gitlab/gitlab.rb를 편집하여 다른 모든 서비스를 비활성화합니다.
# Avoid running unnecessary services on the Praefect server
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

# Enable only the Praefect service
praefect['enable'] = true

# Prevent database migrations from running on upgrade automatically
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'] = {
       # ...
       #
       # Enable Prometheus metrics access to Praefect. You must use firewalls
       # to restrict access to this address/port.
       # The default metrics endpoint is /metrics
       prometheus_listen_addr: '0.0.0.0:9652',
       # Some metrics run queries against the database. Enabling separate database metrics allows
       # these metrics to be collected when the metrics are
       # scraped on a separate /db_metrics endpoint.
       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: {
          # ...
          #
          # Connect to PostgreSQL using a TLS client certificate
          # sslcert: '/path/to/client-cert',
          # sslkey: '/path/to/client-key',
          #
          # Trust a custom certificate authority
          # sslrootcert: '/path/to/rootcert',
       },
    }
    

    기본적으로 Praefect는 기회적 TLS(opportunistic TLS)를 사용하여 PostgreSQL에 연결합니다. 즉, Praefect는 sslmode를 prefer로 설정하여 PostgreSQL에 연결을 시도합니다. 다음 줄의 주석을 해제하여 이를 재정의할 수 있습니다.

    praefect['configuration'] = {
       # ...
       database: {
          # ...
          # sslmode: 'disable',
       },
    }
    
  5. /etc/gitlab/gitlab.rb를 편집하여 Praefect 클러스터가 클러스터의 각 Gitaly 노드에 연결하도록 구성합니다.

    가상 스토리지의 이름은 GitLab 구성의 스토리지 이름과 일치해야 합니다. 이후 단계에서 스토리지 이름을 default로 구성하므로 여기서도 default를 사용합니다. 이 클러스터에는 세 개의 Gitaly 노드 gitaly-1, gitaly-2, gitaly-3이 있으며, 이들은 서로의 복제본으로 사용됩니다.

    [!warning] 이미 default라는 이름의 스토리지에 데이터가 있다면, 가상 스토리지를 다른 이름으로 구성하고 이후에 데이터를 Gitaly Cluster(Praefect) 스토리지로 마이그레이션해야 합니다.

    PRAEFECT_INTERNAL_TOKEN을 강력한 시크릿으로 바꿉니다. 이 시크릿은 Praefect가 클러스터의 Gitaly 노드와 통신할 때 사용합니다. 이 토큰은 PRAEFECT_EXTERNAL_TOKEN과 구분됩니다.

    GITALY_HOST_*를 각 Gitaly 노드의 IP 또는 호스트 주소로 바꿉니다.

    복제본 수를 늘리려면 클러스터에 Gitaly 노드를 더 추가할 수 있습니다. 규모가 매우 큰 GitLab 인스턴스에는 클러스터를 더 추가할 수도 있습니다.

    [!note] 가상 스토리지에 Gitaly 노드를 추가할 때는 해당 가상 스토리지의 모든 스토리지 이름이 고유해야 합니다. 또한 Praefect 구성에서 참조하는 모든 Gitaly 노드 주소도 고유해야 합니다.

    # Name of storage hash must match storage name in gitlab_rails['repositories_storages'] on GitLab
    # server ('default') and in gitaly['configuration'][:storage][INDEX][:name] on Gitaly nodes ('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'
                },
             ],
          },
       ],
    }
    
  6. /etc/gitlab/gitlab.rb에 변경 사항을 저장하고 Praefect를 재구성합니다.

    gitlab-ctl reconfigure
    
  7. 다음 노드별로 수행합니다.

    • "배포 노드"의 경우:

      1. /etc/gitlab/gitlab.rb에서 praefect['auto_migrate'] = true로 설정하여 Praefect 데이터베이스 자동 마이그레이션을 다시 활성화합니다.

      2. 데이터베이스 마이그레이션이 업그레이드 시 자동으로 실행되지 않고 재구성 중에만 실행되도록 다음을 실행합니다.

        sudo touch /etc/gitlab/skip-auto-reconfigure
        
    • 나머지 노드의 경우 설정을 그대로 두어도 됩니다. /etc/gitlab/skip-auto-reconfigure는 필수가 아니지만, apt-get update 같은 명령을 실행할 때 GitLab이 재구성을 자동으로 실행하지 않도록 이 파일을 설정할 수 있습니다. 이렇게 하면 추가 구성 변경을 마친 뒤 재구성을 수동으로 실행할 수 있습니다.

  8. /etc/gitlab/gitlab.rb에 변경 사항을 저장하고 Praefect를 재구성합니다.

    gitlab-ctl reconfigure
    
  9. Praefect가 Prometheus 수신 대기 주소를 업데이트했는지 확인하려면 Praefect를 다시 시작합니다.

    gitlab-ctl restart praefect
    
  10. 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 서버에 해당하는 인증서를 그 Praefect 서버에 설치해야 합니다.

또한 GitLab 사용자 지정 인증서 구성(아래에 다시 설명)에 설명된 절차에 따라, 인증서 또는 해당 인증 기관을 모든 Gitaly 서버와 이 서버와 통신하는 모든 Praefect 클라이언트에 설치해야 합니다.

다음 사항에 유의합니다.

  • 인증서에는 Praefect 서버에 접근하는 데 사용하는 주소가 지정되어 있어야 합니다. 호스트 이름 또는 IP 주소를 주체 대체 이름(Subject Alternative Name)으로 인증서에 추가해야 합니다.

  • 명령줄에서 dial-nodes, list-untracked-repositories 같은 Praefect 하위 명령을 Gitaly TLS가 활성화된 상태로 실행할 때는 Gitaly 인증서가 신뢰되도록 SSL_CERT_DIR 또는 SSL_CERT_FILE 환경 변수를 설정해야 합니다. 예를 들면 다음과 같습니다.

    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. Gitaly 서버가 호출할 때 Praefect 서버가 인증서를 신뢰하도록, 모든 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 레코드를 통한 서비스 디스커버리를 지원하지 않습니다.

기본적으로 확인 간 최소 간격은 레코드의 TTL과 관계없이 5분입니다. Praefect는 이 간격을 사용자 지정하는 기능을 지원하지 않습니다. 클라이언트가 업데이트를 받으면 다음과 같이 동작합니다.

  • 새 IP 주소로 새 연결을 설정합니다.
  • 변경되지 않은 IP 주소에 대한 기존 연결은 유지합니다.
  • 제거된 IP 주소에 대한 연결은 끊습니다.

제거 예정인 연결에서 처리 중인 요청은 완료될 때까지 계속 처리됩니다. Workhorse에는 10분 제한 시간이 있고, 다른 클라이언트는 유예 제한 시간을 지정하지 않습니다.

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]
히스토리

TLS 암호화와 함께 서비스 디스커버리를 사용하려면 dns+tls 스킴을 사용합니다.

  • dns+tls:[host]:[port] (축약형)
  • dns+tls:///[host]:[port] (슬래시가 세 개인 점에 유의)
  • dns+tls://[authority_host]:[authority_port]/[host]:[port]

dns+tls:// 스킴은 DNS 기반 서비스 디스커버리와 TLS 암호화를 결합합니다. 이 스킴을 사용하기 전에 Praefect 서버에 TLS를 구성해야 합니다. 자세한 내용은 TLS 지원 활성화를 참고합니다.

각 Praefect 엔드포인트의 TLS 인증서에는 아래 PRAEFECT_SERVICE_DISCOVERY_ADDRESS에서 사용하는 호스트 이름과 일치하는 주체 대체 이름(SAN)이 포함되어야 합니다. 예를 들어 주소가 dns+tls:///praefect.service.consul:3305라면 각 Praefect 노드의 인증서에는 SAN 항목으로 praefect.service.consul이 있어야 합니다. SAN이 일치하지 않으면 연결이 실패합니다.

  1. 각 Praefect 노드의 IP 주소를 DNS 서비스 디스커버리 주소에 추가합니다.

  2. Praefect 클라이언트(Gitaly 서버 제외)에서 /etc/gitlab/gitlab.rb의 gitlab_rails['repositories_storages']를 다음과 같이 편집합니다. PRAEFECT_SERVICE_DISCOVERY_ADDRESS를 praefect.service.consul 같은 Praefect 서비스 디스커버리 주소로 바꿉니다.

    gitlab_rails['repositories_storages'] = {
      "default" => {
        "gitaly_address" => 'dns:PRAEFECT_SERVICE_DISCOVERY_ADDRESS:2305',
        "gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
      }
    }
    

    TLS를 사용하려면 스킴을 dns+tls://로 변경합니다.

    gitlab_rails['repositories_storages'] = {
      "default" => {
        "gitaly_address" => 'dns+tls://DNS_SERVER_ADDRESS:53/PRAEFECT_SERVICE_DISCOVERY_ADDRESS:3305',
        "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
    

    TLS를 사용하려면 스킴을 dns+tls://로 변경합니다.

    gitlab:
      repositories:
        storages:
          default:
            gitaly_address: dns+tls://DNS_SERVER_ADDRESS:53/PRAEFECT_SERVICE_DISCOVERY_ADDRESS:3305
    
  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'
    
    # The following must also be added until this issue is addressed:
    # 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#

Note

각 Gitaly 노드에서 이 단계를 완료합니다.

이 섹션을 완료하려면 다음이 필요합니다.

  • 구성된 Praefect 노드
  • GitLab이 설치되어 Gitaly 노드로 구성할 서버 3대(또는 그 이상). 이 노드는 전용 노드여야 하며, 이 노드에서 다른 서비스를 실행하지 않습니다.

Praefect 클러스터에 할당된 모든 Gitaly 서버를 구성해야 합니다. 구성은 표준 독립 실행형 Gitaly 서버와 같지만 다음이 다릅니다.

  • 스토리지 이름은 GitLab이 아닌 Praefect에 노출됩니다.
  • 시크릿 토큰은 GitLab이 아닌 Praefect와 공유됩니다.

Praefect가 작업을 올바르게 라우팅하므로, Praefect 클러스터에 속한 모든 Gitaly 노드의 구성은 동일해도 됩니다.

특히 다음 사항에 주의해야 합니다.

  • 이 섹션에서 구성하는 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-1, gitaly-2, gitaly-3을 물리 스토리지 이름으로 사용합니다.

Gitaly 서버 구성에 대한 자세한 내용은 Gitaly 문서를 참고합니다.

  1. Gitaly 노드에 SSH로 접속하여 root로 로그인합니다.

    sudo -i
    
  2. /etc/gitlab/gitlab.rb를 편집하여 다른 모든 서비스를 비활성화합니다.

    # Disable all other services on the Gitaly node
    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
    
    # Enable only the Gitaly service
    gitaly['enable'] = true
    
    # Enable Prometheus if needed
    prometheus['enable'] = true
    
    # Disable database migrations to prevent database connections during 'gitlab-ctl reconfigure'
    gitlab_rails['auto_migrate'] = false
    
  3. /etc/gitlab/gitlab.rb를 편집하여 Gitaly가 네트워크 인터페이스에서 수신 대기하도록 구성합니다.

    gitaly['configuration'] = {
       # ...
       #
       # Make Gitaly accept connections on all network interfaces.
       # Use firewalls to restrict access to this address/port.
       listen_addr: '0.0.0.0:8075',
       # Enable Prometheus metrics access to Gitaly. You must use firewalls
       # to restrict access to this address/port.
       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. git push 작업에 필요한 GitLab Shell 시크릿 토큰을 구성합니다. 다음 중 하나를 선택합니다.

    • 방법 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. git push 작업에도 필요한 internal_api_url을 구성합니다.

    # Configure the gitlab-shell API callback URL. Without this, `git push` will
    # fail. This can be your front door GitLab URL or an internal load balancer.
    # Examples: '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: [
         # Replace with appropriate name for each Gitaly node.
         {
           name: 'gitaly-1',
           path: '/var/opt/gitlab/git-data/repositories',
         },
       ],
    }
    
  8. /etc/gitlab/gitlab.rb에 변경 사항을 저장하고 Gitaly를 재구성합니다.

    gitlab-ctl reconfigure
    
  9. Gitaly가 Prometheus 수신 대기 주소를 업데이트했는지 확인하려면 Gitaly를 다시 시작합니다.

    gitlab-ctl restart gitaly
    
Note

이전 단계는 각 Gitaly 노드에서 완료해야 합니다.

모든 Gitaly 노드를 구성한 후 Praefect 연결 검사기를 실행하여 Praefect가 Praefect 구성의 모든 Gitaly 서버에 연결할 수 있는지 확인합니다.

  1. 각 Praefect 노드에 SSH로 접속하여 Praefect 연결 검사기를 실행합니다.

    sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dial-nodes
    

로드 밸런서#

내결함성을 갖춘 Gitaly 구성에서는 GitLab 애플리케이션에서 Praefect 노드로 가는 내부 트래픽을 라우팅하기 위해 로드 밸런서가 필요합니다. 어떤 로드 밸런서를 사용할지, 정확한 구성은 어떻게 할지에 대한 세부 사항은 GitLab 문서의 범위를 벗어납니다.

Note

로드 밸런서는 GitLab 노드뿐 아니라 Gitaly 노드의 트래픽도 수락하도록 구성해야 합니다.

GitLab 같은 내결함성 시스템을 운영한다면 이미 선호하는 로드 밸런서가 있을 것으로 생각합니다. 예로는 HAProxy (오픈 소스), Google Internal Load Balancer, AWS Elastic Load Balancer, F5 Big-IP LTM, Citrix Net Scaler가 있습니다. 이 문서에서는 구성해야 하는 포트와 프로토콜을 설명합니다.

클론 같은 장시간 실행 작업은 연결을 오랫동안 열어 두므로 HAProxy leastconn 부하 분산 전략에 해당하는 방식을 사용해야 합니다.

LB 포트 백엔드 포트 프로토콜
2305 2305 TCP

TCP 로드 밸런서를 사용해야 합니다. Gitaly 사이드채널 때문에 HTTP/2 또는 gRPC 로드 밸런서를 Praefect와 함께 사용하면 작동하지 않습니다. 이 최적화는 gRPC 핸드셰이크 과정을 가로챕니다. 부하가 큰 모든 Git 작업을 gRPC보다 효율적인 "채널"로 리디렉션하지만, HTTP/2 또는 gRPC 로드 밸런서는 이런 요청을 올바르게 처리하지 못합니다.

TLS가 활성화된 경우 일부 Praefect 버전은 RFC 7540에 따라 Application-Layer Protocol Negotiation(ALPN) 확장을 사용해야 합니다. TCP 로드 밸런서는 추가 구성 없이 ALPN을 그대로 전달합니다.

Mermaid 다이어그램 (12줄)
소스 코드 보기
sequenceDiagram
    autonumber
    participant Client as Client
    participant LB as TCP Load Balancer
    participant Praefect as Praefect
Client-&gt;&gt;LB: Establish TLS Session (w/ ALPN Extension)
LB-&gt;&gt;Praefect: Establish TLS Session (w/ ALPN Extension)
Client-&gt;&gt;LB: Encrypted TCP packets
LB-&gt;&gt;Praefect: Encrypted TCP packets
Praefect-&gt;&gt;LB: Encrypted Response
LB-&gt;&gt;Client: Encrypted Response</code></pre></details></div>

일부 TCP 로드 밸런서는 TLS 클라이언트 연결을 수락한 뒤 새 TLS 연결로 Praefect에 연결을 프록시하도록 구성할 수 있습니다. 그러나 이는 두 연결 모두에서 ALPN이 지원될 때만 작동합니다.

이러한 이유로 NGINX의 ngx_stream_proxy_module은 proxy_ssl 구성 옵션이 활성화되어 있으면 작동하지 않습니다.

Mermaid 다이어그램 (9줄)
소스 코드 보기
sequenceDiagram
    autonumber
    participant Client as Client
    participant NGINX as NGINX Stream Proxy
    participant Praefect as Praefect
Client-&gt;&gt;NGINX: Establish TLS Session (w/ ALPN Extension)
NGINX-&gt;&gt;Praefect: Establish New TLS Session
Praefect-&gt;&gt;NGINX: Connection failed: missing selected ALPN property</code></pre></details></div>

2단계에서는 NGINX가 이를 지원하지 않기 때문에 ALPN이 사용되지 않습니다. 자세한 내용은 NGINX 이슈 406을 참고합니다.

ALPN 강제#

일부 GitLab 버전에서는 ALPN 강제가 활성화되어 있었습니다. 그러나 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 섹션에서 설정했습니다. 이 문서에서는 Praefect 스토리지 이름으로 default를 사용합니다.
  1. GitLab 노드에 SSH로 접속하여 root로 로그인합니다.

    sudo -i
    
  2. /etc/gitlab/gitlab.rb를 편집하여 GitLab이 올바른 엔드포인트 접근으로 파일을 제공할 수 있도록 external_url을 구성합니다.

    GITLAB_SERVER_URL을 현재 GitLab 인스턴스가 서비스 중인 실제 외부 공개 URL로 바꿔야 합니다.

    external_url 'GITLAB_SERVER_URL'
    
  3. GitLab 호스트에서 실행 중인 기본 Gitaly 서비스를 비활성화합니다. GitLab이 구성된 클러스터에 연결하므로 이 서비스는 필요하지 않습니다.

    [!warning] 기본 Gitaly 스토리지에 저장된 데이터가 있다면 먼저 데이터를 Gitaly Cluster(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. git push 중 Gitaly 노드의 콜백이 올바르게 인증되도록 GitLab Shell 시크릿 토큰을 구성합니다. 다음 중 하나를 선택합니다.

    • 방법 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 훅이 GitLab에 도달할 수 있는지 확인합니다. 각 Gitaly 노드에서 다음을 실행합니다.

    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. 오른쪽 상단에서 Admin을 선택합니다.
    2. 왼쪽 사이드바에서 Settings > Repository를 선택합니다.
    3. Repository storage 섹션을 확장합니다.

    이 가이드를 따랐다면 default 스토리지는 모든 새 리포지터리를 저장하도록 가중치가 100이어야 합니다.

  11. 새 프로젝트를 만들어 모든 것이 작동하는지 확인합니다. 리포지터리에 볼 수 있는 콘텐츠가 있도록 "Initialize repository with a README" 확인란을 선택합니다. 프로젝트가 만들어지고 README 파일이 보이면 정상적으로 작동하는 것입니다.

기존 GitLab 인스턴스에서 TCP 사용#

기존 Gitaly 인스턴스에 Gitaly Cluster(Praefect)를 추가할 때, 기존 Gitaly 스토리지는 TCP/TLS로 수신 대기해야 합니다. gitaly_address를 지정하지 않으면 Unix 소켓이 사용되며, 이로 인해 클러스터와 통신할 수 없습니다.

예를 들면 다음과 같습니다.

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

여러 Gitaly 스토리지를 실행하는 방법에 대한 자세한 내용은 혼합 구성을 참고합니다.

여러 가상 스토리지 구성#

여러 가상 스토리지를 구성하여 리포지터리를 서로 다른 Gitaly Cluster(Praefect) 클러스터로 구성할 수 있습니다. 각 가상 스토리지는 자체 Gitaly 노드 집합과 복제 설정으로 독립적으로 작동합니다.

여러 가상 스토리지를 구성하려면 다음을 수행합니다.

  1. 각 Praefect 노드에서 /etc/gitlab/gitlab.rb를 편집하여 virtual_storage 배열에 여러 항목을 추가합니다.

    praefect['configuration'] = {
       # ...
       virtual_storage: [
          {
             name: 'storage-1',
             default_replication_factor: 3,
             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'
                }
             ]
          },
          {
             name: 'storage-2',
             default_replication_factor: 2,
             node: [
                {
                   storage: 'gitaly-4',
                   address: 'tcp://GITALY_HOST_4:8075',
                   token: 'PRAEFECT_INTERNAL_TOKEN'
                },
                {
                   storage: 'gitaly-5',
                   address: 'tcp://GITALY_HOST_5:8075',
                   token: 'PRAEFECT_INTERNAL_TOKEN'
                },
                {
                   storage: 'gitaly-6',
                   address: 'tcp://GITALY_HOST_6:8075',
                   token: 'PRAEFECT_INTERNAL_TOKEN'
                }
             ]
          }
       ]
    }
    
  2. 변경 사항을 저장하고 Praefect를 재구성합니다.

    gitlab-ctl reconfigure
    
  3. GitLab 서버에서 /etc/gitlab/gitlab.rb를 편집하여 두 가상 스토리지를 모두 구성합니다.

    gitlab_rails['repositories_storages'] = {
      "storage-1" => {
        "gitaly_address" => "tcp://PRAEFECT_1_LOADBALANCER_HOST:2305",
        "gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
      },
      "storage-2" => {
        "gitaly_address" => "tcp://PRAEFECT_2_LOADBALANCER_HOST:2305",
        "gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
      }
    }
    
  4. 변경 사항을 저장하고 GitLab을 재구성합니다.

    gitlab-ctl reconfigure
    
  5. 구성을 확인합니다.

    gitlab-rake gitlab:gitaly:check
    

구성 후 다음을 수행할 수 있습니다.

독립 실행형과 클러스터 스토리지 혼합 구성#

독립 실행형 Gitaly 인스턴스와 Gitaly Cluster(Praefect) 가상 스토리지를 동시에 사용하도록 GitLab을 구성할 수 있습니다. 마이그레이션 중이거나 일부 리포지터리에만 고가용성이 필요할 때 이렇게 할 수 있습니다.

혼합 설정을 구성하려면 다음을 수행합니다.

  1. 독립 실행형 Gitaly 인스턴스가 TCP에서 수신 대기하도록 구성되어 있는지 확인합니다. 독립 실행형 Gitaly 노드에서 /etc/gitlab/gitlab.rb를 편집합니다.

    gitaly['configuration'] = {
       # ...
       listen_addr: '0.0.0.0:8075'
    }
    
  2. 독립 실행형 Gitaly 인스턴스의 인증을 구성합니다.

    gitaly['configuration'] = {
       # ...
       auth: {
          token: 'GITALY_AUTH_TOKEN',
       },
    }
    
  3. 저장하고 재구성합니다.

    gitlab-ctl reconfigure
    
  4. GitLab 서버에서 /etc/gitlab/gitlab.rb를 편집하여 독립 실행형 스토리지와 클러스터 스토리지를 모두 구성합니다.

    gitlab_rails['repositories_storages'] = {
      'default' => {
        'gitaly_address' => 'tcp://STANDALONE_GITALY_HOST:8075',
        'gitaly_token' => 'GITALY_AUTH_TOKEN'
      },
      'cluster' => {
        'gitaly_address' => 'tcp://PRAEFECT_LOADBALANCER_HOST:2305',
        'gitaly_token' => 'PRAEFECT_EXTERNAL_TOKEN'
      }
    }
    
  5. 저장하고 GitLab을 재구성합니다.

    gitlab-ctl reconfigure
    
  6. 두 스토리지에 모두 접근할 수 있는지 확인합니다.

    gitlab-rake gitlab:gitaly:check
    

이 구성에서는 다음과 같이 동작합니다.

  • default 스토리지는 독립 실행형 Gitaly 노드에 직접 연결됩니다.
  • cluster 스토리지는 로드 밸런서를 통해 Gitaly Cluster(Praefect)에 연결됩니다.
  • GitLab은 두 스토리지를 동등하게 취급하며 어느 스토리지에나 리포지터리를 저장할 수 있습니다.
  • 스토리지 가중치를 구성하여 새 리포지터리에 한쪽 스토리지를 우선하도록 할 수 있습니다.

자세한 내용은 혼합 구성을 참고합니다.

Grafana#

Grafana는 GitLab에 포함되어 있으며 Praefect 클러스터를 모니터링하는 데 사용할 수 있습니다. 자세한 문서는 Grafana 대시보드 서비스를 참고합니다.

빠르게 시작하려면 다음을 수행합니다.

  1. GitLab 노드(또는 Grafana가 활성화된 노드)에 SSH로 접속하여 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. 웹 브라우저에서 GitLab 서버의 /-/grafana(예: https://gitlab.example.com/-/grafana)를 엽니다.

    설정한 비밀번호와 사용자 이름 admin으로 로그인합니다.

  6. Explore로 이동하여 gitlab_build_info를 쿼리하고 모든 머신에서 메트릭을 가져오고 있는지 확인합니다.

관측 가능한 내결함성 Praefect 클러스터 구성이 완료되었습니다.

복제 계수 구성#

Praefect는 리포지터리를 호스팅할 특정 스토리지 노드를 할당하는 방식으로 리포지터리별 복제 계수를 구성할 수 있도록 지원합니다.

Warning

오브젝트 풀, 포크된 적이 있는 모든 리포지터리, 또는 포크 자체의 복제 계수를 줄이지 않습니다. 그러면 전체 포크 네트워크가 손상될 수 있습니다. 오브젝트 풀의 상대 경로는 @pools/로 시작합니다. 리포지터리가 포크되었는지는 GitLab UI에서 확인할 수 있습니다.

Praefect는 실제 복제 계수를 저장하지 않고, 원하는 복제 계수를 충족하도록 리포지터리를 호스팅할 충분한 스토리지를 할당합니다. 이후 스토리지 노드가 가상 스토리지에서 제거되면 해당 스토리지에 할당된 리포지터리의 복제 계수도 그에 맞게 줄어듭니다.

다음 중 하나를 구성할 수 있습니다.

  • 새로 만든 리포지터리에 적용되는 가상 스토리지별 기본 복제 계수
  • set-replication-factor 하위 명령을 사용한 기존 리포지터리의 복제 계수

기본 복제 계수 구성#

Warning

오브젝트 풀이 있을 때 기본 복제를 줄이면 연결된 일부 리포지터리가 손상될 수 있습니다. 오브젝트 풀의 상대 경로는 @pools/로 시작합니다.

default_replication_factor를 설정하지 않으면 리포지터리는 항상 virtual_storages에 정의된 모든 스토리지 노드에 복제됩니다. 가상 스토리지에 새 스토리지 노드가 추가되면 새 리포지터리와 기존 리포지터리 모두 해당 노드로 자동으로 복제됩니다.

스토리지 노드가 많은 대규모 Gitaly Cluster(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> -relative-path <relative-path> -replication-factor <replication-factor>
  • -virtual-storage는 리포지터리가 위치한 가상 스토리지입니다.
  • -relative-path는 스토리지에서 리포지터리의 상대 경로입니다.
  • -replication-factor는 리포지터리에 원하는 복제 계수입니다. 기본 노드에 리포지터리 사본이 필요하므로 최솟값은 1입니다. 최대 복제 계수는 가상 스토리지에 있는 스토리지 수입니다.

성공하면 할당된 호스트 스토리지가 출력됩니다. 예를 들면 다음과 같습니다.

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

current assignments: gitaly-1, gitaly-2

리포지터리 스토리지 권장 사항#

필요한 스토리지 크기는 인스턴스마다 다를 수 있으며 설정한 복제 계수에 따라 달라집니다. 리포지터리 스토리지 이중화 구현을 포함하는 것이 좋을 수 있습니다.

복제 계수가 다음과 같은 경우입니다.

  • 1인 경우: Gitaly와 Gitaly Cluster(Praefect)의 스토리지 요구 사항은 대략 같습니다.
  • 1보다 큰 경우: 필요한 스토리지 양은 used space * replication factor입니다. used space에는 향후 계획된 증가분이 포함되어야 합니다.

리포지터리 검증#

Praefect는 리포지터리에 대한 메타데이터를 데이터베이스에 저장합니다. Praefect를 거치지 않고 디스크에서 리포지터리가 수정되면 메타데이터가 부정확해질 수 있습니다. 예를 들어 Gitaly 노드를 새 노드로 교체하지 않고 재구축한 경우, 리포지터리 검증을 통해 이를 감지할 수 있습니다.

메타데이터는 복제와 라우팅 결정에 사용되므로 부정확한 내용이 있으면 문제가 발생할 수 있습니다. Praefect에는 디스크의 실제 상태와 메타데이터를 주기적으로 대조하여 검증하는 백그라운드 워커가 있습니다. 이 워커는 다음과 같이 동작합니다.

  1. 정상 스토리지에서 검증할 복제본을 일괄로 가져옵니다. 복제본은 검증되지 않았거나 구성된 검증 간격을 초과한 것입니다. 한 번도 검증되지 않은 복제본이 우선이고, 그다음은 마지막 검증 성공 이후 시간이 가장 오래된 순서로 나머지 복제본을 처리합니다.
  2. 각 복제본이 해당 스토리지에 존재하는지 확인합니다. 결과가 다음과 같은 경우:
    • 복제본이 존재하면 마지막 검증 성공 시간을 업데이트합니다.
    • 복제본이 존재하지 않으면 해당 메타데이터 레코드를 제거합니다.
    • 확인에 실패하면 다음 워커가 작업을 더 가져올 때 해당 복제본이 다시 검증 대상으로 선택됩니다.

워커는 검증하려는 각 복제본에 대해 배타적 검증 리스를 획득합니다. 이렇게 하면 여러 워커가 동일한 복제본을 동시에 검증하는 것을 방지합니다. 워커는 확인을 마치면 리스를 해제합니다. 워커가 리스를 해제하지 못한 채 어떤 이유로 종료되면, Praefect의 백그라운드 고루틴이 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"
      ]
    }
  }
}

검증 워커 구성#

워커는 기본적으로 활성화되어 있으며 7일마다 메타데이터 레코드를 검증합니다. 검증 간격은 유효한 Go duration 문자열로 구성할 수 있습니다.

메타데이터를 3일마다 검증하려면 다음과 같이 구성합니다.

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

0 이하의 값은 백그라운드 검증기를 비활성화합니다.

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

삭제 활성화#

기본적으로 워커는 잘못된 메타데이터 레코드를 삭제합니다. 또한 삭제된 레코드를 로그로 남기고 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 Cluster(Praefect)는 리포지터리마다 별도로 기본 Gitaly 노드를 선출합니다. 구성 가능한 복제 계수와 함께 사용하면 스토리지 용량을 수평으로 확장하고 쓰기 부하를 Gitaly 노드 전반에 분산할 수 있습니다.

기본 노드 선출은 지연 방식으로 실행됩니다. 현재 기본 노드가 비정상이더라도 Praefect는 새 기본 노드를 즉시 선출하지 않습니다. 현재 기본 노드를 사용할 수 없는 상태에서 요청을 처리해야 할 때 새 기본 노드가 선출됩니다.

유효한 기본 노드 후보는 다음 조건을 충족하는 Gitaly 노드입니다.

  • 정상입니다. Praefect 노드의 >=50%가 이전 10초 동안 해당 Gitaly 노드의 상태 확인에 성공하면 Gitaly 노드가 정상으로 간주됩니다.
  • 리포지터리의 완전히 최신인 사본이 있습니다.

기본 노드 후보가 여러 개이면 Praefect는 다음과 같이 처리합니다.

  • 그중 하나를 무작위로 선택합니다.
  • 리포지터리를 호스팅하도록 할당된 Gitaly 노드의 승격을 우선합니다. 기본 노드로 선출할 할당된 Gitaly 노드가 없으면 Praefect가 할당되지 않은 노드를 일시적으로 선출할 수 있습니다. 할당된 노드를 사용할 수 있게 되면 할당되지 않은 기본 노드는 강등되고 할당된 노드가 그 자리를 대신합니다.

리포지터리에 유효한 기본 노드 후보가 없으면 다음과 같이 됩니다.

  • 비정상 기본 노드는 강등되고 리포지터리에는 기본 노드가 없는 상태가 됩니다.
  • 기본 노드가 필요한 작업은 기본 노드가 성공적으로 선출될 때까지 실패합니다.

Gitaly Cluster(Praefect) 구성

GitLab v19.5
원문 보기

요약

다음 중 하나를 사용하여 Gitaly Cluster(Praefect)를 구성합니다. 소규모 GitLab 설치에는 Gitaly 자체만 필요할 수 있습니다. Gitaly Cluster(Praefect)는 아직 Kubernetes, Amazon ECS 또는 이와 유사한 컨테이너 환경에서 지원되지 않습니다.

다음 중 하나를 사용하여 Gitaly Cluster(Praefect)를 구성합니다.

소규모 GitLab 설치에는 Gitaly 자체만 필요할 수 있습니다.

Note

Gitaly Cluster(Praefect)는 아직 Kubernetes, Amazon ECS 또는 이와 유사한 컨테이너 환경에서 지원되지 않습니다. 자세한 내용은 에픽 6127을 참고합니다.

요구 사항#

Gitaly Cluster(Praefect)의 최소 권장 구성에는 다음이 필요합니다.

  • 로드 밸런서 1대
  • PostgreSQL 서버 1대(지원되는 버전)
  • Praefect 노드 3대
  • Gitaly 노드 3대(기본 1대, 보조 2대)
Note

디스크 요구 사항은 Gitaly 노드에 적용됩니다.

Gitaly 노드 중 하나가 변경 RPC 호출 중에 실패하더라도 트랜잭션에 결정권을 가진 표가 남도록, Gitaly 노드는 홀수 개로 구성해야 합니다.

구현 세부 사항은 설계 문서를 참고합니다.

Note

GitLab에서 기능 플래그를 설정하지 않으면 콘솔에서는 false로 읽히고, Praefect는 해당 플래그의 기본값을 사용합니다. 기본값은 GitLab 버전에 따라 다릅니다.

네트워크 지연 시간과 연결#

Gitaly Cluster(Praefect)의 네트워크 지연 시간은 이상적으로 한 자릿수 밀리초 단위로 측정될 수 있어야 합니다. 지연 시간은 특히 다음 경우에 중요합니다.

  • Gitaly 노드 상태 확인. 노드는 1초 이내에 응답할 수 있어야 합니다.
  • 강한 일관성을 강제하는 참조 트랜잭션. 지연 시간이 낮을수록 Gitaly 노드가 변경 사항에 더 빠르게 합의할 수 있습니다.

Gitaly 노드 간에 허용 가능한 지연 시간을 확보하는 방법은 다음과 같습니다.

  • 물리 네트워크에서는 일반적으로 대역폭이 높은 단일 위치 연결을 의미합니다.
  • 클라우드에서는 일반적으로 가용 영역 간 복제를 허용하는 것을 포함해 같은 리전 안에 두는 것을 의미합니다. 이러한 링크는 이런 유형의 동기화를 위해 설계되었습니다. Gitaly Cluster(Praefect)에는 2ms 미만의 지연 시간이면 충분합니다.

복제를 위한 낮은 네트워크 지연 시간을 제공할 수 없는 경우(예: 멀리 떨어진 위치 사이) Geo를 고려합니다. 자세한 내용은 Geo와의 비교를 참고합니다.

Gitaly Cluster(Praefect)의 구성 요소는 여러 경로로 서로 통신합니다. Gitaly Cluster(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
Note

Gitaly는 Praefect에 직접 연결하지 않습니다. 그러나 Praefect 노드의 방화벽이 Gitaly 노드의 트래픽을 허용하지 않으면 Gitaly에서 Praefect 로드 밸런서로 가는 요청이 여전히 차단될 수 있습니다.

Praefect 데이터베이스 스토리지#

데이터베이스에는 다음 메타데이터만 들어 있으므로 요구 사항이 비교적 낮습니다.

  • 리포지터리가 위치한 곳
  • 대기열에 있는 일부 작업

리포지터리 수에 따라 다르지만, 메인 GitLab 애플리케이션 데이터베이스와 마찬가지로 최소 5-10GB가 적절합니다.

설정 지침#

Linux 패키지를 사용하여 GitLab을 설치한 경우(강력히 권장), 다음 단계를 따릅니다.

  1. 준비
  2. Praefect 데이터베이스 구성
  3. Praefect 프록시/라우터 구성
  4. 각 Gitaly 노드 구성(Gitaly 노드마다 한 번씩)
  5. 로드 밸런서 구성
  6. GitLab 서버 구성 업데이트
  7. Grafana 구성

준비#

시작하기 전에 이미 작동하는 GitLab 인스턴스가 있어야 합니다. GitLab 설치 방법을 참고합니다.

PostgreSQL 서버를 프로비저닝합니다. Linux 패키지에 포함된 PostgreSQL을 사용하여 PostgreSQL 데이터베이스를 구성하는 것을 권장합니다. 외부 PostgreSQL 서버를 사용할 수도 있지만 수동으로 설정해야 합니다.

모든 새 노드에 GitLab을 설치하여 준비합니다. 다음이 필요합니다.

  • PostgreSQL 노드 1대
  • PgBouncer 노드 1대(선택 사항)
  • Praefect 노드 최소 1대(필요한 스토리지 최소)
  • Gitaly 노드 3대(높은 CPU, 높은 메모리, 빠른 스토리지)
  • GitLab 서버 1대

각 노드의 IP/호스트 주소도 필요합니다.

  1. PRAEFECT_LOADBALANCER_HOST: Praefect 로드 밸런서의 IP/호스트 주소
  2. POSTGRESQL_HOST: PostgreSQL 서버의 IP/호스트 주소
  3. PGBOUNCER_HOST: PostgreSQL 서버의 IP/호스트 주소
  4. PRAEFECT_HOST: Praefect 서버의 IP/호스트 주소
  5. GITALY_HOST_*: 각 Gitaly 서버의 IP 또는 호스트 주소
  6. GITLAB_HOST: GitLab 서버의 IP/호스트 주소

Google Cloud Platform, SoftLayer 또는 가상 사설 클라우드(VPC)를 제공하는 다른 공급업체를 사용하는 경우, PRAEFECT_HOST, GITALY_HOST_*, GITLAB_HOST에 각 클라우드 인스턴스의 사설 주소(Google Cloud Platform의 "내부 주소"에 해당)를 사용할 수 있습니다.

시크릿#

구성 요소 간 통신은 서로 다른 시크릿으로 보호되며, 아래에 설명되어 있습니다. 시작하기 전에 각 항목에 고유한 시크릿을 생성하고 기록해 둡니다. 이렇게 하면 설정 과정을 완료하면서 자리 표시자 토큰을 안전한 토큰으로 교체할 수 있습니다.

  1. GITLAB_SHELL_SECRET_TOKEN: Git 훅이 Git 푸시를 수락할 때 GitLab에 콜백 HTTP API 요청을 보내는 데 사용합니다. 이 시크릿은 기존 방식과의 호환을 위해 GitLab Shell과 공유됩니다.
  2. PRAEFECT_EXTERNAL_TOKEN: Praefect 클러스터에 호스팅된 리포지터리는 이 토큰을 가진 Gitaly 클라이언트만 접근할 수 있습니다.
  3. PRAEFECT_INTERNAL_TOKEN: Praefect 클러스터 내부의 복제 트래픽에 사용하는 토큰입니다. Gitaly 클라이언트가 Praefect 클러스터의 내부 노드에 직접 접근해서는 안 되고, 접근하면 데이터 손실로 이어질 수 있으므로 이 토큰은 PRAEFECT_EXTERNAL_TOKEN과 구분됩니다.
  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 문서를 참고합니다.

아래 지침에서 이러한 시크릿이 필요한 위치를 표시합니다.

Note

Linux 패키지 설치는 GITLAB_SHELL_SECRET_TOKEN에 gitlab-secrets.json을 사용할 수 있습니다.

시간 서버 설정 사용자 지정#

기본적으로 Gitaly 노드와 Praefect 노드는 시간 동기화 확인에 pool.ntp.org의 시간 서버를 사용합니다. 각 노드의 gitlab.rb에 다음을 추가하여 이 설정을 사용자 지정할 수 있습니다.

  • Gitaly 노드: gitaly['env'] = { "NTP_HOST" => "ntp.example.com" }
  • Praefect 노드: praefect['env'] = { "NTP_HOST" => "ntp.example.com" }

PostgreSQL#

Note

Praefect는 GitLab 애플리케이션 데이터베이스와 별개의 데이터베이스를 사용하여 Gitaly 리포지터리 복제 상태를 관리합니다. Geo와 Gitaly Cluster(Praefect)를 함께 사용하면 Praefect 복제 상태는 각 사이트마다 고유합니다. 각 Geo 사이트에는 Praefect 데이터베이스를 담을 별도의 읽기-쓰기 PostgreSQL 데이터베이스 인스턴스가 있어야 합니다.

  • GitLab 애플리케이션 데이터베이스와 Praefect 데이터베이스를 같은 PostgreSQL 서버에 저장하지 않습니다.
  • Geo 기본 사이트의 Praefect Postgres 데이터베이스가 Geo 보조 사이트로 복제되도록 구성하지 않습니다.

이 지침은 단일 장애 지점이 되는 단일 PostgreSQL 데이터베이스를 설정하는 방법을 안내합니다. 이를 피하려면 자체 클러스터형 PostgreSQL을 구성할 수 있습니다. 다른 데이터베이스(예: Praefect 및 Geo 데이터베이스)에 대한 클러스터형 데이터베이스 지원은 이슈 7292에서 제안되어 있습니다.

다음 옵션을 사용할 수 있습니다.

  • Geo를 사용하지 않는 설치의 경우 다음 중 하나를 선택합니다.
    • 문서화된 PostgreSQL 설정 중 하나를 사용합니다.
    • 자체 서드 파티 데이터베이스 설정을 사용합니다. 이 경우 수동 설정이 필요합니다.
  • Geo 인스턴스의 경우 다음 중 하나를 선택합니다.

PostgreSQL을 설정하면 비어 있는 Praefect 테이블이 생성됩니다. 자세한 내용은 관련 문제 해결 섹션을 참고합니다.

같은 서버에서 GitLab 및 Praefect 데이터베이스 실행#

GitLab 애플리케이션 데이터베이스와 Praefect 데이터베이스는 같은 서버에서 실행할 수 있습니다. 그러나 Linux 패키지의 PostgreSQL을 사용하는 경우 Praefect에는 자체 데이터베이스 서버를 두어야 합니다. 장애 조치가 발생하면 Praefect는 이를 인식하지 못하고, 사용하려는 데이터베이스가 다음 상태가 되어 실패하기 시작합니다.

  • 사용할 수 없음
  • 읽기 전용 모드

수동 데이터베이스 설정#

이 섹션을 완료하려면 다음이 필요합니다.

  • Praefect 노드 1대
  • PostgreSQL 노드 1대
    • 데이터베이스 서버를 관리할 권한이 있는 PostgreSQL 사용자

이 섹션에서는 PostgreSQL 데이터베이스를 구성합니다. 이 방법은 외부 PostgreSQL 서버와 Linux 패키지에서 제공하는 PostgreSQL 서버 모두에 사용할 수 있습니다.

다음 지침을 실행하려면 Linux 패키지가 psql을 설치해 둔 Praefect 노드(/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';
    

    를 준비 단계에서 생성한 비밀번호의 해시로 바꿉니다. 앞에 md5 리터럴이 붙습니다.

  2. PgBouncer가 사용할 새 사용자 pgbouncer를 만듭니다.

    CREATE ROLE pgbouncer WITH LOGIN;
    ALTER USER pgbouncer WITH password 'md5';
    

    PGBOUNCER_SQL_PASSWORD_HASH를 준비 단계에서 생성한 강력한 비밀번호 해시로 바꿉니다.

  3. pg_shadow_lookup 함수를 praefect_production 데이터베이스에 생성합니다.

이제 Praefect가 사용하는 데이터베이스가 구성되었습니다.

이제 Praefect가 이 데이터베이스를 사용하도록 구성할 수 있습니다.

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

PostgreSQL을 구성한 후 Praefect 데이터베이스 오류가 표시되면 문제 해결 단계를 참고합니다.

자체 관리 Patroni 클러스터로 자동 장애 조치 구성#

수동 데이터베이스 설정을 완료한 후, Patroni와 같은 장애 조치 도구가 관리하는 PostgreSQL 클러스터를 Praefect가 직접 가리키도록 할 수 있습니다. Praefect는 pgx를 사용하여 PostgreSQL에 연결하며, pgx는 libpq와 동일한 다중 호스트 연결 동작을 지원합니다. Praefect는 주소 목록의 모든 호스트를 확인하여 현재 쓰기를 수락하는 호스트에 연결하고, 장애 조치 후에는 자동으로 다시 연결합니다.

이 구성에서는 PostgreSQL 클러스터 앞에 프록시를 두지 않습니다. 이 클라이언트 측 장애 조치 감지는 GitLab 애플리케이션 데이터베이스에 사용하는 설정과 다릅니다. 해당 설정에서는 PgBouncer나 Consul 기반 라우팅 같은 프록시가 클러스터 앞에 위치하여 자체적으로 서버 측 전환을 수행합니다. 두 방식을 결합하면 프록시가 개별 클러스터 노드를 Praefect로부터 숨기므로 pgx가 각 노드를 직접 확인할 수 없게 되거나, 프록시 자체의 장애 조치가 Praefect의 클라이언트 측 감지와 경합하게 됩니다.

GitLab은 이 구성을 GitLab.com 또는 Dedicated 환경에 배포하거나 테스트하지 않았습니다. 이 구성에 의존하기 전에 비프로덕션 환경에서 철저히 검증해야 합니다.

Warning

클러스터가 동기식 복제를 사용하도록 구성합니다. 비동기식 복제를 사용하면 기본 노드를 잃는 장애 조치에서 커밋되었지만 아직 복제되지 않은 트랜잭션도 손실될 수 있으며, 이로 인해 Praefect 데이터베이스가 Gitaly가 예상하지 못하는 상태가 될 수 있습니다.

사전 요구 사항:

  • 클러스터에 대해 수동 데이터베이스 설정을 완료했습니다.
  • Patroni 또는 새 기본 노드를 자동으로 승격하는 동등한 도구가 관리하는 PostgreSQL 클러스터가 Praefect 데이터베이스 전용 서버에 있고, 동기식 복제로 구성되어 있습니다. 이 클러스터는 GitLab 애플리케이션 데이터베이스에 사용하는 것과 동일한 Patroni, Consul, PostgreSQL 구성 요소를 별도의 노드 집합에 구성하여 구축할 수 있습니다.
  • Praefect 노드에서 클러스터의 모든 노드로의 네트워크 접근

Praefect를 구성하려면 다음을 수행합니다.

  1. Praefect 구성에서 database.host를 클러스터 노드 주소의 쉼표로 구분된 목록으로 설정하고, database.port를 모든 노드가 공유하는 포트로 설정합니다.

    praefect['configuration'] = {
       # ...
       database: {
          # ...
          host: 'POSTGRESQL_HOST_1,POSTGRESQL_HOST_2,POSTGRESQL_HOST_3',
          port: 5432,
          user: 'praefect',
          password: PRAEFECT_SQL_PASSWORD,
          dbname: 'praefect_production',
       }
    }
    
  2. Praefect 프로세스가 현재 기본 노드에 연결되도록 PGTARGETSESSIONATTRS 환경 변수를 read-write로 설정합니다. Praefect 구성에는 PGTARGETSESSIONATTRS 전용 설정이 없으므로 Praefect 환경을 통해 변수를 설정합니다. Praefect의 기존 기본 환경 변수가 제거되지 않도록 env 해시 전체를 할당하지 말고 키를 직접 설정합니다.

    praefect['env']['PGTARGETSESSIONATTRS'] = 'read-write'
    
  3. 변경 사항이 적용되도록 재구성합니다.

    gitlab-ctl reconfigure
    

이 구성은 Praefect와 PostgreSQL 사이의 직접 연결만 다룹니다. PgBouncer를 사용하도록 session_pooled 설정도 구성하는 경우 PgBouncer의 고가용성은 별도로 확보해야 합니다. session_pooled 설정은 호스트를 하나만 허용하므로 PgBouncer 연결은 이 장애 조치 메커니즘에 참여하지 않습니다.

읽기 분산 캐싱#

추가로 session_pooled 설정을 구성하면 Praefect 성능을 개선할 수 있습니다.

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

         # Use the following to override parameters of direct database connection.
         # Comment out where the parameters are the same for both connections.
         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를 설정하고 구성하는 것이 좋습니다. 그러나 PgBouncer는 필수가 아닙니다. Praefect는 연결 수가 적기 때문입니다. 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에는 LISTEN 기능을 지원하는 PostgreSQL에 대한 추가 연결이 필요합니다. PgBouncer에서 이 기능은 session 풀 모드(pool_mode = session)에서만 사용할 수 있습니다. transaction 풀 모드(pool_mode = transaction)에서는 지원되지 않습니다.

추가 연결을 구성하려면 다음 중 하나를 수행해야 합니다.

  • 동일한 PostgreSQL 데이터베이스 엔드포인트에 연결하되 풀 모드가 다른(pool_mode = session) 새 PgBouncer 데이터베이스를 구성합니다.
  • PgBouncer를 우회하여 Praefect를 PostgreSQL에 직접 연결합니다.
pool_mode = session으로 새 PgBouncer 데이터베이스 구성#

PgBouncer는 session 풀 모드로 사용해야 합니다. 번들 PgBouncer를 사용하거나 외부 PgBouncer를 사용하여 수동으로 구성할 수 있습니다.

다음 예시는 번들 PgBouncer를 사용하며, PostgreSQL 호스트에 session 풀 모드와 transaction 풀 모드 각각의 연결 풀을 별도로 두 개 설정합니다. 이 예시가 작동하려면 설정 지침에 설명된 대로 PostgreSQL 서버를 준비해야 합니다.

그런 다음 PgBouncer 호스트에서 별도의 연결 풀을 구성합니다.

pgbouncer['databases'] = {
  # Other database configuration including gitlabhq_production
  ...

  praefect_production: {
    host: POSTGRESQL_HOST,
    # Use `pgbouncer` user to connect to database backend.
    user: 'pgbouncer',
    password: PGBOUNCER_SQL_PASSWORD_HASH,
    pool_mode: 'transaction'
  },
  praefect_production_direct: {
    host: POSTGRESQL_HOST,
    # Use `pgbouncer` user to connect to database backend.
    user: 'pgbouncer',
    password: PGBOUNCER_SQL_PASSWORD_HASH,
    dbname: 'praefect_production',
    pool_mode: 'session'
  },

  ...
}

# Allow the praefect user to connect to PgBouncer
pgbouncer['users'] = {
  'praefect': {
    'password': PRAEFECT_SQL_PASSWORD_HASH,
  }
}

praefect_production과 praefect_production_direct는 같은 데이터베이스 엔드포인트 (praefect_production)를 사용하지만 풀 모드가 다릅니다. 이는 PgBouncer의 다음 databases 섹션으로 변환됩니다.

[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

이제 두 연결 모두에 PgBouncer를 사용하도록 Praefect를 구성할 수 있습니다.

praefect['configuration'] = {
   # ...
   database: {
      # ...
      host: PGBOUNCER_HOST,
      port: 6432,
      user: 'praefect',
      # `PRAEFECT_SQL_PASSWORD` is the plain-text password of
      # Praefect user. Not to be confused with `PRAEFECT_SQL_PASSWORD_HASH`.
      password: PRAEFECT_SQL_PASSWORD,
      dbname: 'praefect_production',
      session_pooled: {
         # ...
         dbname: 'praefect_production_direct',
         # There is no need to repeat the following. Parameters of direct
         # database connection will fall back to the values specified in the
         # database block.
         #
         # host: PGBOUNCER_HOST,
         # port: 6432,
         # user: 'praefect',
         # password: PRAEFECT_SQL_PASSWORD,
      },
   },
}

이 구성에서 Praefect는 두 연결 유형 모두에 PgBouncer를 사용합니다.

Note

Linux 패키지 설치는 (auth_query를 사용하여) 인증 요구 사항을 처리합니다. 다만 데이터베이스를 수동으로 준비하고 외부 PgBouncer를 구성하는 경우, PgBouncer가 사용하는 파일에 praefect 사용자와 해당 비밀번호를 포함해야 합니다. 예를 들어 auth_file 구성 옵션이 설정되어 있다면 userlist.txt입니다. 자세한 내용은 PgBouncer 문서를 참고합니다.

PostgreSQL에 직접 연결하도록 Praefect 구성#

session 풀 모드로 PgBouncer를 구성하는 대신, PostgreSQL에 직접 접근할 때 사용할 서로 다른 연결 매개변수를 Praefect에 구성할 수 있습니다. 이 연결은 LISTEN 기능을 지원합니다.

PgBouncer를 우회하여 PostgreSQL에 직접 연결하는 Praefect 구성 예시는 다음과 같습니다.

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

         # Use the following to override parameters of direct database connection.
         # Comment out where the parameters are the same for both connections.
         #
         user: 'praefect',
         password: PRAEFECT_SQL_PASSWORD,
         dbname: 'praefect_production',
         # sslmode: '...',
         # sslcert: '...',
         # sslkey: '...',
         # sslrootcert: '...',
      },
   },
}

Praefect#

Praefect를 구성하기 전에 Praefect 구성 파일 예시를 참고하여 익혀 둡니다. Linux 패키지를 사용하여 GitLab을 설치한 경우, 예시 파일의 설정을 Ruby로 변환해야 합니다.

Praefect 노드가 여러 개인 경우 다음을 수행합니다.

  1. 노드 하나를 배포 노드로 지정하고, 다음 단계를 사용하여 구성합니다.
  2. 나머지 각 노드에서 다음 단계를 완료합니다.

이 섹션을 완료하려면 다음을 포함하는 구성된 PostgreSQL 서버가 필요합니다.

Warning

Praefect는 전용 노드에서 실행해야 합니다. 애플리케이션 서버나 Gitaly 노드에서 Praefect를 실행하지 않습니다.

Praefect 노드에서 다음을 수행합니다.

  1. /etc/gitlab/gitlab.rb를 편집하여 다른 모든 서비스를 비활성화합니다.
# Avoid running unnecessary services on the Praefect server
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

# Enable only the Praefect service
praefect['enable'] = true

# Prevent database migrations from running on upgrade automatically
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'] = {
       # ...
       #
       # Enable Prometheus metrics access to Praefect. You must use firewalls
       # to restrict access to this address/port.
       # The default metrics endpoint is /metrics
       prometheus_listen_addr: '0.0.0.0:9652',
       # Some metrics run queries against the database. Enabling separate database metrics allows
       # these metrics to be collected when the metrics are
       # scraped on a separate /db_metrics endpoint.
       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: {
          # ...
          #
          # Connect to PostgreSQL using a TLS client certificate
          # sslcert: '/path/to/client-cert',
          # sslkey: '/path/to/client-key',
          #
          # Trust a custom certificate authority
          # sslrootcert: '/path/to/rootcert',
       },
    }
    

    기본적으로 Praefect는 기회적 TLS(opportunistic TLS)를 사용하여 PostgreSQL에 연결합니다. 즉, Praefect는 sslmode를 prefer로 설정하여 PostgreSQL에 연결을 시도합니다. 다음 줄의 주석을 해제하여 이를 재정의할 수 있습니다.

    praefect['configuration'] = {
       # ...
       database: {
          # ...
          # sslmode: 'disable',
       },
    }
    
  5. /etc/gitlab/gitlab.rb를 편집하여 Praefect 클러스터가 클러스터의 각 Gitaly 노드에 연결하도록 구성합니다.

    가상 스토리지의 이름은 GitLab 구성의 스토리지 이름과 일치해야 합니다. 이후 단계에서 스토리지 이름을 default로 구성하므로 여기서도 default를 사용합니다. 이 클러스터에는 세 개의 Gitaly 노드 gitaly-1, gitaly-2, gitaly-3이 있으며, 이들은 서로의 복제본으로 사용됩니다.

    [!warning] 이미 default라는 이름의 스토리지에 데이터가 있다면, 가상 스토리지를 다른 이름으로 구성하고 이후에 데이터를 Gitaly Cluster(Praefect) 스토리지로 마이그레이션해야 합니다.

    PRAEFECT_INTERNAL_TOKEN을 강력한 시크릿으로 바꿉니다. 이 시크릿은 Praefect가 클러스터의 Gitaly 노드와 통신할 때 사용합니다. 이 토큰은 PRAEFECT_EXTERNAL_TOKEN과 구분됩니다.

    GITALY_HOST_*를 각 Gitaly 노드의 IP 또는 호스트 주소로 바꿉니다.

    복제본 수를 늘리려면 클러스터에 Gitaly 노드를 더 추가할 수 있습니다. 규모가 매우 큰 GitLab 인스턴스에는 클러스터를 더 추가할 수도 있습니다.

    [!note] 가상 스토리지에 Gitaly 노드를 추가할 때는 해당 가상 스토리지의 모든 스토리지 이름이 고유해야 합니다. 또한 Praefect 구성에서 참조하는 모든 Gitaly 노드 주소도 고유해야 합니다.

    # Name of storage hash must match storage name in gitlab_rails['repositories_storages'] on GitLab
    # server ('default') and in gitaly['configuration'][:storage][INDEX][:name] on Gitaly nodes ('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'
                },
             ],
          },
       ],
    }
    
  6. /etc/gitlab/gitlab.rb에 변경 사항을 저장하고 Praefect를 재구성합니다.

    gitlab-ctl reconfigure
    
  7. 다음 노드별로 수행합니다.

    • "배포 노드"의 경우:

      1. /etc/gitlab/gitlab.rb에서 praefect['auto_migrate'] = true로 설정하여 Praefect 데이터베이스 자동 마이그레이션을 다시 활성화합니다.

      2. 데이터베이스 마이그레이션이 업그레이드 시 자동으로 실행되지 않고 재구성 중에만 실행되도록 다음을 실행합니다.

        sudo touch /etc/gitlab/skip-auto-reconfigure
        
    • 나머지 노드의 경우 설정을 그대로 두어도 됩니다. /etc/gitlab/skip-auto-reconfigure는 필수가 아니지만, apt-get update 같은 명령을 실행할 때 GitLab이 재구성을 자동으로 실행하지 않도록 이 파일을 설정할 수 있습니다. 이렇게 하면 추가 구성 변경을 마친 뒤 재구성을 수동으로 실행할 수 있습니다.

  8. /etc/gitlab/gitlab.rb에 변경 사항을 저장하고 Praefect를 재구성합니다.

    gitlab-ctl reconfigure
    
  9. Praefect가 Prometheus 수신 대기 주소를 업데이트했는지 확인하려면 Praefect를 다시 시작합니다.

    gitlab-ctl restart praefect
    
  10. 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 서버에 해당하는 인증서를 그 Praefect 서버에 설치해야 합니다.

또한 GitLab 사용자 지정 인증서 구성(아래에 다시 설명)에 설명된 절차에 따라, 인증서 또는 해당 인증 기관을 모든 Gitaly 서버와 이 서버와 통신하는 모든 Praefect 클라이언트에 설치해야 합니다.

다음 사항에 유의합니다.

  • 인증서에는 Praefect 서버에 접근하는 데 사용하는 주소가 지정되어 있어야 합니다. 호스트 이름 또는 IP 주소를 주체 대체 이름(Subject Alternative Name)으로 인증서에 추가해야 합니다.

  • 명령줄에서 dial-nodes, list-untracked-repositories 같은 Praefect 하위 명령을 Gitaly TLS가 활성화된 상태로 실행할 때는 Gitaly 인증서가 신뢰되도록 SSL_CERT_DIR 또는 SSL_CERT_FILE 환경 변수를 설정해야 합니다. 예를 들면 다음과 같습니다.

    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. Gitaly 서버가 호출할 때 Praefect 서버가 인증서를 신뢰하도록, 모든 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 레코드를 통한 서비스 디스커버리를 지원하지 않습니다.

기본적으로 확인 간 최소 간격은 레코드의 TTL과 관계없이 5분입니다. Praefect는 이 간격을 사용자 지정하는 기능을 지원하지 않습니다. 클라이언트가 업데이트를 받으면 다음과 같이 동작합니다.

  • 새 IP 주소로 새 연결을 설정합니다.
  • 변경되지 않은 IP 주소에 대한 기존 연결은 유지합니다.
  • 제거된 IP 주소에 대한 연결은 끊습니다.

제거 예정인 연결에서 처리 중인 요청은 완료될 때까지 계속 처리됩니다. Workhorse에는 10분 제한 시간이 있고, 다른 클라이언트는 유예 제한 시간을 지정하지 않습니다.

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]
히스토리

TLS 암호화와 함께 서비스 디스커버리를 사용하려면 dns+tls 스킴을 사용합니다.

  • dns+tls:[host]:[port] (축약형)
  • dns+tls:///[host]:[port] (슬래시가 세 개인 점에 유의)
  • dns+tls://[authority_host]:[authority_port]/[host]:[port]

dns+tls:// 스킴은 DNS 기반 서비스 디스커버리와 TLS 암호화를 결합합니다. 이 스킴을 사용하기 전에 Praefect 서버에 TLS를 구성해야 합니다. 자세한 내용은 TLS 지원 활성화를 참고합니다.

각 Praefect 엔드포인트의 TLS 인증서에는 아래 PRAEFECT_SERVICE_DISCOVERY_ADDRESS에서 사용하는 호스트 이름과 일치하는 주체 대체 이름(SAN)이 포함되어야 합니다. 예를 들어 주소가 dns+tls:///praefect.service.consul:3305라면 각 Praefect 노드의 인증서에는 SAN 항목으로 praefect.service.consul이 있어야 합니다. SAN이 일치하지 않으면 연결이 실패합니다.

  1. 각 Praefect 노드의 IP 주소를 DNS 서비스 디스커버리 주소에 추가합니다.

  2. Praefect 클라이언트(Gitaly 서버 제외)에서 /etc/gitlab/gitlab.rb의 gitlab_rails['repositories_storages']를 다음과 같이 편집합니다. PRAEFECT_SERVICE_DISCOVERY_ADDRESS를 praefect.service.consul 같은 Praefect 서비스 디스커버리 주소로 바꿉니다.

    gitlab_rails['repositories_storages'] = {
      "default" => {
        "gitaly_address" => 'dns:PRAEFECT_SERVICE_DISCOVERY_ADDRESS:2305',
        "gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
      }
    }
    

    TLS를 사용하려면 스킴을 dns+tls://로 변경합니다.

    gitlab_rails['repositories_storages'] = {
      "default" => {
        "gitaly_address" => 'dns+tls://DNS_SERVER_ADDRESS:53/PRAEFECT_SERVICE_DISCOVERY_ADDRESS:3305',
        "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
    

    TLS를 사용하려면 스킴을 dns+tls://로 변경합니다.

    gitlab:
      repositories:
        storages:
          default:
            gitaly_address: dns+tls://DNS_SERVER_ADDRESS:53/PRAEFECT_SERVICE_DISCOVERY_ADDRESS:3305
    
  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'
    
    # The following must also be added until this issue is addressed:
    # 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#

Note

각 Gitaly 노드에서 이 단계를 완료합니다.

이 섹션을 완료하려면 다음이 필요합니다.

  • 구성된 Praefect 노드
  • GitLab이 설치되어 Gitaly 노드로 구성할 서버 3대(또는 그 이상). 이 노드는 전용 노드여야 하며, 이 노드에서 다른 서비스를 실행하지 않습니다.

Praefect 클러스터에 할당된 모든 Gitaly 서버를 구성해야 합니다. 구성은 표준 독립 실행형 Gitaly 서버와 같지만 다음이 다릅니다.

  • 스토리지 이름은 GitLab이 아닌 Praefect에 노출됩니다.
  • 시크릿 토큰은 GitLab이 아닌 Praefect와 공유됩니다.

Praefect가 작업을 올바르게 라우팅하므로, Praefect 클러스터에 속한 모든 Gitaly 노드의 구성은 동일해도 됩니다.

특히 다음 사항에 주의해야 합니다.

  • 이 섹션에서 구성하는 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-1, gitaly-2, gitaly-3을 물리 스토리지 이름으로 사용합니다.

Gitaly 서버 구성에 대한 자세한 내용은 Gitaly 문서를 참고합니다.

  1. Gitaly 노드에 SSH로 접속하여 root로 로그인합니다.

    sudo -i
    
  2. /etc/gitlab/gitlab.rb를 편집하여 다른 모든 서비스를 비활성화합니다.

    # Disable all other services on the Gitaly node
    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
    
    # Enable only the Gitaly service
    gitaly['enable'] = true
    
    # Enable Prometheus if needed
    prometheus['enable'] = true
    
    # Disable database migrations to prevent database connections during 'gitlab-ctl reconfigure'
    gitlab_rails['auto_migrate'] = false
    
  3. /etc/gitlab/gitlab.rb를 편집하여 Gitaly가 네트워크 인터페이스에서 수신 대기하도록 구성합니다.

    gitaly['configuration'] = {
       # ...
       #
       # Make Gitaly accept connections on all network interfaces.
       # Use firewalls to restrict access to this address/port.
       listen_addr: '0.0.0.0:8075',
       # Enable Prometheus metrics access to Gitaly. You must use firewalls
       # to restrict access to this address/port.
       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. git push 작업에 필요한 GitLab Shell 시크릿 토큰을 구성합니다. 다음 중 하나를 선택합니다.

    • 방법 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. git push 작업에도 필요한 internal_api_url을 구성합니다.

    # Configure the gitlab-shell API callback URL. Without this, `git push` will
    # fail. This can be your front door GitLab URL or an internal load balancer.
    # Examples: '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: [
         # Replace with appropriate name for each Gitaly node.
         {
           name: 'gitaly-1',
           path: '/var/opt/gitlab/git-data/repositories',
         },
       ],
    }
    
  8. /etc/gitlab/gitlab.rb에 변경 사항을 저장하고 Gitaly를 재구성합니다.

    gitlab-ctl reconfigure
    
  9. Gitaly가 Prometheus 수신 대기 주소를 업데이트했는지 확인하려면 Gitaly를 다시 시작합니다.

    gitlab-ctl restart gitaly
    
Note

이전 단계는 각 Gitaly 노드에서 완료해야 합니다.

모든 Gitaly 노드를 구성한 후 Praefect 연결 검사기를 실행하여 Praefect가 Praefect 구성의 모든 Gitaly 서버에 연결할 수 있는지 확인합니다.

  1. 각 Praefect 노드에 SSH로 접속하여 Praefect 연결 검사기를 실행합니다.

    sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dial-nodes
    

로드 밸런서#

내결함성을 갖춘 Gitaly 구성에서는 GitLab 애플리케이션에서 Praefect 노드로 가는 내부 트래픽을 라우팅하기 위해 로드 밸런서가 필요합니다. 어떤 로드 밸런서를 사용할지, 정확한 구성은 어떻게 할지에 대한 세부 사항은 GitLab 문서의 범위를 벗어납니다.

Note

로드 밸런서는 GitLab 노드뿐 아니라 Gitaly 노드의 트래픽도 수락하도록 구성해야 합니다.

GitLab 같은 내결함성 시스템을 운영한다면 이미 선호하는 로드 밸런서가 있을 것으로 생각합니다. 예로는 HAProxy (오픈 소스), Google Internal Load Balancer, AWS Elastic Load Balancer, F5 Big-IP LTM, Citrix Net Scaler가 있습니다. 이 문서에서는 구성해야 하는 포트와 프로토콜을 설명합니다.

클론 같은 장시간 실행 작업은 연결을 오랫동안 열어 두므로 HAProxy leastconn 부하 분산 전략에 해당하는 방식을 사용해야 합니다.

LB 포트 백엔드 포트 프로토콜
2305 2305 TCP

TCP 로드 밸런서를 사용해야 합니다. Gitaly 사이드채널 때문에 HTTP/2 또는 gRPC 로드 밸런서를 Praefect와 함께 사용하면 작동하지 않습니다. 이 최적화는 gRPC 핸드셰이크 과정을 가로챕니다. 부하가 큰 모든 Git 작업을 gRPC보다 효율적인 "채널"로 리디렉션하지만, HTTP/2 또는 gRPC 로드 밸런서는 이런 요청을 올바르게 처리하지 못합니다.

TLS가 활성화된 경우 일부 Praefect 버전은 RFC 7540에 따라 Application-Layer Protocol Negotiation(ALPN) 확장을 사용해야 합니다. TCP 로드 밸런서는 추가 구성 없이 ALPN을 그대로 전달합니다.

Mermaid 다이어그램 (12줄)
소스 코드 보기
sequenceDiagram
    autonumber
    participant Client as Client
    participant LB as TCP Load Balancer
    participant Praefect as Praefect
Client-&gt;&gt;LB: Establish TLS Session (w/ ALPN Extension)
LB-&gt;&gt;Praefect: Establish TLS Session (w/ ALPN Extension)
Client-&gt;&gt;LB: Encrypted TCP packets
LB-&gt;&gt;Praefect: Encrypted TCP packets
Praefect-&gt;&gt;LB: Encrypted Response
LB-&gt;&gt;Client: Encrypted Response</code></pre></details></div>

일부 TCP 로드 밸런서는 TLS 클라이언트 연결을 수락한 뒤 새 TLS 연결로 Praefect에 연결을 프록시하도록 구성할 수 있습니다. 그러나 이는 두 연결 모두에서 ALPN이 지원될 때만 작동합니다.

이러한 이유로 NGINX의 ngx_stream_proxy_module은 proxy_ssl 구성 옵션이 활성화되어 있으면 작동하지 않습니다.

Mermaid 다이어그램 (9줄)
소스 코드 보기
sequenceDiagram
    autonumber
    participant Client as Client
    participant NGINX as NGINX Stream Proxy
    participant Praefect as Praefect
Client-&gt;&gt;NGINX: Establish TLS Session (w/ ALPN Extension)
NGINX-&gt;&gt;Praefect: Establish New TLS Session
Praefect-&gt;&gt;NGINX: Connection failed: missing selected ALPN property</code></pre></details></div>

2단계에서는 NGINX가 이를 지원하지 않기 때문에 ALPN이 사용되지 않습니다. 자세한 내용은 NGINX 이슈 406을 참고합니다.

ALPN 강제#

일부 GitLab 버전에서는 ALPN 강제가 활성화되어 있었습니다. 그러나 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 섹션에서 설정했습니다. 이 문서에서는 Praefect 스토리지 이름으로 default를 사용합니다.
  1. GitLab 노드에 SSH로 접속하여 root로 로그인합니다.

    sudo -i
    
  2. /etc/gitlab/gitlab.rb를 편집하여 GitLab이 올바른 엔드포인트 접근으로 파일을 제공할 수 있도록 external_url을 구성합니다.

    GITLAB_SERVER_URL을 현재 GitLab 인스턴스가 서비스 중인 실제 외부 공개 URL로 바꿔야 합니다.

    external_url 'GITLAB_SERVER_URL'
    
  3. GitLab 호스트에서 실행 중인 기본 Gitaly 서비스를 비활성화합니다. GitLab이 구성된 클러스터에 연결하므로 이 서비스는 필요하지 않습니다.

    [!warning] 기본 Gitaly 스토리지에 저장된 데이터가 있다면 먼저 데이터를 Gitaly Cluster(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. git push 중 Gitaly 노드의 콜백이 올바르게 인증되도록 GitLab Shell 시크릿 토큰을 구성합니다. 다음 중 하나를 선택합니다.

    • 방법 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 훅이 GitLab에 도달할 수 있는지 확인합니다. 각 Gitaly 노드에서 다음을 실행합니다.

    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. 오른쪽 상단에서 Admin을 선택합니다.
    2. 왼쪽 사이드바에서 Settings > Repository를 선택합니다.
    3. Repository storage 섹션을 확장합니다.

    이 가이드를 따랐다면 default 스토리지는 모든 새 리포지터리를 저장하도록 가중치가 100이어야 합니다.

  11. 새 프로젝트를 만들어 모든 것이 작동하는지 확인합니다. 리포지터리에 볼 수 있는 콘텐츠가 있도록 "Initialize repository with a README" 확인란을 선택합니다. 프로젝트가 만들어지고 README 파일이 보이면 정상적으로 작동하는 것입니다.

기존 GitLab 인스턴스에서 TCP 사용#

기존 Gitaly 인스턴스에 Gitaly Cluster(Praefect)를 추가할 때, 기존 Gitaly 스토리지는 TCP/TLS로 수신 대기해야 합니다. gitaly_address를 지정하지 않으면 Unix 소켓이 사용되며, 이로 인해 클러스터와 통신할 수 없습니다.

예를 들면 다음과 같습니다.

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

여러 Gitaly 스토리지를 실행하는 방법에 대한 자세한 내용은 혼합 구성을 참고합니다.

여러 가상 스토리지 구성#

여러 가상 스토리지를 구성하여 리포지터리를 서로 다른 Gitaly Cluster(Praefect) 클러스터로 구성할 수 있습니다. 각 가상 스토리지는 자체 Gitaly 노드 집합과 복제 설정으로 독립적으로 작동합니다.

여러 가상 스토리지를 구성하려면 다음을 수행합니다.

  1. 각 Praefect 노드에서 /etc/gitlab/gitlab.rb를 편집하여 virtual_storage 배열에 여러 항목을 추가합니다.

    praefect['configuration'] = {
       # ...
       virtual_storage: [
          {
             name: 'storage-1',
             default_replication_factor: 3,
             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'
                }
             ]
          },
          {
             name: 'storage-2',
             default_replication_factor: 2,
             node: [
                {
                   storage: 'gitaly-4',
                   address: 'tcp://GITALY_HOST_4:8075',
                   token: 'PRAEFECT_INTERNAL_TOKEN'
                },
                {
                   storage: 'gitaly-5',
                   address: 'tcp://GITALY_HOST_5:8075',
                   token: 'PRAEFECT_INTERNAL_TOKEN'
                },
                {
                   storage: 'gitaly-6',
                   address: 'tcp://GITALY_HOST_6:8075',
                   token: 'PRAEFECT_INTERNAL_TOKEN'
                }
             ]
          }
       ]
    }
    
  2. 변경 사항을 저장하고 Praefect를 재구성합니다.

    gitlab-ctl reconfigure
    
  3. GitLab 서버에서 /etc/gitlab/gitlab.rb를 편집하여 두 가상 스토리지를 모두 구성합니다.

    gitlab_rails['repositories_storages'] = {
      "storage-1" => {
        "gitaly_address" => "tcp://PRAEFECT_1_LOADBALANCER_HOST:2305",
        "gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
      },
      "storage-2" => {
        "gitaly_address" => "tcp://PRAEFECT_2_LOADBALANCER_HOST:2305",
        "gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
      }
    }
    
  4. 변경 사항을 저장하고 GitLab을 재구성합니다.

    gitlab-ctl reconfigure
    
  5. 구성을 확인합니다.

    gitlab-rake gitlab:gitaly:check
    

구성 후 다음을 수행할 수 있습니다.

독립 실행형과 클러스터 스토리지 혼합 구성#

독립 실행형 Gitaly 인스턴스와 Gitaly Cluster(Praefect) 가상 스토리지를 동시에 사용하도록 GitLab을 구성할 수 있습니다. 마이그레이션 중이거나 일부 리포지터리에만 고가용성이 필요할 때 이렇게 할 수 있습니다.

혼합 설정을 구성하려면 다음을 수행합니다.

  1. 독립 실행형 Gitaly 인스턴스가 TCP에서 수신 대기하도록 구성되어 있는지 확인합니다. 독립 실행형 Gitaly 노드에서 /etc/gitlab/gitlab.rb를 편집합니다.

    gitaly['configuration'] = {
       # ...
       listen_addr: '0.0.0.0:8075'
    }
    
  2. 독립 실행형 Gitaly 인스턴스의 인증을 구성합니다.

    gitaly['configuration'] = {
       # ...
       auth: {
          token: 'GITALY_AUTH_TOKEN',
       },
    }
    
  3. 저장하고 재구성합니다.

    gitlab-ctl reconfigure
    
  4. GitLab 서버에서 /etc/gitlab/gitlab.rb를 편집하여 독립 실행형 스토리지와 클러스터 스토리지를 모두 구성합니다.

    gitlab_rails['repositories_storages'] = {
      'default' => {
        'gitaly_address' => 'tcp://STANDALONE_GITALY_HOST:8075',
        'gitaly_token' => 'GITALY_AUTH_TOKEN'
      },
      'cluster' => {
        'gitaly_address' => 'tcp://PRAEFECT_LOADBALANCER_HOST:2305',
        'gitaly_token' => 'PRAEFECT_EXTERNAL_TOKEN'
      }
    }
    
  5. 저장하고 GitLab을 재구성합니다.

    gitlab-ctl reconfigure
    
  6. 두 스토리지에 모두 접근할 수 있는지 확인합니다.

    gitlab-rake gitlab:gitaly:check
    

이 구성에서는 다음과 같이 동작합니다.

  • default 스토리지는 독립 실행형 Gitaly 노드에 직접 연결됩니다.
  • cluster 스토리지는 로드 밸런서를 통해 Gitaly Cluster(Praefect)에 연결됩니다.
  • GitLab은 두 스토리지를 동등하게 취급하며 어느 스토리지에나 리포지터리를 저장할 수 있습니다.
  • 스토리지 가중치를 구성하여 새 리포지터리에 한쪽 스토리지를 우선하도록 할 수 있습니다.

자세한 내용은 혼합 구성을 참고합니다.

Grafana#

Grafana는 GitLab에 포함되어 있으며 Praefect 클러스터를 모니터링하는 데 사용할 수 있습니다. 자세한 문서는 Grafana 대시보드 서비스를 참고합니다.

빠르게 시작하려면 다음을 수행합니다.

  1. GitLab 노드(또는 Grafana가 활성화된 노드)에 SSH로 접속하여 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. 웹 브라우저에서 GitLab 서버의 /-/grafana(예: https://gitlab.example.com/-/grafana)를 엽니다.

    설정한 비밀번호와 사용자 이름 admin으로 로그인합니다.

  6. Explore로 이동하여 gitlab_build_info를 쿼리하고 모든 머신에서 메트릭을 가져오고 있는지 확인합니다.

관측 가능한 내결함성 Praefect 클러스터 구성이 완료되었습니다.

복제 계수 구성#

Praefect는 리포지터리를 호스팅할 특정 스토리지 노드를 할당하는 방식으로 리포지터리별 복제 계수를 구성할 수 있도록 지원합니다.

Warning

오브젝트 풀, 포크된 적이 있는 모든 리포지터리, 또는 포크 자체의 복제 계수를 줄이지 않습니다. 그러면 전체 포크 네트워크가 손상될 수 있습니다. 오브젝트 풀의 상대 경로는 @pools/로 시작합니다. 리포지터리가 포크되었는지는 GitLab UI에서 확인할 수 있습니다.

Praefect는 실제 복제 계수를 저장하지 않고, 원하는 복제 계수를 충족하도록 리포지터리를 호스팅할 충분한 스토리지를 할당합니다. 이후 스토리지 노드가 가상 스토리지에서 제거되면 해당 스토리지에 할당된 리포지터리의 복제 계수도 그에 맞게 줄어듭니다.

다음 중 하나를 구성할 수 있습니다.

  • 새로 만든 리포지터리에 적용되는 가상 스토리지별 기본 복제 계수
  • set-replication-factor 하위 명령을 사용한 기존 리포지터리의 복제 계수

기본 복제 계수 구성#

Warning

오브젝트 풀이 있을 때 기본 복제를 줄이면 연결된 일부 리포지터리가 손상될 수 있습니다. 오브젝트 풀의 상대 경로는 @pools/로 시작합니다.

default_replication_factor를 설정하지 않으면 리포지터리는 항상 virtual_storages에 정의된 모든 스토리지 노드에 복제됩니다. 가상 스토리지에 새 스토리지 노드가 추가되면 새 리포지터리와 기존 리포지터리 모두 해당 노드로 자동으로 복제됩니다.

스토리지 노드가 많은 대규모 Gitaly Cluster(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> -relative-path <relative-path> -replication-factor <replication-factor>
  • -virtual-storage는 리포지터리가 위치한 가상 스토리지입니다.
  • -relative-path는 스토리지에서 리포지터리의 상대 경로입니다.
  • -replication-factor는 리포지터리에 원하는 복제 계수입니다. 기본 노드에 리포지터리 사본이 필요하므로 최솟값은 1입니다. 최대 복제 계수는 가상 스토리지에 있는 스토리지 수입니다.

성공하면 할당된 호스트 스토리지가 출력됩니다. 예를 들면 다음과 같습니다.

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

current assignments: gitaly-1, gitaly-2

리포지터리 스토리지 권장 사항#

필요한 스토리지 크기는 인스턴스마다 다를 수 있으며 설정한 복제 계수에 따라 달라집니다. 리포지터리 스토리지 이중화 구현을 포함하는 것이 좋을 수 있습니다.

복제 계수가 다음과 같은 경우입니다.

  • 1인 경우: Gitaly와 Gitaly Cluster(Praefect)의 스토리지 요구 사항은 대략 같습니다.
  • 1보다 큰 경우: 필요한 스토리지 양은 used space * replication factor입니다. used space에는 향후 계획된 증가분이 포함되어야 합니다.

리포지터리 검증#

Praefect는 리포지터리에 대한 메타데이터를 데이터베이스에 저장합니다. Praefect를 거치지 않고 디스크에서 리포지터리가 수정되면 메타데이터가 부정확해질 수 있습니다. 예를 들어 Gitaly 노드를 새 노드로 교체하지 않고 재구축한 경우, 리포지터리 검증을 통해 이를 감지할 수 있습니다.

메타데이터는 복제와 라우팅 결정에 사용되므로 부정확한 내용이 있으면 문제가 발생할 수 있습니다. Praefect에는 디스크의 실제 상태와 메타데이터를 주기적으로 대조하여 검증하는 백그라운드 워커가 있습니다. 이 워커는 다음과 같이 동작합니다.

  1. 정상 스토리지에서 검증할 복제본을 일괄로 가져옵니다. 복제본은 검증되지 않았거나 구성된 검증 간격을 초과한 것입니다. 한 번도 검증되지 않은 복제본이 우선이고, 그다음은 마지막 검증 성공 이후 시간이 가장 오래된 순서로 나머지 복제본을 처리합니다.
  2. 각 복제본이 해당 스토리지에 존재하는지 확인합니다. 결과가 다음과 같은 경우:
    • 복제본이 존재하면 마지막 검증 성공 시간을 업데이트합니다.
    • 복제본이 존재하지 않으면 해당 메타데이터 레코드를 제거합니다.
    • 확인에 실패하면 다음 워커가 작업을 더 가져올 때 해당 복제본이 다시 검증 대상으로 선택됩니다.

워커는 검증하려는 각 복제본에 대해 배타적 검증 리스를 획득합니다. 이렇게 하면 여러 워커가 동일한 복제본을 동시에 검증하는 것을 방지합니다. 워커는 확인을 마치면 리스를 해제합니다. 워커가 리스를 해제하지 못한 채 어떤 이유로 종료되면, Praefect의 백그라운드 고루틴이 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"
      ]
    }
  }
}

검증 워커 구성#

워커는 기본적으로 활성화되어 있으며 7일마다 메타데이터 레코드를 검증합니다. 검증 간격은 유효한 Go duration 문자열로 구성할 수 있습니다.

메타데이터를 3일마다 검증하려면 다음과 같이 구성합니다.

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

0 이하의 값은 백그라운드 검증기를 비활성화합니다.

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

삭제 활성화#

기본적으로 워커는 잘못된 메타데이터 레코드를 삭제합니다. 또한 삭제된 레코드를 로그로 남기고 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 Cluster(Praefect)는 리포지터리마다 별도로 기본 Gitaly 노드를 선출합니다. 구성 가능한 복제 계수와 함께 사용하면 스토리지 용량을 수평으로 확장하고 쓰기 부하를 Gitaly 노드 전반에 분산할 수 있습니다.

기본 노드 선출은 지연 방식으로 실행됩니다. 현재 기본 노드가 비정상이더라도 Praefect는 새 기본 노드를 즉시 선출하지 않습니다. 현재 기본 노드를 사용할 수 없는 상태에서 요청을 처리해야 할 때 새 기본 노드가 선출됩니다.

유효한 기본 노드 후보는 다음 조건을 충족하는 Gitaly 노드입니다.

  • 정상입니다. Praefect 노드의 >=50%가 이전 10초 동안 해당 Gitaly 노드의 상태 확인에 성공하면 Gitaly 노드가 정상으로 간주됩니다.
  • 리포지터리의 완전히 최신인 사본이 있습니다.

기본 노드 후보가 여러 개이면 Praefect는 다음과 같이 처리합니다.

  • 그중 하나를 무작위로 선택합니다.
  • 리포지터리를 호스팅하도록 할당된 Gitaly 노드의 승격을 우선합니다. 기본 노드로 선출할 할당된 Gitaly 노드가 없으면 Praefect가 할당되지 않은 노드를 일시적으로 선출할 수 있습니다. 할당된 노드를 사용할 수 있게 되면 할당되지 않은 기본 노드는 강등되고 할당된 노드가 그 자리를 대신합니다.

리포지터리에 유효한 기본 노드 후보가 없으면 다음과 같이 됩니다.

  • 비정상 기본 노드는 강등되고 리포지터리에는 기본 노드가 없는 상태가 됩니다.
  • 기본 노드가 필요한 작업은 기본 노드가 성공적으로 선출될 때까지 실패합니다.