보이지 않는 재작성: Kubernetes Image Promoter 현대화
Source: Kubernetes Blog
번역을 진행하려면 실제 블로그 본문 텍스트가 필요합니다. 번역하고자 하는 전체 내용(마크다운 형식 포함)을 제공해 주시면, 요청하신 대로 한국어로 번역해 드리겠습니다.
개요
당신이 registry.k8s.io에서 끌어오는 모든 컨테이너 이미지는 kpromo, 즉 Kubernetes 이미지 프로모터를 통해 전달됩니다. 이 도구는 스테이징 레지스트리에서 프로덕션으로 이미지를 복사하고, cosign으로 서명하며, 20개가 넘는 지역 미러에 서명을 복제하고, SLSA provenance 증명을 생성합니다. 이 도구가 고장 나면 Kubernetes 릴리스가 배포되지 않습니다.
지난 몇 주 동안 우리는:
- 핵심을 처음부터 다시 작성했습니다
- 코드베이스의 20 %를 삭제했습니다
- 성능을 크게 향상시켰습니다
…그리고 아무도 눈치채지 못했습니다. 그게 바로 요점이었습니다.
약간의 역사
| 연도 | 이정표 |
|---|---|
| 2018년 말 | 이미지 프로모터는 Linus Arver가 시작한 구글 내부 프로젝트였습니다. 목표: k8s.gcr.io에 컨테이너 이미지를 복사하는 수동적이고 구글러가 관리하는 과정을 커뮤니티가 소유하고 GitOps 기반 워크플로우(스테이징 레지스트리에 푸시 → YAML 매니페스트로 PR 열기 → 검토 및 병합 → 자동화가 나머지 처리)로 대체하는 것. KEP‑1734가 이 제안을 공식화했습니다. |
| 2019년 초 | 코드가 kubernetes-sigs/k8s-container-image-promoter 로 이동하면서 빠르게 성장했습니다. |
| 그 이후 | Stephen Augustus가 여러 도구(cip, gh2gcs, krel promote-images, promobot-files)를 하나의 CLI인 kpromo 로 통합했습니다. 저장소 이름은 promo-tools 로 바뀌었습니다. |
| 기여 | Adolfo Garcia Veytia (Puerco) 가 cosign 서명과 SBOM 지원을 추가했습니다. Tyler Ferrara 가 취약점 스캔을 구축했습니다. Carlos Panato 가 프로젝트를 건강하고 릴리즈 가능한 상태로 유지했습니다. 42명의 기여자가 ~3,500개의 커밋을 60개가 넘는 릴리즈에 걸쳐 작성했습니다. |
| 2025년 | 코드베이스는 여러 SIG와 하위 프로젝트에서 7년 동안 누적된 추가 사항을 포함하고 있었습니다. README에는 “중복된 코드, 동일한 작업을 수행하는 여러 기술, 그리고 여러 TODO가 보일 것입니다.” 라고 경고하고 있었습니다. |
작동은 했지만, 모놀리식 아키텍처 때문에 새로운 기능(예: 프로베넌스나 취약점 스캔) 등을 확장하고 테스트하기가 어려웠습니다.
우리가 해결해야 했던 문제들
- Production promotion jobs for Kubernetes core images가 정기적으로 > 30 분이 걸렸고, 종종 rate‑limit 오류로 실패했습니다.
- 핵심 promotion 로직이 monolith 형태가 되어 확장이 어렵고 테스트도 힘들었습니다.
- SIG Release 로드맵 항목인 “Rewrite artifact promoter”와 “Make artifact validation more robust”가 정리될 때까지 대기하고 있었습니다.
project board #171에 있는 여덟 개의 오픈 리서치 스파이크가 앞으로 진행하기 전에 답을 찾아야 할 질문들을 포착했습니다.
모든 문제를 해결하는 하나의 이슈
2026 년 2월에 issue #1701(“Rewrite artifact promoter pipeline”)을 열고, 여덟 개의 스파이크를 모두 하나의 트래킹 이슈로 해결했습니다. 리라이트는 각 단계가 독립적으로 검토·병합·검증될 수 있도록 의도적으로 단계별로 진행되었습니다.
단계
| 단계 | 이슈 | 우리가 한 일 |
|---|---|---|
| Phase 1 – Rate Limiting | #1702 | 적응형 백오프를 사용하여 모든 레지스트리 작업을 적절히 제한하도록 Rate Limiting을 다시 작성했습니다. |
| Phase 2 – Interfaces | #1704 | 레지스트리 및 인증 작업을 깔끔한 인터페이스 뒤에 두어 교체 및 독립적으로 테스트할 수 있게 했습니다. |
| Phase 3 – Pipeline Engine | #1705 | 프로모션을 하나의 거대한 함수가 아니라 구분된 단계들의 순서로 실행하는 파이프라인 엔진을 구축했습니다. |
| Phase 4 – Provenance | #1706 | 스테이징 이미지에 대한 SLSA Provenance 검증을 추가했습니다. |
| Phase 5 – Scanner & SBOMs | #1709 | 취약점 스캔 및 SBOM 지원을 추가했습니다. 기본값을 새로운 파이프라인 엔진으로 전환했습니다. v4.2.0을 배포하고, 다음 단계로 진행하기 전에 프로덕션에서 충분히 검증했습니다. |
| Phase 6 – Split Signing from Replication | #1713 | 이미지 서명을 서명 복제와 분리하여 각각 별도의 파이프라인 단계로 만들었으며, 대부분의 프로덕션 장애를 일으키던 Rate Limiting 충돌을 제거했습니다. |
| Phase 7 – Remove Legacy Pipeline | #1712 | 구식 코드 경로를 완전히 삭제했습니다. |
| Phase 8 – Remove Legacy Dependencies | #1716 | 감사 서브시스템, 사용 중단된 도구, 그리고 e2e 테스트 인프라를 삭제했습니다. |
| Phase 9 – Delete the Monolith | #1718 | 구식 모놀리식 코어와 그 지원 패키지를 제거했습니다. 7‑9단계에 걸쳐 수천 줄의 코드가 삭제되었습니다. |
각 단계는 독립적으로 배포되었습니다. 다음 날 v4.3.0이 출시되어 레거시 코드가 완전히 제거되었습니다.
후속 개선 사항
새로운 아키텍처가 구축되면서 일련의 후속 개선이 적용되었습니다:
- 레지스트리 읽기 병렬화 (#1736)
- 모든 네트워크 작업에 대한 재시도 로직 (#1742)
- 파이프라인 정지를 방지하기 위한 요청당 타임아웃 (#1763)
- HTTP 연결 재사용 (#1759)
- 로컬 레지스트리 통합 테스트 (#1746)
- 폐기된 credential‑file 지원 제거 (#1758)
- cosign의 OCI API를 사용하도록 attestation 처리 재구성 및 폐기된 SBOM 지원 제거 (#1764)
- in‑toto attestation 프레임워크에 등록된 전용 promotion‑record 프레디케이트 타입 (#1767)
이러한 개선 사항들은 리팩터링이 제공한 명확한 분리 없이는 적용하기 훨씬 어려웠을 것입니다. v4.4.0은 이 모든 개선을 포함하여 기본적으로 provenance 생성 및 검증을 활성화했습니다.
새로운 파이프라인
프로모션 파이프라인은 이제 명확히 구분된 일곱 단계로 구성됩니다:
graph LR
Setup --> Plan --> Provenance --> Validate --> Promote --> Sign --> Attest
| 단계 | 수행 내용 |
|---|---|
| Setup | 옵션을 검증하고 TUF 캐시를 미리 준비합니다. |
| Plan | 매니페스트를 파싱하고 레지스트리를 읽어, 어떤 이미지가 프로모션이 필요한지 계산합니다. |
| Provenance | 스테이징 이미지에 대한 SLSA 어태스테이션을 검증합니다. |
| Validate | cosign 서명을 확인합니다; 여기서 드라이런일 경우 종료합니다. |
| Promote | 서버 측에서 이미지를 복사하고 다이제스트를 보존합니다. |
| Sign | 키 없는 cosign으로 프로모션된 이미지를 서명합니다. |
| Attest | 전용 in‑toto 프레디케이트 타입을 사용해 프로모션 증명 어태스테이션을 생성합니다. |
단계는 순차적으로 실행되므로 각 단계가 전체 레이트‑리밋 예산에 독점적으로 접근합니다—더 이상 경쟁이 없습니다.
시그니처 복제는 이제 이 파이프라인의 일부가 아니며, 전용 주기적 Prow 작업으로 실행됩니다.
빠르게 만들기
병렬 레지스트리 읽기 (#1736)
Plan 단계는 1,350개의 레지스트리를 읽습니다. 이를 병렬화함으로써 단계가 ~20 분에서 ~2 분으로 단축되었습니다.
두 단계 태그 나열 (#1761)
46,000개의 이미지 그룹을 20개 이상의 미러 전체에서 확인하는 대신, 먼저 소스 레지스트리만 확인하여 필요한 작업량을 크게 줄였습니다.
요약
- kpromo의 핵심을 처음부터 다시 작성하고 코드베이스의 20 %를 삭제했습니다.
- 단일형 프로모션 프로세스를 seven개의 명확히 정의된 단계로 분할했습니다.
- 견고한 속도 제한, 깔끔한 인터페이스, 플러그인 가능한 파이프라인 엔진을 추가했습니다.
- SLSA provenance, 취약점 스캔, SBOM, 키 없는 cosign 서명을 통합했습니다.
- 성능이 크게 향상되었습니다 (Plan 단계가 20 → 2 분으로 단축).
- 시스템을 테스트, 확장, 유지보수가 더 쉬워졌으며, 향후 Kubernetes 릴리스가 안정적으로 배포될 수 있도록 보장했습니다.
Source check before replication (#1727)
주어진 이미지에 대해 모든 미러를 순회하기 전에, 먼저 기본 레지스트리에서 서명이 존재하는지 확인합니다. 정상 상태에서는 대부분의 서명이 이미 복제되어 있기 때문에, 작업 시간을 ≈ 17 시간에서 ≈ 15 분으로 줄였습니다.
요청당 타임아웃 (#1763)
우리는 간헐적인 정지 현상을 관찰했으며, 정체된 연결이 파이프라인을 9 시간 이상 차단했습니다. 이제 모든 네트워크 작업마다 자체 타임아웃이 설정되어 있으며, 일시적인 오류는 자동으로 재시도됩니다.
Connection reuse (#1759)
우리는 HTTP 연결과 인증 상태를 작업 간에 재사용하기 시작했으며, 중복된 토큰 협상을 제거했습니다. 이를 통해 2023년부터 지속되던 요청을 마무리했습니다.
숫자로 보는 성과
- > 40 PRs 병합, 3개의 릴리스 배포 (v4.2.0, v4.3.0, v4.4.0)
- > 10 000 라인 추가 및 > 16 000 라인 삭제 → 순 감소 ≈ 5 000 라인 (코드베이스 약 20 % 축소)
- 전반적으로 성능이 크게 향상됨
- 재시도 로직, 요청당 타임아웃, 적응형 속도 제한을 도입해 견고성이 향상됨
- 19개의 장기 미해결 이슈 해결
- 코드베이스가 1/5 감소하면서 다음을 얻음:
- 출처 증명
- 파이프라인 엔진
- 취약점 스캔 통합
- 병렬 작업
- 재시도 로직
- 로컬 레지스트리를 대상으로 한 통합 테스트
- 독립형 서명 복제 모드
사용자에게 보이는 변경 사항 없음
kpromo cip명령은 여전히 동일한 플래그를 받아들이고 동일한 YAML 매니페스트를 읽습니다.post‑k8sio‑image‑promoProw 작업은 계속해서 정상적으로 작동했습니다.kubernetes/k8s.io의 프로모션 매니페스트는 변경되지 않았으며, 따라서 워크플로우나 설정 업데이트가 필요하지 않았습니다.
우리는 프로덕션 초기에 두 가지 회귀를 발견했습니다:
- #1731 – 레지스트리 키 불일치로 모든 이미지가 “손실된” 것으로 표시되어 프로모션이 차단되었습니다.
- #1733 – 기본 스레드 수가 0으로 설정되어 모든 고루틴이 차단되었습니다.
두 문제 모두 몇 시간 안에 해결되었습니다. 단계적 릴리스 전략(v4.2.0에 새 엔진, v4.3.0에 레거시 코드 제거)을 통해 명확한 롤백 경로를 확보했으며, 다행히도 실제로 롤백할 필요는 없었습니다.
다음 단계
모든 미러 레지스트리에서 서명 복제는 프로모션 사이클에서 가장 비용이 많이 드는 부분입니다.
- Issue #1762는 archeio(
registry.k8s.io리다이렉트 서비스)가 서명‑태그 요청을 지역별 백엔드가 아니라 단일 정규 업스트림으로 라우팅하도록 하여 이를 완전히 없애는 방안을 제안합니다. - 또 다른 옵션은 서명 작업을 레지스트리 인프라 자체에 더 가깝게 이동시키는 것입니다.
두 접근 방식 모두 SIG Release와 infrastructure 팀과의 추가 논의가 필요하지만, 어느 쪽이든 프로모션 사이클당 수천 건의 API 호출을 제거하고 코드베이스를 더욱 간소화할 수 있습니다.
감사드립니다
이 프로젝트는 7년에 걸친 커뮤니티 노력의 결과였습니다. 코드, 리뷰, 그리고 계획에 기여해 주신 Linus, Stephen, Adolfo, Carlos, Ben, Marko, Lauri, Tyler, Arnaud와 그 외 많은 분들께 감사드립니다.
SIG Release와 Release Engineering 커뮤니티는 모든 Kubernetes 릴리스가 의존하는 인프라 재작성에 필요한 맥락, 논의, 그리고 인내를 제공해 주었습니다.
참여하고 싶으시면 Kubernetes Slack의 #release-management 채널에 참여하시거나 저장소를 확인해 주세요.