Image Promotion

Image promotion은 검증한 container image를 environment의 desired state에 반영하는 절차입니다.

이 문서는 다음 질문에 답합니다.

  • dev, stg, prd가 각각 어떤 image를 사용해야 하는가?
  • 여러 image를 항상 같이 release해야 하는가?
  • Staging에서 component 하나만 먼저 검증해도 되는가?
  • OutOfSync는 언제 정상이고 언제 문제인가?
  • 문제가 생기면 어떤 image로 rollback해야 하는가?

Source repo의 package와 image 생성은 CI/CD, version 계산은 Versioning, environment 구조는 Environment Layout을 함께 봅니다.

1. 먼저 구분할 개념

Version 상태와 배포 environment는 서로 다른 축입니다.

용어 의미 예시
Git tag Source revision에 붙이는 release ref v1.4.2, v1.5.0-rc.1
Container tag Registry image에 붙이는 사람이 읽을 수 있는 이름 1.4.2, 1.5.0-rc.1
Digest Image content를 식별하는 변경 불가능한 값 sha256:...
Environment Workload를 실행하고 검증하는 독립 배포 대상 dev, stg, prd
Release unit 하나의 승인 절차로 함께 검증하고 승격하는 image 묶음 API, Web, Operator
Release baseline Environment에서 기준으로 삼는 release unit의 tag와 digest 조합 1.4.2 image catalog
Component override Stg baseline 중 일부 image만 임시 후보 image로 교체한 구성 api:sha-<git-sha>@sha256:...

rc는 environment 이름이 아닙니다. RC는 release 전 검증하는 version 상태이고, stg는 RC 또는 stable version을 실행하는 environment입니다.

2. 핵심 원칙

2-1. Build once, promote by digest

Stg에서 검증한 image와 prd에 배포하는 image는 같은 digest여야 합니다. Environment마다 같은 source를 다시 build하지 않습니다.

source revision
  -> image build
  -> registry digest 확정
  -> stg overlay에 exact tag와 digest 기록
  -> stg 검증
  -> 같은 digest를 prd overlay에 기록

Tag는 사람이 version을 읽고 registry를 탐색할 때 유용합니다. 실제 배포 content와 environment 간 동일성은 digest로 보장합니다.

Kubernetes는 repository:tag@sha256:... 형식을 허용하며, 이 경우 image pull에는 digest가 사용됩니다. 따라서 overlay에는 사람이 읽을 exact tag와 실제 실행 identity인 digest를 함께 기록합니다.

이 원칙을 지키려면 environment별 URL, credential과 runtime option을 image 밖의 ConfigMap, Secret과 overlay로 분리해야 합니다. Stg와 prd 설정값이 다르다는 이유로 image를 다시 build하지 않습니다.

2-2. Environment를 release tag로 사용하지 않음

Image reference 사용 기준
app:dev@sha256:... Dev에서 허용합니다. dev는 mutable channel이고 overlay의 digest가 현재 실행 content를 고정합니다.
app:stg 사용하지 않습니다. 어떤 version을 검증 중인지 알 수 없습니다.
app:prd 사용하지 않습니다. Tag 이동만으로 production content가 바뀔 수 있습니다.
app:1.4.2@sha256:... Stg와 prd의 기본 형식입니다.

Stg와 prd 승격은 environment tag를 움직이는 registry 작업이 아니라 overlay의 exact tag와 digest를 변경하는 GitOps pull request입니다.

2-3. Exact tag는 덮어쓰지 않음

다음 tag는 한 번 publish한 뒤 다른 digest로 덮어쓰지 않습니다.

  • 1.4.2
  • 1.5.0-rc.1
  • sha-<git-sha>

Build input이나 source revision이 달라지면 새 RC, patch version 또는 SHA tag를 발행합니다. dev 같은 moving tag만 새 build를 가리킬 수 있습니다.

3. Release 운영 모델

여러 container가 있다고 해서 반드시 한 가지 release 모델을 사용해야 하는 것은 아닙니다. Architecture, data ownership, contract와 검증 책임을 기준으로 선택합니다.

운영 모델 Desired state 적합한 조건 비용
독립 component release Service마다 version과 digest가 다르고 overlay가 검증된 조합의 BOM 역할을 합니다. Service가 독립 배포 가능하고 API, event, schema의 하위 호환성과 service별 rollback 책임이 명확합니다. 지원할 version 조합과 호환성 검증 범위가 늘어납니다.
통합 release train 여러 image를 하나의 product version과 release baseline으로 함께 검증하고 승격합니다. Shared code, data, contract, migration 또는 end-to-end 검증 때문에 component가 함께 움직여야 합니다. 작은 수정도 전체 release catalog와 검증이 필요할 수 있습니다.

Microservice를 독립 release하려면 단순히 container가 분리되어 있는 것만으로는 부족합니다. 다른 service를 다시 배포하지 않고 변경할 수 있는 경계, data ownership과 호환성 계약이 있어야 합니다.

반대로 통합 release train은 모든 application의 정답도 아닙니다. 독립 배포 가능한 service까지 한 version으로 묶으면 불필요한 release 비용이 생깁니다. Application마다 선택한 모델과 이유를 CD repo 운영 문서에 남깁니다.

3-1. 이 guide의 선택

이 guide는 정식 release에 통합 release train을 사용합니다.

  • Root release tag가 package, app image, firmware, contract와 test evidence를 하나의 system baseline으로 묶습니다.
  • API, Web, Operator가 같은 patient-risk contract와 end-to-end scenario를 구성합니다.
  • SaMD release review와 rollback에서 실제 배포 구성을 source revision과 함께 설명해야 합니다.

따라서 정식 stg promotion에서는 release unit의 image를 한 PR에서 exact tag와 digest로 함께 변경합니다. Dev에서는 빠른 feedback을 위해 변경된 image의 dev digest를 선택적으로 갱신할 수 있습니다.

4. Version과 tag 계약

4-1. Git tag와 container tag

Git tag의 v는 version control ref임을 나타내는 prefix입니다. Container exact tag에는 선행 v를 사용하지 않습니다.

Git tag Container exact tag Moving alias
v1.4.2 1.4.2 필요하면 1.4, 1, latest
v1.5.0-rc.1 1.5.0-rc.1 없음

Moving alias는 registry 소비자에게 편의를 제공할 수 있지만 GitOps overlay에서는 사용하지 않습니다. 특히 RC는 latest, major, minor alias를 갱신하지 않습니다.

4-2. Dev trace tag

Main build는 다음 tag를 함께 발행할 수 있습니다.

Tag 역할
dev 최신 main build를 가리키는 mutable channel
dev-<count>-g<sha> 사람이 source revision을 추적하기 쉬운 build tag
sha-<git-sha> 특정 source revision을 가리키는 immutable tag

Stg component override에는 dev를 사용하지 않고 sha-<git-sha>와 digest를 사용합니다.

5. Environment별 lifecycle

5-1. Dev

Dev는 빠른 feedback을 위해 dev moving tag를 허용합니다.

main merge
  -> :dev publish
  -> Image Updater가 새 digest 발견
  -> dev overlay에 digest write-back
  -> Argo CD automated sync

Tag가 mutable이어도 overlay에는 현재 digest가 기록되므로 Git에서 어떤 content를 실행했는지 확인할 수 있습니다.

5-2. Stg

Stg는 release 검증 environment입니다. RC 또는 stable release의 exact tag와 digest를 reviewed pull request로 반영합니다.

release image catalog 확인
  -> stg overlay의 release unit 변경
  -> Kustomize render와 diff 검토
  -> pull request review와 merge
  -> Argo CD manual sync
  -> rollout, integration과 업무 smoke 검증

Tirosh 운영 정책에서는 stg의 Git merge 승인과 실제 배포 시점을 분리하기 위해 manual sync를 사용합니다. 따라서 merge 후 sync 전의 OutOfSync는 승인된 desired state가 아직 배포되지 않은 예상 상태입니다.

Automated sync 자체가 GitOps 원칙에 어긋나는 것은 아닙니다. 빠른 feedback이 목적인 dev에는 잘 맞습니다. 다만 stg처럼 배포 시점, migration과 검증 시작을 사람이 통제해야 하는 environment에서는 manual sync를 선택합니다.

가능한 범위에서 stg의 runtime policy, storage, ingress와 integration dependency를 prd와 가깝게 유지합니다. 비용 때문에 replica나 용량을 줄일 수는 있지만, 검증 결과를 바꾸는 configuration 차이는 명시적으로 기록합니다.

5-3. Prd

이 guide에는 prd overlay가 없지만, production을 추가할 때는 stg에서 complete release로 검증한 동일 digest만 승격합니다.

Stg component override가 적용된 혼합 baseline은 그대로 prd로 승격하지 않습니다.

6. Stg component override

Component override는 검증된 release baseline을 유지하면서 특정 수정만 stg에서 빠르게 검증하기 위한 임시 예외입니다. 새로운 product release나 prd 승격 후보가 아닙니다.

6-1. 사용 조건

다음 질문에 모두 라고 답할 수 있을 때만 사용합니다.

확인할 질문 아니요일 때
Stg에서만 검증하고 prd로 직접 승격하지 않는가? 정식 RC 또는 stable release를 만듭니다.
영향받는 image를 source change와 dependency 기준으로 한정할 수 있는가? Complete RC를 만듭니다.
각 image에 immutable tag와 registry digest가 존재하는가? Source CI 완료 후 다시 확인합니다.
API, event, shared package와 schema가 baseline과 호환되는가? Complete RC에서 전체 검증합니다.
Integration test와 rollback 대상을 설명할 수 있는가? 검증·rollback 계획을 먼저 보완합니다.

6-2. Pull request에 남길 정보

  • 현재 stg release baseline
  • Source commit과 override image의 exact tag, digest
  • 변경 사유와 영향받는 component
  • API, event, schema와 migration compatibility 판단
  • 수행할 test와 업무 smoke
  • 실패 시 복원할 baseline digest
  • 담당자와 만료일
  • 변경을 포함할 다음 RC

Live resource만 kubectl patch하지 않습니다. Override도 Git desired state로 남기고 reviewed pull request와 manual sync로 적용합니다.

6-3. 종료 조건

검증이 실패하면 override set 전체를 직전 baseline의 tag와 digest로 복원합니다.

검증이 성공해도 override image 하나를 prd에 복사하지 않습니다. Source 변경을 다음 complete RC에 포함하고, 새 RC의 release unit 전체가 준비되면 stg를 다시 통합 baseline으로 수렴시킵니다.

7. Source, GitOps와 infra의 책임

책임 주체 주요 책임
Source repo Release unit 목록, image build, exact tag, digest, OCI source revision, SBOM/provenance와 migration 정보
GitOps repo Environment별 desired image, promotion PR, namespace·config·ingress 차이와 rollback history
Infra repo Runtime Secret, registry credential와 cluster-level policy

Source handoff에는 tag 또는 digest가 아니라 다음 항목을 함께 포함합니다.

  • Image repository
  • Exact tag
  • Top-level registry digest
  • Source Git tag와 commit SHA
  • OCI source revision과 platform manifest
  • Runtime config, port와 health endpoint 변경
  • Migration과 data compatibility

Secret 값은 source repo나 GitOps repo에 기록하지 않습니다.

8. OutOfSync와 sync policy

OutOfSync는 Git desired state와 cluster live state가 다르다는 뜻이지, 그 자체로 장애라는 뜻은 아닙니다.

상황 판단
Dev automated sync 직후 잠깐 OutOfSync Reconciliation 중일 수 있으므로 잠시 후 operation과 health를 확인합니다.
Dev가 계속 OutOfSync Sync 실패, render 차이 또는 controller 상태를 확인합니다.
Stg PR merge 후 manual sync 전 의도된 승인 대기 상태입니다.
Stg sync 후 계속 OutOfSync Hook, immutable field, admission mutation 또는 sync 실패를 확인합니다.
Live resource를 직접 수정해 OutOfSync Git에 반영할 변경인지 판단하고, 아니면 desired state로 복원합니다.

Automated sync와 manual sync 중 어느 하나가 GitOps의 필수 조건은 아닙니다. 중요한 것은 Git이 desired state의 source of truth이고, agent가 그 상태를 pull하고 reconcile하며, 변경과 승격 근거가 version history에 남는 것입니다.

9. Promotion과 rollback

9-1. Promotion checklist

Check Reason
Source checks와 release catalog가 완료됨 부분 release나 깨진 image를 배포하지 않기 위함
Exact tag와 digest가 registry에 존재함 Pull 실패와 tag overwrite 위험을 줄이기 위함
OCI source revision이 release commit과 일치함 Artifact provenance를 확인하기 위함
Target overlay와 Application이 render됨 Argo CD sync 실패를 줄이기 위함
다른 environment의 namespace, Secret, host를 참조하지 않음 Environment 격리를 유지하기 위함
Migration과 rollback 호환성을 검토함 Image만 되돌릴 수 없는 상황을 방지하기 위함
Rollout과 업무 경로를 관찰할 수 있음 배포 후 검증하기 위함

9-2. Rollback

Rollback은 이전에 승인하고 실행한 tag와 digest로 Git desired state를 되돌리는 작업입니다.

  1. 이전 release의 image별 tag와 digest를 확인합니다.
  2. 현재 migration과 data가 이전 application version과 호환되는지 확인합니다.
  3. Overlay의 release unit을 이전 digest로 되돌리는 pull request를 만듭니다.
  4. Review와 merge 후 Argo CD를 sync합니다.
  5. Rollout, hook, endpoint와 업무 smoke를 다시 검증합니다.

Schema가 이전 version과 호환되지 않으면 image만 rollback하지 않습니다. Application별 migration 또는 data recovery 절차를 먼저 따릅니다.

10. 현재 guide 구현 상태

현재 sample은 다음 기준을 적용합니다.

| 항목 | 현재 적용 | | --- | --- | --- | | Dev image | dev tag와 digest를 Image Updater가 추적 | | Stg image | Legacy v0.1.5 exact tag와 top-level digest 고정 | | Release tag 계산 | 다음 release부터 Git tag의 v를 제거한 container exact tag 발행 | | Stg sync | Manual sync |

v0.1.5는 tag mapping 정책 변경 전에 발행되어 registry에 0.1.5 tag가 없습니다. 같은 source를 다시 build하거나 registry를 운영자 작업으로 임의 retag하지 않고, 이미 발행된 top-level digest로 content를 고정합니다. 다음 release promotion부터 0.1.6@sha256:... 같은 목표 형식으로 자연스럽게 전환합니다.

11. 참고 자료와 정책 근거

아래 자료는 정책의 보편적인 근거와 유사 운영 사례입니다.

위 자료가 Tirosh의 container tag 형식, release unit 또는 component override 절차를 직접 규정하지는 않습니다. v 제거, 이 guide의 통합 release train, stg manual sync와 component override는 이 원칙들을 바탕으로 선택한 Tirosh 운영 계약입니다.