Ruby 업그레이드 가이드라인
우리는 최신 Ruby MRI 릴리스를 사용하여 GitLab을 실행하여 성능 및 보안 업데이트 및 새로운 Ruby API의 이점을 누리기 위해 노력합니다. GitLab 전반에 걸쳐 Ruby를 업그레이드할 때, 다음 사항을 고려하여 진행해야 합니다.
- 기여자에게 가장 적은 방해를 줍니다.
- GitLab SaaS의 가용성을 최적화합니다.
- GitLab의 모든 부분에서 Ruby 버전을 동일하게 유지합니다.
Ruby 버전을 변경하기 전에 이 문서를 주의 깊게 읽어 진행할 변경 사항에 대한 대략적인 이해를 얻습니다. 모든 Ruby 업그레이드가 이전과 조금씩 다를 수 있으므로 문서화된 단계의 순서와 필요성을 평가합니다.
Ruby 업그레이드 범위
Ruby를 업그레이드할 때 고려해야 할 첫 번째 사항은 범위입니다. 일반적으로 Ruby 업데이트가 필요한 다음 영역을 고려합니다.
- 주요 GitLab Rails 리포지터리.
- 부수적인 Ruby 시스템 리포지터리.
- 이러한 리포지터리에서 사용하는 타사 라이브러리.
- 이러한 리포지터리에서 사용하는 GitLab 라이브러리.
이 모두를 항상 손대야 하는 것은 아닙니다. 예를 들어, 패치 레벨의 Ruby 업데이트가 타사 젬의 업데이트를 요구하지 않을 수 있습니다.
패치, 마이너 및 메이저 업그레이드
범위를 평가할 때 Ruby 버전 수준이 중요합니다. 예를 들어, Ruby 2.x에서 3.x로 GitLab를 업그레이드하는 것은 Ruby 2.7.2에서 2.7.4로 업그레이드하는 것보다 어렵고 위험합니다. 패치 릴리스는 일반적으로 보안 또는 버그 수정에 제한됩니다. 업그레이드를 준비할 때 이 점을 유의해야 하며, 그에 맞게 계획을 세워야 합니다.
향후 업그레이드 범위를 추정하는 데 도움이 되도록 다음 업그레이드에 필요한 노력을 확인하세요.
영향을 받는 대상 및 대상
어떤 업그레이드 전에든 Ruby 업그레이드로 인해 영향을 받는 대상 및 대상을 고려합니다. Ruby 업그레이드로 인해 영향을 받는 정도에 따라 순서를 매겨보세요.
-
개발자. 회사 내외의 GitLab 및 관련 프로젝트에 많은 기여자들이 있습니다.
.ruby-version
과 같은 파일을 해석하는 도구를 사용하는 모든 사람에게 영향을 줍니다. 변경된 파일을 포함하는 리포지터리에서 pull하는 즉시 개발자들은 영향을 받습니다. -
GitLab CI/CD. 코드 통합 및 테스트를 위해 CI/CD에 크게 의존합니다. CI/CD 작업은
.ruby-version
과 같은 파일을 해석하지 않습니다. 대신, 그들은 실행되는 Docker 컨테이너에 정의된 Ruby를 사용합니다(.gitlab-ci.yml
에 정의). 이러한 작업에서 사용되는 컨테이너 이미지는gitlab-build-images
리포지터리에서 관리됩니다. 이미지가 빌드되면 CI/CD 작업은 영향을 받습니다. -
GitLab SaaS. GitLab.com은 Cloud Native GitLab (CNG)에서 Docker 이미지를 사용하는 맞춤형 Helm 차트에서 배포됩니다.
CI/CD와 마찬가지로,
.ruby-version
은 이 환경에서 무의미합니다. 대신, 이러한 Docker 이미지를 패치하여 Ruby를 업그레이드해야 합니다. GitLab SaaS는 다음 배포에서 영향을 받습니다. - 자체 설치형 GitLab. Omnibus를 통해 GitLab을 설치하는 고객은 위의 방법을 사용하지 않습니다. 대신, 그들의 Ruby 버전은 Omnibus의 Ruby 소프트웨어 번들에 의해 정의됩니다. 자체 설치형 고객들은 해당 변경이 포함된 릴리스로 업그레이드하자마자 영향을 받습니다.
Ruby 업그레이드 접근 방식
Ruby 업그레이드의 모든 단계를 올바르게 타이밍하는 것이 중요합니다. 일반적인 가이드라인으로 다음을 고려하세요.
- 프로덕션 동작이 변경될 가능성이 적은 소규모 업그레이드의 경우, 리포지터리와 프로덕션 간 버전 차이를 최소화하도록 노력하세요. 변경 사항을 가능한 한 가까이(1~2일 이내) 함께 Merge하기 위해 이해 관계자와 조율합니다. 이러한 시나리오에서는 개발자 도구 및 환경을 먼저 업그레이드한 다음, 프로덕션을 업그레이드합니다.
- 큰 변경 사항의 경우, 새로운 Ruby로 프로덕션에 이동하는 위험이 상당합니다. 이 경우, 새로운 Ruby 버전과 관련된 알려진 호환성 문제가 이미 수정된 상태로 만든 다음, GitLab 프로덕션 일부에 새로운 Ruby를 배포할 수 있는 위치에 이르기를 노력하세요. 이런 경우에는 프로덕션을 먼저 업데이트하고, 그 다음으로 개발자 도구와 환경을 업그레이드합니다. 이렇게 하면 프로덕션이 중요한 회귀에 대비하여 롤백하기가 쉬워집니다.
어떤 방식으로든 과거 경험으로부터 다음 접근 방식이 잘 작동하는 것으로 확인했습니다. 일부 단계는 마이너 및 메이저 업그레이드에만 필요할 수 있음을 유의하시기 바랍니다. 일부 단계는 병렬로 발생하거나 상기한 것과 반대로 순서가 바뀔 수 있습니다.
에픽(Epic) 생성
이 작업을 에픽에 기록하는 것은 진행 상황을 파악하는 데 유용합니다. 대규모 업그레이드의 경우, 에픽 설명에 타임라인을 포함하여 이를 통보하는 이해 관계자에게 예상되는 마지막 전환 시기를 알려줍니다. Ruby 롤아웃 성능 테스트를 지정하여 업그레이드에 대한 성능 표준을 보장하는 데 도움이 되도록 합니다.
이 에픽 아래에서 개별 리포지터리 변경사항을 별도의 이슈로 분할하세요.
업그레이드 의도 통보
특히 기능을 도입하거나 제거하는 업그레이드의 경우, 업그레이드가 예정되었음을 미리 통보합니다. 가능하면 연관된 타임라인과 함께 이 업그레이드의 의도를 공유하세요. 중요하거나 주목할 만한 변경 사항에 대한 링크를 제공하여 개발자들이 변경 사항에 대해 미리 익숙해질 수 있도록 합니다.
GitLab 팀원들은 업그레이드 에픽의 링크를 포함하여 관련한 Slack 채널(#backend
및 최소한 #development
) 및 공학 주간 검토(EWIR)에서 의도를 공지해야 합니다.
소통에서 업그레이드 에픽의 링크를 포함합니다.
Ruby 추가하기 CI/CD 및 개발 환경
새 Ruby로 Ruby gems 및 GitLab Rails 애플리케이션을 빌드하고 실행하려면 먼저 CI/CD 및 개발 환경을 새 Ruby 버전을 포함하도록 준비해야 합니다. 이 단계에서 아직 기본 Ruby로 설정해서는 안 되지만 옵션으로 만들어야 합니다. 이렇게 하면 일정 기간 동안 이전 및 새 Ruby 버전을 지원하여 원활한 전환을 가능케 합니다.
변경이 필요한 두 군데가 있습니다.
-
GitLab Build Images. 이것들은 러너와 기타 Docker 기반 사전 프로덕션 환경에 사용되는 Docker 이미지입니다. 필요한 변경의 종류는 범위에 따라 다릅니다.
-
패치 레벨 업데이트의 경우
RUBY_VERSION
의 패치 레벨을 증가시키면 될 것입니다. 동일한 마이너 릴리스에 있는 모든 프로젝트는 자동으로 새로운 패치 릴리스를 다운로드합니다. -
주 버전 및 마이너 업데이트의 경우, 기존 이미지와 병행하여 사용할 수 있는 새로운 Docker 이미지 세트를 만들어야 합니다. 중요: Ruby 버전이 업그레이드되면
/patches
디렉터리의 모든 Ruby 패치 파일을 새로운 폴더로 복사하여 적용되도록 해야 합니다.
-
패치 레벨 업데이트의 경우
-
GitLab Development Kit (GDK).
기존 개발자들이 선택할 수 있는 옵션으로 새 Ruby를 추가하기 위해 GDK를 업데이트하세요. 일반적으로
.tool-versions
에 추가하면asdf
사용자는 여기서 이점을 얻을 수 있습니다. 다른 사용자들은 매뉴얼으로 설치해야 할 것입니다 (예시.)
큰 버전 업그레이드의 경우 Quality Engineering와 협력하여 테스트 계획을 식별하고 설정하는 것을 고려해보세요.
서드파티 gem 업데이트하기
패치 릴리스의 경우 이 작업이 필요하지는 않겠지만, 마이너 및 메이저 릴리스의 경우 gem이 특정 버전의 Ruby에 고정되면 서드파티 gem에 대한 중단되거나 Bundler 의존성 문제가 발생할 수 있습니다. 어떤 일이 벌어지는지 알아보는 좋은 방법은 gitlab-org/gitlab
에서 Merge Request을 생성하고 무엇이 실패하는지 확인하는 것입니다.
GitLab gem 및 관련 시스템 업데이트
일반적으로 우리가 유지 관리하는 gem 또는 Ruby 애플리케이션은 .ruby-version
, .tool-versions
, 또는 .gitlab-ci.yml
과 같은 빌드 설정을 포함하고 있기 때문에 이 작업이 필요합니다. GitLab Rails 애플리케이션이 새로운 Ruby와 작동하기 위해 이러한 리포지터리를 항상 기술적으로 업데이트할 필요는 없지만, 모든 리포지터리에서 Ruby 버전을 일치시키는 것이 좋은 실천 방법입니다. 마이너 및 메이저 업그레이드의 경우 이러한 리포지터리에 새로운 Ruby를 사용하여 CI/CD 작업을 추가하세요.
빌드 매트릭스 정의를 사용하여 효율적으로 이를 수행할 수 있습니다.
업데이트할 리포지터리 결정하기
Ruby를 업그레이드할 때 ruby/gems
그룹 내의 리포지터리를 업데이트하는 것도 고려해보세요.
참조용으로, 지난 프로젝트 중 일부에서 Ruby를 업데이트한 Merge Request 디렉터리을 제공합니다:
- GitLab LabKit (예시)
- GitLab Exporter (예시)
- GitLab Experiment (예시)
- Gollum Lib (예시)
- GitLab Sidekiq fetcher (예시)
- Prometheus Ruby Mmap Client (예시)
- GitLab-mail_room (예시)
메인 GitLab 애플리케이션과 함께 업데이트할 필수 리포지터리를 평가할 때 아래 사항을 고려하세요:
- Ruby 버전 범위.
- 서비스 또는 라이브러리의 전체 GitLab 기능에서의 역할.
GitLab 프로젝트 디렉터리을 참조하여 어떤 리포지터리가 영향을 받을 수 있는지 완전히 확인하세요. 보다 작은 버전 업그레이드의 경우 필수적이지 않은 라이브러리의 업데이트를 지연시키는 것이 허용될 수 있으며, 새로운 Ruby 버전에서 재현되는 문제를 메인 애플리케이션 테스트 스위트가 잡을 수 있다고 확신되는 경우에도 해당합니다.
GitLab 애플리케이션 MR(Merge Request) 준비하기
의존성을 업데이트하고 새로운 gem 버전을 릴리스하였다면, 메인 Rails 애플리케이션을 변경할 수 있는 필요한 변경사항들과 함께 업데이트할 수 있게 됩니다. 또한, 설치 및 업데이트 안내서에 버전 변경을 반영하기 위해 문서도 업데이트하세요 (예시).
개발자가 업그레이드하는 데 시간을 제공하세요(유예 기간)
새로운 Ruby를 옵션으로 제공하고 모든 Merge Request이 준비되거나 Merge되었을 때,
개발자들이 자신의 머신에 새로운 Ruby를 설치할 수 있는 유예 기간을 가져야 합니다(최소 1주).
GDK 및 asdf
사용자의 경우, 이 과정은 gdk update
를 통해 자동으로 이루어져야 합니다.
이 유예는 GitLab SaaS의 이 업그레이드에 대한 위험을 평가하는 좋은 기회입니다. 주요 버전 업그레이드와 같은 높은 위험의 Ruby 업그레이드의 경우, change management request를 통해 인프라 팀과 변경 사항을 조정하는 것이 권장됩니다. 모든 사람들이 일정을 조정하고 변경 사항을 준비할 충분한 시간을 제공하기 위해 조기에 이 문제를 생성하세요.
Ruby를 기본값으로 만드세요
알려진 버전 호환성 문제가 없는 경우, 유예 기간이 지난 후 모든 영향을 받는 리포지터리 및 개발자 도구를 업데이트하여 새로운 Ruby를 기본값으로 만들어야 합니다.
이 시점에서 GitLab Compose Kit (GCK)를 업데이트하세요.
이것은 docker-compose
에서 GitLab을 실행하는 사용자를 위한 대안적인 개발 환경입니다.
이 프로젝트는 우리의 러너와 동일한 Docker 이미지에 의존하기 때문에 해당 리포지터리의 변경 사항과 동일하게 유지되어야 합니다. 이 변경 사항은 주 버전 또는 부 버전 변경 시에만 필요합니다(예시.)
위에서 언급한 대로, Ruby 업그레이드가 SaaS 가용성에 미치는 영향이 불확실한 경우, 이 단계를 생략하는 것이 현명합니다. 이 경우에는 우선 다음 단계로 이동한 후, 검증 기간이 지난 후에 새로운 Ruby를 새로운 기본값으로 승격하세요.
CNG, Omnibus, Self-compiled 업데이트 및 GitLab MR Merge
마지막 단계는 새로운 Ruby를 본사에서 사용하는 것입니다. 이는 Omnibus 및 프로덕션 Docker 이미지를 업데이트하여 새 버전을 사용하는 것을 요구합니다.
본사에서 새로운 Ruby를 사용하려면 다음 프로젝트를 업데이트하세요:
- Cloud-native GitLab Docker Images (CNG) (예시)
- Omnibus GitLab (예시)
- Self-compiled installations: Ruby 시스템 버전 확인 업데이트
GitLab Helm Chart과 같은 차트가 일부 상황에서 Ruby를 사용하는 경우, 예를 들어 테스트를 실행하기 위해(이 예시를 참조하세요(https://gitlab.com/gitlab-org/charts/gitlab/-/merge_requests/2162)), 업데이트되어야 할 수도 있지만, 이것은 엄격히 필수적인 것은 아닐 수 있습니다.
변경 관리 요청을 제출하면 인프라 엔지니어들과 롤아웃을 조정하세요. 큰 업그레이드를 다룰 때, 롤아웃 계획에 릴리스 매니저를 참여시키세요.
보안 패치를 위한 패치 릴리스 및 백포트 생성
업그레이드가 패치 릴리스이고 중요한 보안 패치가 포함된 경우, Self-managed 고객에게 GitLab 패치 릴리스로 출시되어야 합니다. 진행 방법은 릴리스 매니저에게 문의하세요.
Ruby 업그레이드 도구
업그레이드 프로세스를 용이하게 하는 몇 가지 도구가 있습니다.
폐기 툴킷
Ruby 업그레이드의 일반적인 문제는 폐기 경고가 오류로 전환되는 것입니다. 이는 그렇기 때문에 새로운 경고가 기본 응용 프로그램 브랜치에 들어가지 않게 하기 위해 DeprecationToolkitEnv
를 사용합니다.
이 모듈은 spec 실행에서 생성된 폐기 경고를 관찰하고 이를 테스트 실패로 변환합니다. 이를 통해 새로운 Ruby에서 실패할 코드를 커밋하지 않도록 합니다.
가끔씩 우리가 사용하는 Ruby gem에서 이러한 경고를 생성하고 우리가 그것을 통제하지 못할 때 새로운 경고를 도입하는 것을 피할 수 없을 때가 있습니다. 이러한 경우에는 이 MR가 수행한 것처럼 조용히하십시오.
폐기 로거
또한 Ruby 및 Rails 폐기 경고를 전용 로그 파일 log/deprecation_json.log
에 기록합니다(GitLab 로깅 가이드에서 GitLab 로그 파일 위치를 참조하세요). 이렇게 하면 테스트에 충분히 포함되지 않은 코드가 있을 때 힌트를 제공할 수 있습니다.
GitLab SaaS의 경우, GitLab 팀원들은 Kibana에서(https://log.gprd.gitlab.net/goto/f7cebf1ff05038d901ba2c45925c7e01
) 이 로그 이벤트를 검토할 수 있습니다.
권장 사항
업그레이드 프로세스 중에 다음과 같은 권장 사항을 고려하세요:
- 가능한 많은 변경 사항을 초기에 집중하세요. 특히 마이너 및 메이저 릴리스의 경우, 애플리케이션 코드가 실패하거나 변경될 가능성이 높습니다. 역호환성이 있는 모든 변경 사항은 본 브랜치로 Merge되어 독립적으로 릴리스되어야 합니다. 이는 우리가 작은 증분으로 이동하고 초기에 프로덕션 환경에서 피드백을 받을 수 있도록 하는 것을 보장합니다.
- 큰 업데이트를 위한 실험 브랜치를 만드세요. 보통 우리는 장기간 실행되는 주제 브랜치를 피하려고 합니다. 그러나 피드백과 실험 목적으로 이러한 브랜치가 유용할 수 있습니다. 이러한 브랜치는 이 MR가 보여주는 것처럼 더 높은 Ruby를 실행할 때 CI/CD에서 정기적인 피드백을 받을 수 있도록 하는 것이 유용할 수 있습니다. 이러한 실험적 브랜치는 Merge되도록 의도된 것이 아닙니다. 필요한 변경 사항이 모두 분리돼 독립적으로 Merge되면 이러한 실험적 브랜치를 닫을 수 있습니다.
- 마일스톤 릴리즈 전에 문제를 해결할 시간을 충분히 가지세요. GitLab은 빠르게 움직입니다. Ruby 업그레이드는 많은 MR을 보내고 리뷰하는 것이 필요하므로, 모든 변경 사항이 릴리스 날짜 전 최소 1주일 전에 Merge되도록 해야 합니다. 이는 무언가가 실패할 경우에 대비해 추가적인 시간을 제공합니다. 의심스러운 경우, 우리는 가속의 우선순위를 넘기는 것이 나아집니다.