루비 업그레이드 가이드라인

우리는 GitLab이 성능 및 보안 업데이트와 새로운 루비 API의 혜택을 누릴 수 있도록 최신 Ruby MRI 릴리스를 사용하는 것을 목표로 합니다. GitLab에서 루비를 업그레이드할 때는 다음과 같은 방식으로 진행해야 합니다:

  • 기여자에게 가장 적은 방해가 되도록.
  • GitLab SaaS 가용성을 최적화하도록.
  • GitLab의 모든 부분에서 루비 버전의 일관성을 유지하도록.

루비 버전 변경을 하기 전에 이 문서를 주의 깊게 읽고 전체를 이해하여 어떤 변경이 필요할 수 있는지에 대한 높은 수준의 인식을 가져야 합니다. 각 루비 업그레이드가 이전과 조금씩 다를 수 있으므로, 문서에 기록된 단계의 순서와 필요성을 평가해야 합니다.

루비 업그레이드의 범위

루비를 업그레이드할 때 가장 먼저 고려해야 할 것은 범위입니다. 일반적으로 루비 업데이트가 필요할 수 있는 다음의 영역을 고려합니다:

  • 주요 GitLab Rails 리포지토리.
  • 기타 루비 시스템 리포지토리.
  • 이러한 리포지토리의 시스템에서 사용하는 모든 서드파티 라이브러리.
  • 이러한 리포지토리의 시스템에서 사용하는 모든 GitLab 라이브러리.

모든 것을 반드시 건드릴 필요는 없습니다. 예를 들어, 패치 수준의 루비 업데이트는 서드파티 젬에서 업데이트가 필요하지 않을 수 있습니다.

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

범위를 평가할 때, 루비 버전 수준이 중요합니다. 예를 들어, GitLab을 루비 2.x에서 3.x로 업그레이드하는 것이 루비 2.7.2에서 2.7.4로 업그레이드하는 것보다 더 어렵고 위험합니다. 패치 릴리스는 일반적으로 보안이나 버그 수정에 제한되기 때문입니다.

업그레이드를 준비할 때 이 점을 염두에 두고 계획해야 합니다.

향후 업그레이드의 범위를 추정하는 데 도움이 되는 노력은 다음의 업그레이드를 참조하세요:

영향을 받는 청중 및 대상

업그레이드를 진행하기 전에 모든 청중 및 대상을 고려하고, 루비 업그레이드의 영향을 가장 즉각적으로 받는 순서로 나열합니다:

  1. 개발자. 우리는 회사 내부와 외부의 GitLab 및 관련 프로젝트에 많은 기여자가 있습니다. .ruby-version과 같은 파일을 변경하면 이러한 파일을 해석하는 도구를 사용하는 모든 사람에게 영향을 미칩니다. 개발자는 병합된 변경 사항을 포함하는 리포지토리에서 풀(Pull)할 때 즉시 영향을 받습니다.

  2. GitLab CI/CD. 우리는 코드 통합 및 테스트를 위해 CI/CD를 많이 활용합니다. CI/CD 작업은 .ruby-version과 같은 파일을 해석하지 않습니다. 대신, CI/CD 작업은 .gitlab-ci.yml에서 정의된 Docker 컨테이너에 설치된 루비를 사용합니다. 이 작업에서 사용되는 컨테이너 이미지는 gitlab-build-images 리포지토리에서 유지 관리됩니다. 이미지를 업데이트하면, 이미지가 빌드될 때 CI/CD 작업이 즉시 영향을 받습니다.

  3. GitLab SaaS. GitLab.com은 Cloud Native GitLab (CNG)의 Docker 이미지를 사용하는 맞춤형 Helm 차트에서 배포됩니다. CI/CD와 마찬가지로, 이 환경에서는 .ruby-version이 의미가 없습니다. 대신, 이러한 Docker 이미지를 패치하여 루비를 업그레이드해야 합니다. GitLab SaaS는 다음 배포 시 영향을 받습니다.

  4. 셀프 관리 GitLab. Omnibus를 통해 GitLab을 설치하는 고객은 위의 어떤 것도 사용하지 않습니다. 대신, 그들의 루비 버전은 Omnibus의 루비 소프트웨어 번들로 정의됩니다. 셀프 관리 고객은 이 변경 사항을 포함하는 릴리스를 업그레이드하는 즉시 영향을 받습니다.

루비 업그레이드 접근 방식

루비 업그레이드의 모든 단계를 정확하게 타이밍하는 것은 매우 중요합니다. 일반적인 지침으로 다음을 고려하세요:

  • 프로덕션 동작이 변경될 가능성이 적은 소규모 업그레이드의 경우, 리포지토리와 프로덕션 간의 버전 차이를 최소한으로 유지하는 것을 목표로 합니다. 이해관계자와 조정하여 모든 변경 사항을 가급적 가까운 시일 내에 통합하여 드리프트를 피하도록 합니다. 이 경우 선호되는 순서는 개발자 도구 및 환경을 먼저 업그레이드하고, 프로덕션을 두 번째로 업그레이드하는 것입니다.

  • 더 큰 변경의 경우, 새로운 루비와 함께 프로덕션으로 가는 위험은 상당합니다. 이 경우 새로운 루비 버전에서 알려진 모든 호환성 문제를 이미 해결한 상태로 만드는 것이 좋습니다. 그런 다음 프로덕션 엔지니어와 협력하여 새로운 루비를 GitLab 프로덕션 플릿의 일부에 배포합니다. 이 경우 선호되는 순서는 프로덕션을 먼저 업데이트하고, 개발자 도구 및 환경을 두 번째로 업데이트하는 것입니다. 이는 프로덕션에서 중요한 회귀가 발생할 경우 롤백을 더 쉽게 합니다.

어쨌든 우리는 과거 경험으로부터 다음 접근 방식이 잘 작동한다는 것을 발견했으며, 일부 단계는 소규모 및 대규모 업그레이드에만 필요할 수 있습니다. 참고로 이러한 단계 중 일부는 병행하여 진행될 수 있거나 위에서 설명한 대로 순서가 바뀔 수 있습니다.

에픽 만들기

이 작업을 에픽으로 추적하는 것은 진행 상황을 파악하는 데 유용합니다. 더 큰 업그레이드의 경우, 에픽 설명에 타임라인을 포함하여 이해관계자들이 최종 전환이 언제 활성화될 것으로 예상되는지를 알 수 있도록 합니다. 업그레이드의 성능 기준을 보장하기 위해 지정된 성능 테스트 템플릿을 포함하세요.

개별 리포지토리의 변경 사항은 이 에픽 하에 별도의 이슈로 분리합니다.

업그레이드 의도 전달하기

특히 기능을 도입하거나 폐지하는 업그레이드의 경우, 업그레이드가 예정되어 있다는 것을 조기에 커뮤니케이션하고, 이상적으로는 관련된 타임라인과 함께 전달합니다. 중요하거나 주목할만한 변경 사항에 대한 링크를 제공하여 개발자들이 사전에 변경 사항에 익숙해질 수 있도록 합니다.

GitLab 팀원들은 관련 슬랙 채널( #backend 및 ` #development ` 최소)과 Engineering Week In Review (EWIR)에서 의도를 발표해야 합니다. 커뮤니케이션에서 업그레이드 에픽에 대한 링크도 포함하세요.

CI/CD 및 개발 환경에 새로운 루비 추가하기

새로운 루비를 사용하여 루비 젬과 GitLab Rails 애플리케이션을 빌드하고 실행하기 위해, 먼저 CI/CD와 개발 환경을 새로운 루비 버전을 포함하도록 준비해야 합니다. 이 단계에서는 아직 기본 루비로 만들지 말고 대신 선택적으로 만드세요. 이는 일정 기간 동안 이전 루비 버전과 새로운 루비 버전을 모두 지원하여 보다 원활한 전환을 허용합니다.

변경이 필요한 두 가지 장소가 있습니다:

  1. GitLab Build Images. 이는 우리가 러너 및 기타 Docker 기반의 프로덕션 환경에서 사용하는 Docker 이미지입니다. 필요한 변경의 세부 사항은 범위에 따라 다르며
    • 패치 수준 업데이트의 경우, RUBY_VERSION의 패치 수준을 증가시키는 것으로 충분해야 합니다. 동일한 마이너 릴리스를 빌드하는 모든 프로젝트는 자동으로 새로운 패치 릴리스를 다운로드합니다.
    • 주요 및 마이너 업데이트의 경우, 업그레이드 과정에서 기존 이미지와 나란히 사용할 수 있는 새로운 Docker 이미지 세트를 생성합니다. 중요: /patches 디렉토리의 모든 루비 패치 파일을 업그레이드하려는 루비 버전에 해당하는 새 폴더로 복사해야 적용됩니다.
  2. GitLab Development Kit (GDK). GDK를 업데이트하여 새로운 루비를 개발자들이 선택할 수 있는 추가 옵션으로 추가합니다. 이는 일반적으로 .tool-versions에 추가하는 것만 필요합니다, 그래서 asdf 사용자들이 이점을 누릴 수 있습니다. 다른 사용자는 수동으로 설치해야 합니다. (예시.)

더 큰 버전 업그레이드의 경우, 품질 엔지니어링과 협력하여 테스트 계획을 확인하고 설정하는 것을 고려하세요.

타사 젬 업데이트

패치 릴리스의 경우 이는 필요하지 않을 가능성이 높지만, 마이너 및 메이저 릴리스의 경우 젬이 특정 버전의 Ruby에 고정될 때 파괴적인 변화나 Bundler 종속성 문제가 발생할 수 있습니다. 이를 확인하는 좋은 방법은 gitlab-org/gitlab에 병합 요청을 생성하고 어떤 것이 깨지는지 확인하는 것입니다.

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

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

업데이트할 저장소 결정

Ruby를 업그레이드할 때 ruby/gems 그룹의 저장소도 업데이트하는 것을 고려하십시오. 참고로, 다음은 과거에 일부 프로젝트를 위해 Ruby를 업데이트한 병합 요청 목록입니다:

이러한 저장소 중 어떤 것이 GitLab 애플리케이션과 함께 업데이트되는 것이 중요한지 평가할 때는 다음을 고려하십시오:

  • Ruby 버전 범위.
  • 서비스 또는 라이브러리가 GitLab 전반의 기능에서 하는 역할.

어떤 저장소가 영향을 받을 수 있는지에 대한 전체 목록은 GitLab 프로젝트 목록을 참조하십시오.

작은 버전 업그레이드의 경우 비필수 라이브러리를 업데이트하는 것을 지연하는 것이 허용될 수 있으며, 새로운 Ruby 버전에서 주요 애플리케이션 테스트 스위트가 회귀를 발견할 것이라는 확신이 있을 경우에는 더욱 그렇습니다.

note
GitLab 애플리케이션을 업데이트하기 전에 이러한 변경을 병합하는 것이 허용되는지 해당 코드 소유자와 상담하십시오. 필요한 승인을 받는 것이 가장 좋지만, 모든 것이 준비될 때까지 변경 사항을 병합하는 것을 기다리는 것이 좋을 수 있습니다.

GitLab 애플리케이션 MR 준비하기

종속성이 업데이트되고 새로운 젬 버전이 출시되었으므로, 젬 및 관련 시스템과 유사하게 필요한 변경 사항으로 메인 Rails 애플리케이션을 업데이트할 수 있습니다.

또한 설치 및 업데이트 지침에서 버전 변경을 반영하도록 문서를 업데이트합니다 (예시).

참고:

이 병합 요청의 타이밍에 특히 주의해야 합니다. 병합되는 순간, 모든 GitLab 기여자에게 영향을 미치고 변경 사항이 배포됩니다. 이 MR은 모든 것이 준비될 때까지 열려 있어야 하지만, 리드 타임을 줄이기 위해 조기에 승인을 받는 것이 유용할 수 있습니다.

개발자에게 업그레이드 시간을 주기 (유예 기간)

새로운 Ruby가 옵션으로 제공되며, 모든 병합 요청이 준비되거나 병합되었으므로, 개발자가 자신의 기계에 새로운 Ruby를 설치할 수 있는 유예 기간(최소 1주일)이 있어야 합니다. GDK 및 asdf 사용자에게는 gdk update를 통해 자동으로 발생해야 합니다.

이 중단 기간은 GitLab SaaS에 대한 이 업그레이드의 위험을 평가하기에 좋은 시간입니다.

주요 버전 업그레이드와 같은 고위험 Ruby 업그레이드의 경우, 인프라 팀과 변경 관리 요청을 통해 변경 사항을 조정하는 것이 좋습니다.

모두가 변경 사항을 일정에 맞춰 준비할 수 있도록 이 이슈를 조기에 생성하세요.

기본 Ruby로 설정하기

알려진 버전 호환성 문제가 없고 유예 기간이 지난 경우, 모든 영향을 받는 저장소와 개발 도구는 새로운 Ruby를 기본으로 설정하도록 업데이트되어야 합니다.

이 시점에서 GitLab Compose Kit(GCK)을 업데이트합니다.

이것은 docker-compose에서 GitLab을 실행하는 것을 선호하는 사용자를 위한 대체 개발 환경입니다.

이 프로젝트는 우리의 러너와 동일한 Docker 이미지를 사용하므로 해당 저장소의 변경 사항과 동기화를 유지해야 합니다.

이 변경은 마이너 또는 주요 버전 변경 시에만 필요합니다 (예시.)

위에서 언급한 대로, Ruby 업그레이드가 SaaS 가용성에 미치는 영향을 확인할 수 없는 경우, 이 단계는 프로덕션에서 원활하게 실행되는지를 확인할 때까지 건너뛰는 것이 현명합니다.

이 경우 먼저 다음 단계로 이동한 다음, 검증 기간이 지난 후에 새로운 Ruby를 기본으로 승격합니다.

CNG, Omnibus, 자체 컴파일을 업데이트하고 GitLab MR 병합하기

마지막 단계는 프로덕션에서 새로운 Ruby를 사용하는 것입니다.

이 작업은 Omnibus 및 프로덕션 Docker 이미지를 새 버전을 사용하도록 업데이트해야 합니다.

프로덕션에서 새로운 Ruby를 사용하려면, 다음 프로젝트를 업데이트하세요:

GitLab Helm Chart와 같은 차트도 Ruby를 사용하는 경우 업데이트되어야 하며, 예를 들어 테스트를 실행하는 데 사용됩니다 ( 이 예시 참조), 비록 이것이 엄격히 필요하지 않을 수 있습니다.

변경 관리 요청을 제출하는 경우, 인프라 엔지니어와 롤아웃을 조정하세요.

더 큰 업그레이드를 다룰 때는 릴리스 관리자를 롤아웃 계획에 포함시키세요.

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

업그레이드가 패치 릴리스였고 중요한 보안 수정을 포함하고 있다면, GitLab 패치 릴리스로 자체 관리 고객에게 발표되어야 합니다. 진행 방법에 대해서는 우리의 릴리스 관리자에게 문의하세요.

루비 업그레이드 도구

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

중단 예정 도구 키트

루비 업그레이드에서 일반적인 문제는 중단 예정 경고가 오류로 변할 수 있다는 점입니다. 즉, 전환하기 전에 모든 중단 예정 경고를 해결해야 합니다. 새로운 경고가 주요 애플리케이션 브랜치에 유입되는 것을 피하기 위해, 우리는 DeprecationToolkitEnv를 사용합니다. 이 모듈은 스펙 실행에서 발생하는 중단 예정 경고를 관찰하고 이를 테스트 실패로 전환합니다. 이로 인해 개발자들이 새로운 루비에서 실패할 코드가 체크인되는 것을 방지합니다.

때로는 우리가 사용하는 루비 젬이 이러한 경고를 발생시키고, 우리가 그것을 통제할 수 없을 때 새로운 경고를 도입하는 것을 피할 수 없습니다. 이런 경우에는 이 병합 요청처럼 침묵을 추가하십시오.

중단 예정 로거

우리는 또한 루비와 Rails의 중단 예정 경고를 전용 로그 파일 log/deprecation_json.log에 기록합니다 (어디서 GitLab 로그 파일을 찾는지에 대한 정보는 GitLab 개발자 가이드를 참조하세요), 이는 테스트로 충분히 커버되지 않는 코드가 있을 때 단서를 제공할 수 있으며, 따라서 DeprecationToolkitEnv를 통과할 수 있습니다.

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

추천 사항

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

  • 가능한 한 많은 변경 사항을 미리 반영하세요. 특히 마이너 및 메이저 릴리스의 경우, 애플리케이션 코드가 깨지거나 변경될 가능성이 높습니다. 하위 호환되는 모든 변경 사항은 주요 브랜치에 병합되어야 하며, Ruby 버전 업그레이드 이전에 독립적으로 발표되어야 합니다. 이렇게 하면 소규모 증가로 진행할 수 있으며, 생산 환경에서 조기에 피드백을 받을 수 있습니다.

  • 더 큰 업데이트를 위한 실험적 브랜치를 생성하세요. 우리는 일반적으로 긴 주제 브랜치를 피하려고 하지만, 피드백과 실험을 위한 목적상, 새로운 루비를 실행할 때 CI/CD로부터 정기적인 피드백을 받을 수 있는 그러한 브랜치가 유용할 수 있습니다. 이는 이 MR이 보여주는 바와 같이 우리가 어떤 문제에 직면할 수 있는지를 처음 평가하는 데 도움이 될 수 있습니다. 이러한 실험적 브랜치는 병합할 목적으로 설계되지 않았으며, 필요한 모든 변경 사항이 분리되어 독립적으로 병합된 후에는 폐쇄될 수 있습니다.

  • 이정표 릴리스 전에 문제를 수정할 충분한 시간을 주세요. GitLab은 빠르게 움직입니다. Ruby 업그레이드에는 보내고 검토해야 할 많은 MR이 필요하므로, 모든 변경 사항이 릴리즈 일주일 전에 병합되었는지 확인하세요. 이렇게 하면 무언가가 문제가 발생할 경우 대응할 수 있는 여유 시간이 생깁니다. 의심스럽다면, 다음 달로 업그레이드를 미루는 것이 좋습니다. 우리는 속도보다 가용성을 우선시합니다.