루비 업그레이드 지침

우리는 성능 및 보안 업데이트와 새로운 루비 API에서 이점을 얻기 위해 최신 루비 MRI 릴리스를 사용하여 GitLab을 실행하기 위해 노력합니다. GitLab 전반에 걸쳐 루비를 업그레이드할 때는 다음과 같은 방식으로 수행해야 합니다.

  • 기여자에게 가장 덜 방해가 되는 방법으로 수행합니다.
  • GitLab SaaS의 가용성을 최적화합니다.
  • GitLab의 모든 부분에서 루비 버전 동등성을 유지합니다.

루비 버전을 변경하기 전에이 문서를 주의 깊게 읽고 전체적으로 읽어 현재 필요한 변경 사항에 대한 상위 수준의 이해를 얻으세요. 모든 루비 업그레이드가 이전 것과 조금 다를 수 있으므로 문서화된 단계의 순서와 필요성을 평가하세요.

루비 업그레이드의 범위

루비를 업그레이드할 때 고려해야 할 첫 번째 사항은 범위입니다. 일반적으로 루비 업데이트가 발생해야 할 다음 영역을 고려합니다.

  • 주요 GitLab Rails 리포지터리.
  • 부수적인 루비 시스템 리포지터리.
  • 이러한 리포지터리의 시스템에서 사용하는 타사 라이브러리.
  • 이러한 리포지터리의 시스템에서 사용하는 GitLab 라이브러리.

이 중에서 모두에 손대지 않아도 될 수도 있습니다. 예를 들어, 패치 레벨 루비 업데이트는 타사 젬에서 업데이트를 요구하지 않을 가능성이 높습니다.

패치, 마이너 및 메이저 업그레이드

범위를 평가할 때 루비 버전 레벨이 중요합니다. 예를 들어, GitLab을 Ruby 2.x에서 3.x로 업그레이드 하는 것은 Ruby 2.7.2에서 2.7.4로 업그레이드하는 것보다 어렵고 리스크가 큽니다. 왜냐하면 패치 릴리스는 일반적으로 보안 또는 버그 수정으로 제한되어 있기 때문입니다. 이 사실을 염두에 두고 업그레이드를 준비하고 그에 맞게 계획하세요.

향후 업그레이드 범위를 추정하는 데 도움이 될 수 있는 작업량을 보려면 다음 업그레이드에 필요한 노력을 참조하세요.

영향을 받는 대상과 대상

어떤 업그레이드 전에도 루비 업그레이드에 영향을 받는 대상 및 대상을 고려하고 루비 업그레이드로 인하여 얼마나 빨리 영향을 받는지에 따라 정렬합니다.

  1. 개발자들. GitLab 및 관련 프로젝트에는 회사 내외의 많은 기여자가 있습니다. .ruby-version과 같은 파일을 해석하는 도구를 사용하는 모든 사용자에게 영향을 미칩니다. 변경된 파일을 포함하는 리포지터리에서 변경 사항을 Merge하는 즉시 개발자들은 영향을 받습니다.
  2. GitLab CI/CD. 코드 통합 및 테스트를 위해 CI/CD를 많이 의존합니다. CI/CD 작업은 .ruby-version과 같은 파일을 해석하지 않습니다. 대신, 실행 중인 Docker 컨테이너에 정의된 .gitlab-ci.yml 파일에 정의된 Ruby를 사용합니다. 이러한 작업에서 사용되는 컨테이너 이미지는 gitlab-build-images 리포지터리에서 유지됩니다. 이미지가 빌드되면 CI/CD 작업은 영향을 받습니다.
  3. GitLab SaaS. GitLab.com은 Cloud Native GitLab (CNG)에서 Docker 이미지를 사용하는 맞춤형 Helm 차트에서 배포됩니다. CI/CD와 마찬가지로 .ruby-version은이 환경에서는 의미가 없습니다. 대신, Docker 이미지를 업그레이드하기 위해 해당 Docker 이미지가 패치되어야 합니다. GitLab SaaS는 다음 배포에서 영향을 받습니다.
  4. 자체 설치 GitLab. Omnibus을 통해 GitLab을 설치하는 고객은 앞에서 언급한 방법을 사용하지 않습니다. 대신, 루비 버전은 Omnibus의 Ruby software bundle에 의해 정의됩니다. 자체 설치 고객은 이 변경 사항이 포함 된 릴리스로 업그레이드하는 즉시 영향을 받습니다.

루비 업그레이드 접근 방식

루비 업그레이드의 모든 단계를 올바르게 타이밍하는 것이 중요합니다. 일반적인 가이드라인으로 다음을 고려하세요.

  • 프로덕션 동작이 변경될 가능성이 적은 작은 업그레이드의 경우, 리포지터리와 프로덕션 간의 버전 갭을 최소화하기 위해 모든 변경 사항을 서로 가까이 Merge하기 위해 이해관계자와 조율합니다(일주일 이내로). 이러한 시나리오에서는 개발자 도구 및 환경을 먼저 업그레이드하고, 그 다음으로 프로덕션을 업그레이드하는 것이 가능합니다.
  • 더 큰 변경 사항의 경우, 새로운 루비로 프로덕션에 출시하는 위험이 상당합니다. 이러한 경우, 새로운 루비 버전과의 알려진 호환성 문제가 이미 모두 해결된 상태로 두고, GitLab 프로덕션 플리트의 일부에 새로운 루비를 배포하는 것이 좋습니다. 이러한 시나리오에서는 프로덕션을 먼저 업데이트하고, 개발자 도구 및 환경을 그 다음으로 업데이트하는 것이 롤백을 쉽게 만듭니다.

어떤 방법이든, 지난 경험으로부터 다음과 같은 방법이 잘 작동한다는 것을 발견했습니다. 일부 단계는 마이너 및 메이저 업그레이드에서만 필요할 수 있습니다. 일부 단계는 병렬로 진행되거나 순서가 뒤바뀌어야 할 수도 있습니다.

에픽 생성

에픽에서 이 작업을 추적하는 것은 진행 상황을 파악하는 데 유용합니다. 더 큰 업그레이드의 경우, 에픽 설명에 타임라인을 포함하여 이 사항에 대한 이해 관계자가 최종 전환이 예상되는 시점을 파악할 수 있도록 합니다. 업그레이드 단계를 개별 리포지터리로 나눠 이 에픽 아래 개별 문제에 대한 문제를 작성하세요.

업그레이드하는 의도를 전달

특히 새로운 기능을 도입하거나 사용 안 함으로 표시하는 업그레이드의 경우, 업그레이드가 예정되어 있음을 조기에 전달하세요. 업그레이드로 인한 중요한 변경 사항을 미리 알 수 있도록 중요하거나 주목할 만한 변경 사항에 대한 링크를 제공하세요.

GitLab 팀원들은 관련 슬랙 채널 (#backend 및 최소한 #development) 및 엔지니어링 주간 검토 (EWIR)에서 의도를 발표해야 합니다. 소통에서 업그레이드 에픽에 대한 링크를 포함하세요.

CI/CD 및 개발 환경에 새 루비 추가

새로운 루비로 Ruby 젬과 GitLab Rails 애플리케이션을 빌드하고 실행하려면 먼저 CI/CD 및 개발 환경을 새 루비 버전을 포함하도록 준비해야 합니다. 이 단계에서 아직은 기본 루비로 설정하면 안 되며, 대신 선택적으로 설정해야 합니다. 이렇게하면 일정 기간 동안 이전 및 새 루비 버전을 모두 지원하여 원활한 전환을 할 수 있습니다.

두 군데에서 변경이 필요합니다.

  1. GitLab Build Images. 이것은 러너 및 기타 Docker 기반 프리 프로덕션 환경에서 사용하는 Docker 이미지입니다. 필요한 변경의 종류에 따라 다릅니다.
    • 패치 레벨 업데이트의 경우, RUBY_VERSION의 패치 레벨을 증가시키면 같은 마이너 릴리스를 사용하는 모든 프로젝트가 새 패치 릴리스를 자동으로 다운로드합니다.
    • 메이저 및 마이너 업데이트의 경우, 업그레이드 프로세스 중에 기존 이미지와 함께 사용할 수 있는 새로운 Docker 이미지 세트를 만들어야 합니다. 중요: 새 Docker 이미지의 새로운 Ruby 버전과 일치하는 /patches 디렉터리의 모든 Ruby 패치 파일을 새로운 폴더에 복사하지 않으면 적용되지 않으므로, 이 점을 주의해야 합니다.
  2. GitLab Development Kit (GDK). 개발자들이 선택할 수 있도록 GDK를 업데이트하여 새 루비를 추가하세요. 일반적으로 .tool-versions에 이를 추가하기만 하면 되므로 asdf 사용자가 이를 활용할 수 있게 됩니다. 다른 사용자들은 매뉴얼으로 설치해야 합니다 (예제.)

보다 큰 버전 업그레이드의 경우, 품질 엔지니어링과 협력하여 테스트 계획을 식별하고 설정하는 것이 좋습니다.

서드파티 젬 업데이트

패치 릴리스의 경우, 이는 필요하지 않을 수 있지만, 마이너 및 메이저 릴리스의 경우에는 루비를 특정 버전으로 지정하는 경우에 중단이나 Bundler 의존성 문제가 발생할 수 있습니다. 무엇이 깨지는지 알아내는 좋은 방법은 gitlab-org/gitlab에서 Merge Request을 생성하고 무엇이 깨지는지 확인하는 것입니다.

GitLab 젬 및 관련 시스템 업데이트

일반적으로 이는 필수적인데, 직접 유지 관리하는 젬 또는 루비 애플리케이션은 .ruby-version, .tool-versions, 또는 .gitlab-ci.yml과 같은 빌드 설정을 포함합니다. GitLab Rails 애플리케이션이 새로운 루비로 작동할 수 있도록 이러한 리포지터리를 업데이트할 기술적 필요성은 항상 존재하지는 않지만, 모든 리포지터리에서 루비 버전을 일관되게 유지하는 것은 좋은 실천입니다. 마이너 및 메이저 업그레이드의 경우, 새로운 루비를 사용하여 이러한 리포지터리에 새로운 CI/CD 작업을 추가하세요. 빌드 매트릭스 정의가 이것을 효율적으로 수행할 수 있습니다.

업데이트할 리포지터리 결정

루비를 업그레이드하는 경우, ruby/gems 그룹의 리포지터리를 업데이트할 것을 고려하세요. 참고로, 이전에 이러한 프로젝트 중 일부를 위해 루비를 업데이트한 Merge Request 디렉터리은 다음과 같습니다:

메인 GitLab 애플리케이션과 함께 업데이트할 필수적인 리포지터리를 평가하려면:

  • 루비 버전 범위를 고려하세요.
  • 서비스 또는 라이브러리의 기능이 GitLab 전반의 작동에 어떤 역할을 하는지 고려하세요.

어떤 경우에는 Merge Request이 아직 준비되지 않았거나 즉시 Merge하는 데에 수용하지 않거나, 메인 애플리케이션 테스트 스위트가 새로운 루비 버전의 하위 호환성을 확인할 수 있는 라이브러리를 지연하는 것이 수용될 수 있습니다.

note
해당 코드 소유자들과 상의하여 GitLab 애플리케이션 업데이트 전에 이러한 변경 사항을 Merge하는 것이 허용되는지 여부를 상의하세요. 필요한 승인을 받는 것이 가장 좋겠지만, 모든 것이 준비되었을 때까지 변경을 Merge하지는 마세요.

GitLab 애플리케이션 MR 준비

의존성을 업데이트하고 새로운 젬 버전이 출시되면, 필요한 변경 사항과 유사하게 주 설치 및 업데이트 설명서에서 새로운 루비 버전의 반영을 업데이트할 수 있습니다. 그뿐만 아니라, 설명서를 업데이트하여 설치 및 업데이트 방법에서의 버전 변경을 반영하세요 (예시).

note
본 Merge Request을 시간에 맞추어주의하세요. 왜냐하면 이것이 Merge되자마자 GitLab 기여자 모두에 영향을 미치게 되고 변경 사항이 배포되기 때문입니다. 이 MR이 모든 것이 준비될 때까지 열려있었음을 보장하되, 초반에 승인을 받아 리드 타임을 줄이는 데 유용할 수 있습니다.

개발자가 업그레이드할 시간 제공 (Grace Period)

새로운 루비를 옵션으로 제공하고 모든 Merge Request이 준비되었거나 Merge된 후에는, 개발자가 자신의 컴퓨터에 새로운 루비를 설치할 수 있는 기간 (최소 1주)이 있어야 합니다. GDK 및 asdf 사용자의 경우, 이것은 gdk update를 통해 자동으로 진행되어야 합니다.

이 일시중단은 GitLab SaaS의 업그레이드 위험을 평가하는 좋은 시기입니다. 주요 버전 업그레이드와 같은 높은 위험성을 가진 루비 업그레이드의 경우, 변경 관리 요청을 통해 변경 사항을 인프라 팀과 조율하는 것이 권장됩니다. 모든 사람이 일정을 조율하고 변경 사항을 준비할 충분한 시간을 확보하기 위해 이러한 문제를 일찍 생성하세요.

새로운 루비를 기본으로 설정하세요

만약 알려진 버전 호환성 문제가 없고 일시중단 기간이 지나면, 모든 영향을 받는 리포지터리와 개발자 도구를 업데이트하여 새로운 루비를 기본으로 설정해야 합니다.

이 시점에서 GitLab Compose Kit (GCK)을 업데이트하세요. 이것은 docker-compose에서 GitLab을 실행하는 것을 선호하는 사용자를 위한 대안적인 개발 환경입니다. 이 프로젝트는 러너와 동일한 Docker 이미지에 의존하기 때문에 이 리포지터리의 변경과 동일하게 유지해야 합니다. 이 변경은 마이너 또는 메이저 버전 변경시에만 필요합니다 (예시.)

위에서 언급한대로, SaaS 가용성에 대한 루비 업그레이드의 영향이 불확실한 경우, 본 단계는 제대로 작동하는지 제품에서 검증되었음을 확인할 때까지 건너뛰는 것이 현명합니다. 이 경우, 먼저 다음 단계로 이동한 후, 검증 기간이 지난 후에 새로운 루비를 새로운 기본으로 승격하십시오.

CNG, Omnibus, Self-compiled 업데이트 및 GitLab MR Merge

마지막 단계는 새로운 루비를 프로덕션 환경에서 사용하는 것입니다. 이를 위해서 Omnibus 및 프로덕션 Docker 이미지를 업데이트하여 새 버전을 사용할 수 있도록 설정해야 합니다.

다음 프로젝트들을 업데이트하여 새로운 루비를 프로덕션 환경에서 사용하세요:

GitLab Helm Chart와 같은 차트도 루비를 실행하는 데 사용된 경우에도 업데이트해야 합니다. 예를 들어, 테스트를 실행하기 위해서 (이 예시) 이것이 절대적으로 필수적인 것은 아닐 수 있습니다.

변경 관리 요청을 제출하는 경우, 인프라 엔지니어들과 변화를 조율하십시오. 큰 업그레이드를 처리할 때는 릴리스 매니저들을 롤아웃 계획에 참여하십시오.

보안 패치를 위한 패치 릴리스 및 백포트 생성

업그레이드가 패치 릴리스이고 중요한 보안 패치가 포함된 경우, 이는 Self-Managed형 고객을 대상으로 GitLab 패치 릴리스로 출시되어야 합니다. 어떻게 진행해야 하는지에 대해 저희 릴리스 매니저들과 협상하세요.

Ruby 업그레이드 도구

업그레이드 프로세스를 용이하게 하는 여러 도구가 있습니다.

폐기 예정 Toolkit

Ruby 업그레이드의 일반적인 문제점은 폐기 경고가 오류로 전환된다는 것입니다. 이는 변경하기 전에 모든 폐기 경고를 해결해야한다는 것을 의미합니다. 새로운 경고가 기본 애플리케이션 브랜치로 들어가지 않도록하기 위해, 우리는 DeprecationToolkitEnv를 사용합니다. 이 모듈은 스펙 실행에서 발생한 폐기 경고를 관찰하고 이를 테스트 실패로 전환합니다. 이를 통해 개발자들이 새로운 루비에서 실패할 코드를 체크인하는 것을 방지합니다.

때로는 우리가 사용하는 Ruby gem이 이러한 경고를 내보내고 우리가 제어할 수 없을 때와 같이 새로운 경고를 통제하는 것을 피할 수 없는 경우도 있습니다. 이러한 경우에는 이 MR에서처럼 침묵을 추가합니다.

폐기 로거

또한 Ruby 및 Rails 폐기 경고를 log/deprecation_json.log라는 별도의 로그 파일에 기록합니다(GitLab Logging 문서에서 GitLab 로그 파일의 위치를 확인하세요). 이를 통해 테스트로 충분히 커버되지 않은 코드가 있을 때 코드에 대한 단서를 제공할 수 있습니다.

GitLab SaaS의 경우, GitLab 팀원은 Kibana에서 이러한 로그 이벤트를 검토할 수 있습니다(https://log.gprd.gitlab.net/goto/f7cebf1ff05038d901ba2c45925c7e01).

추천 사항

업그레이드 프로세스 중에 다음 권장 사항을 고려하세요:

  • 가능한 한 많은 변경을 최초에 진행하세요. 특히 마이너 및 메이저 릴리스의 경우, 애플리케이션 코드가 중단되거나 변경될 수 있습니다. 하위 호환성이 있는 모든 변경 사항은 주 브랜치로 Merge되어 릴리스되어야 합니다. 이를 통해 우리는 작은 단계로 이동하고 프로덕션 환경으로부터 초기 피드백을 받을 수 있습니다.
  • 대규모 업데이트를 위한 실험적 브랜치를 생성하세요. 일반적으로 우리는 장기 실행 토픽 브랜치를 피하려고 노력하지만, 피드백 및 실험 목적으로 이러한 브랜치를 가지고 있는 것이 유용할 수 있습니다. 새로운 루비를 실행할 때 CI/CD에서 정기적으로 피드백을 받을 수 있습니다. 이 MR에서 보여주는 것처럼 우리가 어떤 문제에 부딪힐지 최초로 평가할 때 유용할 수 있습니다. 이러한 실험적 브랜치는 Merge되도록 의도되지 않았으며, 필요한 모든 변경 사항이 분리되고 별도로 다시 Merge된 후에 닫을 수 있습니다.
  • 마일스톤 릴리스 이전에 문제를 해결할 충분한 시간을 확보하세요. GitLab은 빠르게 움직입니다. 루비 업그레이드는 많은 MR을 보내고 검토해야하므로, 모든 변경 사항이 릴리스 일주일 전에는 Merge되도록 보장하세요. 이를 통해 무언가가 실패할 경우 대응할 여유 시간을 확보할 수 있습니다. 의심이 든다면, 가용성을 우선시하는 것이 가용성을 우선시합니다. 다음 달로 업그레이드를 미루는 것이 더 나을 수 있습니다.