Ruby 업그레이드 가이드라인

우리는 성능 및 보안 업데이트와 새로운 Ruby API를 활용하기 위해 최신 Ruby MRI 릴리스를 사용하여 GitLab을 운영하기 위해 노력합니다. GitLab 전체적으로 Ruby를 업그레이드할 때는 다음과 같은 방식으로 진행해야 합니다.

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

Ruby 버전을 변경하기 전에, 이 문서를 주의 깊게 읽고 이해하여 변경이 필요한 내용에 대해 개략적으로 파악해야 합니다. 모든 Ruby 업그레이드가 이전과 조금씩 다를 가능성이 있으므로 문서화된 단계의 순서와 필요성을 평가해야 합니다.

Ruby 업그레이드 범위

Ruby를 업그레이드할 때 첫 번째로 고려해야 할 것은 범위입니다. 일반적으로 Ruby 업데이트가 발생할 수 있는 다음과 같은 영역을 고려합니다.

  • 주요 GitLab Rails 저장소.
  • 보조 Ruby 시스템 저장소.
  • 이러한 저장소의 시스템에서 사용되는 제3자 라이브러리.
  • 이러한 저장소의 시스템에서 사용되는 GitLab 라이브러리.

이들 중 모두를 건드려야 할 필요는 없을 수 있습니다. 예를 들어, 패치 레벨의 Ruby 업데이트는 제3자 젬을 업데이트하는 것이 필요하지 않을 수 있습니다.

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

범위를 평가할 때, Ruby 버전 수준이 중요합니다. 예를 들어, GitLab을 Ruby 2.x에서 3.x로 업그레이드하는 것은 Ruby 2.7.2에서 2.7.4로 업그레이드하는 것보다 어렵고 위험할 수 있습니다. 보통 패치 릴리스는 보안 또는 버그 수정으로 제한되므로 이를 유의해야 하며, 업그레이드를 준비하고 그에 따라 계획을 세워야 합니다.

미래 업그레이드의 범위를 추정하는 데 도움이 되도록 다음 업그레이드에 필요한 노력을 참조하세요.

영향을 받는 대상과 대상 그룹

어떤 업그레이드 전에도 Ruby 업그레이드에 영향을 받는 순서대로 모든 대상과 대상 그룹을 고려해야 합니다.

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

Ruby 업그레이드 접근 방식

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

  • 제품의 행동이 변경될 가능성이 적은 작은 업그레이드의 경우, 저장소와 프로덕션 간의 버전 차이를 최소화해야 합니다. 알려진 모든 호환성 문제가 이미 해결되어 있는 상태로 설비 엔지니어들과 협력하여 변경 사항을 밀접하게(하루 이내) 병합하기 위해 이해 관계자와 조정하세요. 이 시나리오에서는 개발자 도구 및 환경을 먼저 업그레이드하고, 그 후에 프로덕션을 업그레이드하는 게 일반적입니다.
  • 큰 변경 사항의 경우, 새로운 Ruby로 프로덕션에 진입하는 위험이 큽니다. 이 경우, 새로운 Ruby 버전과의 알려진 호환성 문제가 이미 해결된 상태가 되는 것이 중요합니다. 그 후에 프로덕션 엔지니어와 협력하여 GitLab 프로덕션의 일부로 새로운 Ruby를 배포하는 작업을 진행하세요. 이 시나리오에서는 프로덕션을 먼저 업데이트하고, 개발자 도구 및 환경을 그 다음에 업그레이드하는 게 롤백을 쉽게 만듭니다.

어떤 방법으로든, 우리는 지난 경험을 통해 다음과 같은 접근 방식이 잘 작동한다는 것을 알게 되었습니다. 일부 단계는 마이너 및 메이저 업그레이드에만 필요한 경우가 있고, 일부 단계는 병렬로 진행될 수 있거나 상기한 바와 같이 순서가 바뀔 수 있습니다.

Epic 생성

대규모 업그레이드의 경우 Epic에 타임라인을 포함하여 설명하면 이해 관계자들이 최종 전환일이 언제 예정되어 있는지 알 수 있으므로 진행 상황을 파악하는 데 유용합니다. 업그레이드 관련이 된 성격을 가진 변경사항에 대해서는 Epic에 트래킹하는 것이 유용합니다.

Epic 아래에서 개별 저장소의 변경 내용을 별도의 이슈로 구분합니다.

업그레이드 의도 전달

특히 기능을 도입하거나 사용하지 않게 되는 업그레이드의 경우, 가능한 빨리 업그레이드가 예정된 것을 알려주세요. 그리고 이에 연결된 타임라인이 있으면 더 좋습니다. 중요하거나 주목할 만한 변경 사항에 대한 링크를 제공하여 개발자가 변경 내용에 미리 익숙해지도록 합니다.

GitLab 팀 구성원들은 업그레이드 의도를 관련된 Slack 채널(#backend#development 최소한)과 Engineering Week In Review(EWIR)에서 공지해야 합니다. 또한, 커뮤니케이션에 업그레이드 Epic의 링크를 포함해야 합니다.

새로운 Ruby 추가하기

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

변경 사항이 필요한 두 곳이 있습니다:

  1. GitLab 빌드 이미지. 이것은 러너와 다른 Docker 기반의 사전 생산 환경에 사용되는 Docker 이미지입니다. 필요한 변경의 종류에 따라 달라집니다.
    • 패치 레벨 업데이트의 경우, RUBY_VERSION의 패치 레벨을 증가시키면 됩니다. 동일한 마이너 릴리스를 사용하는 모든 프로젝트가 새로운 패치 릴리스를 자동으로 다운로드합니다.
    • 주요 및 마이너 업데이트의 경우, 기존 이미지와 함께 사용할 수 있는 새로운 Docker 이미지 집합을 만들어야 합니다. 중요: 새로운 폴더에 모든 Ruby 패치 파일을 기존 /patches 디렉토리에서 새로 업그레이드할 Ruby 버전과 일치하도록 복사해야 합니다. 그렇지 않으면 적용되지 않습니다.
  2. GitLab Development Kit (GDK). GDK를 업데이트하여 개발자가 선택할 수 있는 새로운 Ruby를 추가합니다. 보통 .tool-versions에 추가만 하면 됩니다. 이렇게 하면 asdf 사용자가 이점을 얻을 수 있습니다. 다른 사용자는 수동으로 설치해야 합니다. (예시: https://gitlab.com/gitlab-org/gitlab-development-kit/-/merge_requests/2136.)

대규모 버전 업그레이드의 경우, Quality Engineering와 함께 테스트 계획을 수립하는 것을 고려해보세요.

타사 gem 업데이트

패치 릴리스의 경우 이것이 필요하지는 않겠지만, 마이너 및 메이저 릴리스의 경우에는 gem이 Ruby를 특정 버전으로 고정할 때 중요한 변경 사항이나 Bundler 종속성 문제가 발생할 수 있습니다. 무엇이 깨졌는지 알아보기 위해 gitlab-org/gitlab에서 병합 요청을 만들어 보는 것이 좋습니다.

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

GitLab Rails 애플리케이션이 새로운 Ruby와 작동하도록하기 위해 우리가 유지 보수하는 gem이나 Ruby 애플리케이션에는 .ruby-version, .tool-versions, 또는 .gitlab-ci.yml과 같은 빌드 설정이 포함되어 있기 때문에 일반적으로 이것이 필요합니다. 모든 저장소에서 Ruby 버전을 일관되게 유지하는 것이 좋은 실천 방법입니다. 주요 및 마이너 업그레이드의 경우, 새로운 Ruby를 사용하여 이러한 저장소에 새로운 CI/CD 작업을 추가합니다. 빌드 매트릭스 정의를 사용하여 이를 효율적으로 수행할 수 있습니다.

업데이트할 저장소 결정

Ruby를 업그레이드할 때는 ruby/gems 그룹에 있는 저장소들을 업데이트하는 것도 고려해야 합니다. 여기에는 과거에 이러한 프로젝트 중 일부를 업데이트한 병합 요청 목록이 있습니다:

GitLab 애플리케이션과 함께 업데이트해야 하는지 평가하는 데 사용되는 기준은:

  • Ruby 버전 범위.
  • 서비스 또는 라이브러리의 전반적인 기능에 대한 역할.

어떤 저장소를 업데이트할지 평가하기 위해 완전한 GitLab 프로젝트 목록을 참조하세요. 좀 더 작은 버전 업그레이드의 경우에는 GitLab 애플리케이션 테스트 스위트에서 새로운 Ruby 버전의 하향 충돌을 잡아낼 수 있다고 확신되거나 중요하지 않은 라이브러리를 지연시키는 것이 허용됩니다.

참고: GitLab 애플리케이션을 업데이트하기 전에 해당 코드 소유자들과 상의하여 이러한 변경 내용을 먼저 병합하는 것이 허용될지 상의하십시오. 필요한 승인을 받는 것이 가장 좋지만 모든 것이 준비될 때까지 변경 사항을 병합하지는 말아야 할 수 있습니다.

GitLab 애플리케이션 MR 준비

의존성을 업데이트했고 새로운 gem 버전이 릴리스된 상태에서, 필요한 변경 사항과 관련 시스템과 유사하게 메인 Rails 애플리케이션을 업데이트할 수 있습니다. 또한 설치 및 업데이트 지침에 버전 변경을 반영하도록 문서를 업데이트하세요 (예시).

참고: 이 MR을 타이밍에 특히 주의해서 병합해야 합니다. MR이 한 번 병합되는 즉시, 모든 GitLab 기여자들이 영향을 받고 변경 내용이 배포됩니다. 이 MR은 모든 준비가 완료될 때까지 열려 있어야 하지만, 리드 타임을 줄이기 위해 일찍 승인을 받을 수도 있습니다.

개발자가 업그레이드할 시간을 확보하세요 (원만한 기간)

새로운 Ruby가 옵션으로 제공되고 모든 MR이 준비되었거나 합쳐졌다면, 개발자가 자신의 기계에 새로운 Ruby를 설치할 수 있도록 일주일 이상의 원만한 기간을 설정해야 합니다. GDK 및 asdf 사용자의 경우 gdk update를 통해 자동으로 이 기간을 설정해야 합니다.

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

Ruby를 기본 값으로 설정하세요

알려진 버전 호환성 문제가 없고 원만한 기간을 지나면 영향을 받는 모든 저장소 및 개발 도구를 새로운 Ruby를 기본 값으로 업데이트해야 합니다.

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

위에서 언급한 바와 같이, SaaS 가용성에 대한 Ruby 업그레이드의 영향이 불확실한 경우, 이 단계는 제품에서 원활하게 실행되는 것을 확인한 후에 진행하는 것이 현명합니다. 이 경우, 먼저 다음 단계로 넘어가고, 확인 기간이 지나면 새로운 Ruby를 새로운 기본 값으로 승격하세요.

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

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

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

GitLab Helm Chart와 같은 차트는 Ruby를 일부 용도로 사용하는 경우 업데이트해야 하지만, 예를 들어 테스트를 실행하는 경우 (이 예시)이지만 엄격히 필요한 것은 아닐 수 있습니다.

변경 관리 요청을 제출하면, 인프라 엔지니어들과 함께 롤아웃을 조정하세요. 더 큰 업그레이드를 다룰 때에는 릴리스 매니저를 롤아웃 계획에 참여하세요.

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

만약 업그레이드가 패치 릴리스이고 중요한 보안 패치를 포함한다면, 이를 자체 관리 고객에게 GitLab 패치 릴리스로 릴리스해야 합니다. 진행 방법에 대해 자세히 알아보려면 릴리스 매니저에게 상담하세요.

Ruby 업그레이드 도구

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

사용 중단 도구킷

Ruby 업그레이드에서 자주 발생하는 문제 중 하나는 사용 중단 경고가 오류로 전환되는 것입니다. 이는 모든 사용 중단 경고가 전환되기 전에 해결해야 한다는 것을 의미합니다. 새로운 경고가 메인 애플리케이션 브랜치에서 발생하지 않도록하기 위해 우리는 DeprecationToolkitEnv를 사용합니다. 이 모듈은 spec 실행에서 발생하는 사용 중단 경고를 관찰하고 이를 테스트 실패로 변환합니다. 이를 통해 새로운 Ruby에서 실패할 수 있는 새 코드를 커밋하는 것을 방지합니다.

가끔은 피할 수 없고, 예를 들어 사용하는 Ruby gem이 이러한 경고를 내보내고 우리가 그에 대한 제어권이 없는 경우에, 이 MR에서와 같이 경고를 추가하세요.

사용 중지 로거

우리는 또한 전용 로그 파일 log/deprecation_json.log(GitLab 로깅을 참조하십시오(로그 파일에 대한 GitLab 개발자 안내서)에서 GitLab 로그 파일의 위치), 루비 및 레일스 사용 중지 경고를 기록합니다. 이는 테스트에 충분히 커버되지 않은 코드가 있을 때 코드 추적키트 환경을 빠져나갈 수 있기 때문에 힌트를 제공할 수 있습니다.

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

권장 사항

업그레이드 프로세스 중에 다음을 고려하십시오:

  • 가능한 많은 변경 사항을 최초로 로드합니다. 특히 작고 큰 배포에 대해서, 어플리케이션 코드가 깨지거나 변경될 가능성이 높습니다. 역호환성이 있는 모든 변경사항은 메인 브랜치에 병합되고 루비 버전 업그레이드 전에 독립적으로 릴리즈되어야 합니다. 이렇게 함으로써 우리는 작은 단계로 전진하고 프로덕션 환경에서 초기 피드백을 받을 수 있습니다.
  • 대규모 업데이트를 위한 실험적인 브랜치를 만드십시오. 일반적으로 우리는 긴 러닝 토픽 브랜치를 피하지만 피드백과 실험을 위해서는 그러한 브랜치가 유용할 수 있습니다. 새로운 루비 버전을 실행할 때 정기적으로 CI/CD로부터 피드백을 받기 위해 이러한 브랜치가 유용할 수 있습니다. 이 MR에서 보여주는 것처럼 어떤 문제에 부딪힐지 최초로 평가할 때 유용할 수 있습니다. 실험적인 브랜치는 병합되도록 의도된 것이 아닙니다. 필요한 변경사항이 모두 분리되고 독립적으로 병합된 후에 닫힐 수 있습니다.
  • 마일스톤 릴리스 전에 문제를 해결할 충분한 시간을 확보하십시오. GitLab은 빠르게 움직입니다. 루비 업그레이드는 여러 MR을 보내고 검토해야 하므로 릴리스 날짜의 최소 1주 전에 모든 변경사항이 병합되도록 해야 합니다. 이렇게 함으로써 뭔가 깨지면 조치할 시간을 따로 확보할 수 있습니다. 의심스러울 때는 가용성을 우선시하는 것이 좋으므로 업그레이드를 다음 달로 연기하는 것이 더 좋습니다.