Omnibus GitLab 아키텍처 및 구성 요소

Omnibus GitLab은 Chef의 Omnibus 프로젝트의 사용자 컴퓨터에서 GitLab을 구성하는 작업을 수행하기 위해 조리책(cookbooks) 및 레시피와 같은 Chef 구성 요소를 사용하는 Omnibus 프로젝트의 사용자 정의 포크입니다. Omnibus GitLab 저장소는 GitLab.com에서 Omnibus GitLab의 모든 필요한 구성 요소를 호스팅합니다. 이에는 패키지 빌드에 필요한 Omnibus의 구성 요소, 프로젝트 메타데이터, 사용자 컴퓨터에 설치된 후 사용되는 Chef 관련 구성 요소가 포함됩니다.

Omnibus-GitLab Components

이러한 구성 요소에 대한 체계적인 비디오 설명서는 YouTube에서 제공됩니다.

소프트웨어 정의

GitLab 프로젝트 정의 파일

Omnibus 아키텍처의 주요 구성 요소는 프로젝트 세부 정보 및 외부 소프트웨어 및 라이브러리와의 종속성 관계를 나열하는 프로젝트 정의 파일입니다.

프로젝트 정의 파일의 주요 구성 요소는 다음과 같습니다.

  • 프로젝트 메타데이터: 프로젝트 이름 및 설명과 같은 속성을 포함합니다.
  • 프로젝트의 라이센스 세부 정보
  • 종속성 목록: GitLab을 빌드하거나 실행하는 데 필요한 외부 도구 및 소프트웨어 목록 및 때로는 이들의 메타데이터.
  • GitLab 설치에 사용되는 전역 구성 변수: 설치 디렉토리, 시스템 사용자 및 시스템 그룹을 포함합니다.

개별 소프트웨어 정의

Omnibus GitLab은 독립형 형식의 배포를 따릅니다. GitLab 인스턴스의 올바른 작동에 필요한 모든 소프트웨어, 라이브러리 및 실행 파일이 패키지의 일부로 임베드 형식으로 제공됩니다.

따라서 Omnibus 아키텍처의 주요 구성 요소 중 하나는 소프트웨어 정의 및 구성입니다. 일반적인 소프트웨어 구성은 다음 부분으로 구성됩니다.

  • 필요한 소프트웨어의 버전.
  • 소프트웨어의 라이센스.
  • 소프트웨어의 빌드/실행을 위한 종속성.
  • 소프트웨어를 빌드하고 패키지 내에 임베드하기 위해 필요한 명령어.

가끔 소프트웨어의 소스 코드를 GitLab과 함께 사용하도록 수정해야 할 수도 있습니다. 이는 보안 취약점을 수정하거나 GitLab에 필요한 기능을 추가하거나 GitLab의 다른 구성 요소와 작동하도록 만들기 위한 것일 수 있습니다. 이를 위해 Omnibus GitLab에는 다양한 소프트웨어의 패치가 저장된 패치 디렉토리가 있습니다.

보다 체계적인 변경을 위해 필요한 변경 사항을 미러의 브랜치에서 추적하는 것이 더 편리할 수 있습니다. 이를 위한 패턴은 상위 태그나 SHA로부터 브랜치를 생성하고 해당 브랜치포인트를 브랜치명에 참조하는 것입니다. 예를 들어, Omnibus 코드베이스의 경우 gitlab-omnibus-v5.6.10는 상위 프로젝트의 v5.6.10 태그를 기반으로 한 브랜치입니다. 이를 통해 우리는 https://gitlab.com/gitlab-org/omnibus/compare/v5.6.10...gitlab-omnibus-v5.6.10와 같은 비교 링크를 생성하여 어떤 로컬 변경 사항이 있는지 식별할 수 있습니다.

전역 GitLab 구성 템플릿

Omnibus GitLab은 사용자 컴퓨터에 설치된 GitLab 인스턴스의 모든 부분을 구성하는 데 사용될 수 있는 단일 구성 파일을 함께 제공합니다. 이 구성 파일은 GitLab 인스턴스에 적용될 모든 구성 설정의 근본적인 원본 역할을 합니다. 이는 GitLab 인스턴스의 일반 설정과 다양한 구성 요소에 대한 여러 옵션을 나열합니다. 이 파일의 일반적인 구조는 <component>['<setting>'] = <value> 형식으로 지정된 구성을 포함하고 있습니다. 모든 사용 가능한 옵션은 구성 템플릿에 나열되어 있지만 GitLab의 기본 작동에 필요한 것을 제외하고는 기본적으로 전부 주석 처리되어 있습니다. 필요한 경우 사용자는 이를 주석 해제하고 해당 값들을 지정할 수 있습니다.

GitLab Cookbook

이전에 설명한 대로 Omnibus GitLab은 조리책, 속성, 자원과 같은 Chef 구성 요소를 많이 사용합니다. GitLab EE는 GitLab CE에서 확장되어 EE 전용 구성 요소를 추가하는 별도의 조리책을 사용합니다. Omnibus GitLab의 Chef 관련 주요 구성 요소는 다음과 같습니다.

기본 속성

기본 속성은 이름에서 알 수 있듯이 구성 파일에서 제공되는 다양한 설정에 대한 기본값을 지정합니다. 이러한 값은 사용자가 설정에 값을 제공하지 않는 경우에 사용되며, 따라서 사용자가 최소한의 조작으로도 작동하는 GitLab 인스턴스를 보장합니다.

레시피

레시피는 Omnibus 패키지를 사용하여 GitLab을 설치하는 동안 대부분의 중요한 작업을 수행합니다. 그들은 사용자 컴퓨터에서 GitLab 생태계의 각 구성 요소를 설정하는 데 책임이 있으며, 해당 위치에 필요한 파일, 디렉토리 및 링크를 생성하고, 그들의 권한과 소유자를 설정하고, 필요한 서비스를 시작하거나 중지하며, 이러한 서비스가 파일의 변경 사항에 대응할 때 이들을 통지합니다. default라고 명명된 메인 레시피는 모든 다른 구성 요소 및 서비스에 대한 모든 필요한 레시피를 호출하는 입구점으로 작용합니다.

사용자 정의 자원

사용자 정의 자원은 레시피 간에 재사용될 수 있는 전역 수준의 매크로로 볼 수 있습니다. 사용자 정의 자원의 일반적인 사용 예시는 일반적인 서비스에 사용되는 포트를 정의하거나 서로 다른 레시피에서 사용될 수 있는 중요한 디렉토리를 나열하는 것입니다. 이들은 서로 다른 레시피에서 재사용될 수 있는 자원을 정의합니다.

구성 요소 구성을 위한 템플릿

이전에 언급했듯이 Omnibus GitLab은 GitLab 인스턴스의 모든 구성 요소를 조정하기 위해 단일 구성 파일을 제공합니다. 그러나 다른 구성 요소의 설계적 특성은 특정 위치에 상주하는 개별 구성 파일을 필요로 할 수 있습니다. 이러한 구성 파일은 사용자가 일반 구성 파일에서 지정한 값이나 기본값을 사용하여 생성되어야 합니다. 따라서 Omnibus GitLab은 이러한 구성 파일 템플릿을 포함하여 이 템플릿을 완성하고 필요한 위치에 배치하는 작업을 레시피가 수행합니다.

일반 라이브러리 메서드

Omnibus GitLab에는 라이브러리 메서드도 함께 제공되며, 주로 코드 재사용을 위한 목적으로 사용됩니다. 이에는 서비스가 가동 중인지 확인하는 메서드, 파일의 존재 여부를 확인하는 메서드, 서로 다른 구성 요소와 상호 작용하는 데 도움이 되는 도우미 메서드 등이 포함됩니다. 이러한 메서드들은 주로 Chef 레시피에서 사용됩니다.

Omnibus GitLab에서 사용되는 라이브러리 중 일부는 특별합니다. 주요 GitLab 모듈과 해당 구성 요소별 라이브러리들이 그 중 하나에 해당합니다. 구성 요소별 라이브러리에는 해당 구성 요소에 정의된 설정을 구문 분석하는 작업을 수행하는 메서드가 포함되어 있습니다. 주요 GitLab 모듈에는 이를 조정하는 메서드가 포함되어 있습니다. 이 모듈은 기본값을 식별하고 구성 요소별 라이브러리를 호출하며, 기본값과 사용자 지정 값 병합 및 유효성 검사에 대한 책임이 있으며, 초기 값을 기반으로 추가 구성을 생성합니다. Omnibus GitLab 패키지로 제공되는 모든 최상위 구성 요소는 이 모듈에 추가되어 구성 파일 및 기본 속성에 언급될 수 있도록 하여 올바르게 구문 분석될 수 있도록 합니다.

runit

GitLab은 서비스 관리 및 감독을 위해 runit 레시피를 사용합니다. runit 레시피는 OS에서 사용 중인 이닛 시스템을 식별하고 GitLab을 위해 필요한 서비스 파일을 만들고, 서비스 활성화 및 서비스 다시로드와 같은 기본 서비스 관리 작업을 수행합니다. runit은 다른 레시피에서 사용할 수 있는 runit_service 정의를 제공하여 서비스와 상호 작용할 수 있습니다. 자세한 정보는 /files/gitlab-cookbooks/runit를 참조하십시오.

서비스

서비스란 runit 프로세스 이닛/감독을 사용하여 실행하는 소프트웨어 프로세스입니다. gitlab-ctl 명령을 사용하여 상태를 확인하고 시작, 중지, 다시 시작할 수 있습니다. 레시피에서는 프로세스 그룹 및 구성한 GitLab의 설정/역할에 따라 이러한 서비스를 비활성화 또는 활성화할 수도 있습니다. 해당 서비스 및 해당 서비스 그룹의 목록은 files/gitlab-cookbooks/package/libraries/config/services.rb에서 찾을 수 있습니다.

추가적인 gitlab-ctl 명령

기본적으로 Omnibus는 gitlab-ctl reconfiguregitlab-ctl restart와 같은 래퍼 명령을 제공하여 GitLab 인스턴스를 관리합니다. Omnibus GitLab 저장소에 정의된 특정 사용 사례를 대상으로 하는 몇 가지 추가 래퍼 명령도 있습니다. 이러한 명령은 데베테이스 마이그레이션 실행 또는 휴면 계정 제거와 같은 특정한 작업 수행에 gitlab-ctl 명령과 함께 사용됩니다.

테스트

Omnibus GitLab 저장소는 ChefSpec을 사용하여 쿡북 및 레시피 테스트를 수행합니다. 보통의 전략은 레시피를 두 가지(또는 그 이상) 상황에서 올바르게 작동하는지 확인하는 것입니다: 사용자가 해당 구성을 지정하지 않았을 때(즉, 기본값을 사용하는 경우)과 사용자 지정 구성을 사용하는 경우. 테스트에는 파일이 올바른 위치에 생성되었는지, 서비스가 시작/중지/알림을 받았는지, 올바른 이진 파일이 호출되었는지, 메서드 호출에 올바른 매개변수가 전달되었는지를 확인할 수 있습니다. 레시피 및 라이브러리 메서드에는 해당 테스트가 포함되어 있습니다. Omnibus GitLab은 테스트 프로세스를 지원하는 데 도움이 되는 지원 메서드 또는 매크로도 사용합니다. 테스트는 가능한 경우 병렬화를 위해 호환되도록 정의되어 전체 테스트 스위트를 실행하는 데 필요한 시간을 줄이려고 합니다.

따라서 위에서 설명한 구성 요소 중에서 일부(소프트웨어 정의, 프로젝트 메타데이터 및 테스트 등)는 빌드 환경에서 패키지 빌딩 중에 사용되며, 일부(예: Chef 쿡북 및 레시피, GitLab 구성 파일, runit 및 gitlab-ctl 명령)는 사용자가 설치한 인스턴스를 구성하는 데 사용됩니다.

Omnibus GitLab의 작업 수명주기

패키지 빌딩 중의 작업

빌드 프로세스가 실행되는 OS에 따라 빌드되는 패키지의 종류가 달라집니다. 빌드 중에 일어나는 작업은 다음 단계로 요약할 수 있습니다.

  1. 종속 소프트웨어의 소스 가져오기:
    1. 해당 버전을 찾기 위해 소프트웨어 정의를 구문 분석합니다.
    2. 원격지 또는 캐시에서 소스 코드 가져오기.
  2. 개별 소프트웨어 구성요소 빌드:
    1. 필요한 환경 변수 및 플래그 설정.
    2. 해당되는 경우 패치 적용.
    3. 구성요소의 빌드 및 설치 수행, 즉 적절한 위치(예: /opt/gitlab 내부)에 설치하기.
  3. 외부 소프트웨어, 루비 젬 및 JS 모듈을 포함한 모든 번들된 구성 요소의 라이센스 정보 생성. 이에는 각 종속성의 정의 분석 및 구성 요소가 제공하는 추가 라이센싱 문서(예: GitLab Rails가 제공하는 licenses.csv 파일) 등이 포함됩니다.
  4. 구성 요소의 라이센스를 확인하여 호환되지 않는 라이센스로 패키지가 제공되지 않는지 확인합니다.
  5. 패키지의 바이너리가 사용 가능한 라이브러리에 링크되어 있는지 확인하기 위한 패키지의 상태 확인. 번들된 라이브러리의 경우 바이너리가 해당되는 라이브러리에 링크되어 있어야 하며, 전역적으로 사용되는 라이브러리에는 링크되어 있지 않아야 합니다.
  6. /opt/gitlab의 내용으로 패키지 빌딩. 이는 저장소 루트에 있는 gitlab.rb 파일 내부에 포함된 메타데이터를 사용합니다. 패키지 이름, 버전, 유지 관리자, 홈페이지 및 다른 패키지와의 충돌 정보를 포함합니다.

캐싱

Omnibus는 빌드 프로세스 최적화를 위해 두 가지 유형의 캐시를 사용합니다: 종속 소프트웨어 아티팩트(종속 소프트웨어의 소스 코드)를 저장하는 캐시와 각 소프트웨어 구성 요소 빌드 후 프로젝트 트리를 저장하는 캐시

소프트웨어 아티팩트 캐시(GitLab Inc 빌드용)

소프트웨어 아티팩트 캐시는 종속 소프트웨어의 소스를 저장하기 위해 Amazon S3 버킷을 사용합니다. 빌드 프로세스에서 이 캐시는 bin/omnibus cache populate 명령을 사용하여 채워집니다. 이는 필요한 모든 소프트웨어 소스를 Amazon 버킷에서 끌어와서 필요한 위치에 저장합니다. 소프트웨어 버전 요구 사항이 변경되면 Omnibus가 원래의 원격지에서 끌어와서 아티팩트 캐시에 추가합니다.이 프로세스는 Omnibus 내부의 것이며, 원래 업스트림 원격지가 다운되더라도 Amazon 버킷을 사용하도록 Omnibus를 구성합니다. 이 캐시를 통해 종속 소프트웨어를 사용 가능하게 합니다.

빌드 캐시

빌드 프로세스에서 중요한 역할을 하는 두 번째 유형의 캐시는 빌드 캐시입니다. 빌드 캐시는 프로젝트 트리(프로젝트가 빌드되는 위치 - /opt/gitlab)의 스냅샷으로 설명할 수 있습니다. 각 의존 소프트웨어 빌드 후에 빌드 캐시가 만들어집니다. A, B, C, D, E 다섯 개의 의존 소프트웨어로 구성된 프로젝트를 고려해보겠습니다. 이들의 의존성은 고려하지 않습니다. 빌드 캐시는 Git 태그를 사용하여 스냅샷을 만듭니다. 각 소프트웨어가 빌드될 때 Git 태그가 계산되고 커밋됩니다. 이제 소프트웨어 D의 정의에 일부 변경을 가했다고 가정해보겠습니다. A, B, C, E는 그대로입니다. 다시 빌드하려고 하면 Omnibus는 이전 빌드에서 D가 빌드되기 전에 만들어진 스냅샷을 재사용할 수 있습니다. 따라서 A, B, C를 빌드하는 데 걸리는 시간을 단축시킬 수 있습니다. Omnibus는 캐시를 ‘더럽힌’ 소프트웨어의 직전 스냅샷을 사용합니다 (‘더럽힘이란 소프트웨어 정의의 변경, 이전 구성 요소의 이름/버전 변경 또는 현재 구성 요소의 버전 변경 중 하나로 발생할 수 있습니다). 비슷하게 빌드에서 소프트웨어 A의 정의가 변경된 경우 캐시를 ‘더럽히고’, 그래서 A 및 모든 이후 의존성이 처음부터 다시 빌드됩니다. C가 캐시를 ‘더럽히면’, A와 B는 재사용되고 C, D, E가 처음부터 다시 빌드됩니다.

이 캐시는 빌드 간 유지되는 경우에만 의미가 있습니다. 이를 위해 GitLab CI의 캐싱 메커니즘을 사용합니다. 우리는 내부 캐시를 저장하기 위해 설정된 전용 러너를 가지고 있습니다. 매 빌드 전에 이 캐시를 가져와야 합니다(우리의 Makefile에 있는 restore_cache_bundle 대상), 적절한 위치로 이동시키고 빌드를 시작합니다. Omnibus가 ‘더럽힐’ 때까지 사용됩니다. 빌드 후에 새 캐시를 패킹하고 CI에게 Amazon 버킷으로 백업하도록 알립니다(우리의 Makefile에서 pack_cache_bundle).

두 유형의 캐시는 GitLab 및 외부 요소에 대한 종속성을 줄이는 전반적인 빌드 시간을 줄입니다.

캐시 메커니즘은 다음과 같이 요약될 수 있습니다:

  1. 각 소프트웨어 의존성에 대해:
    1. 버전 및 SHA256을 이해하기 위해 정의를 구문 분석합니다.
    2. Amazon 버킷의 아티팩트 캐시에서 사용 가능한 소스 파일 타볼이 버전 및 SHA256과 일치하는지 확인합니다.
    3. 그렇지 않으면 업스트림 원격에서 올바른 타볼을 다운로드합니다.
  2. CI 캐시에서 캐시를 가져옵니다.
  3. 각 소프트웨어 의존성에 대해:
    1. 캐시를 ‘더럽혀’ 버립니다.
    2. 그렇지 않으면 스냅샷을 확인합니다.
  4. 남은 의존성이 있는 경우:
    1. 남은 의존성마다:
      1. 의존성을 빌드합니다.
      2. 스냅샷을 만들고 커밋합니다.
  5. 새 빌드 캐시를 CI 캐시로 밀어 넣습니다.

다중 데이터베이스

이전에 GitLab Rails 애플리케이션은 Omnibus GitLab 데이터베이스에 연결된 유일한 클라이언트였습니다. 시간이 지나면서 상황이 바뀌었습니다.

  • Praefect 및 컨테이너 레지스트리는 독립적인 데이터베이스를 사용합니다.
  • Rails 애플리케이션은 이제 분해된 데이터베이스를 사용합니다.

추가 데이터베이스가 필요할 수 있기 때문에: