IT, MIND & CAREER / EDITORIAL DESK

흐름을 읽고, 다음 선택을 설계합니다.

기술의 변화와 사람의 판단, 그리고 오래 가는 커리어를 한 장의 리포트로 정리합니다.

EDITOR'S SELECTION

지금, 먼저 읽을 리포트

변화의 신호를 읽는 네 편의 이야기

THE ARCHIVE

최근 리포트

IT 최신동향 조회 9

Kubernetes 저장 버전 이관 자동화 설계

Kubernetes 저장 버전 이관 자동화 설계
EDITORIAL BRIEF

이 글에서 먼저 가져갈 세 가지

이번 GA의 핵심은 API 버전 선언을 바꾸는 것만으로 끝나지 않고, 이미 저장된 객체를 안전하게 현재 저장 버전으로 수렴시킬 수 있게 됐다는 데 있다.

  1. 01
    v1.37에서 저장 버전 이관은 정식 기능이며 기본 활성화됐다

    8월 31일 공개된 공식 안내에 따라 StorageVersionMigration API와 내장 컨트롤러를 별도 운영 도구 없이 사용할 수 있다. 본문 1절

  2. 02
    완료 확인은 ‘apply 성공’이 아니라 상태와 저장 버전의 정합성이다

    이관 객체의 Succeeded 조건과 CRD의 storedVersions를 함께 확인해야 오래된 저장 버전을 안전하게 제거할 수 있다. 본문 3절

  3. 03
    스키마 변경과 데이터 재기록을 분리하면 무중단 전환이 깨진다

    이관 중 CRD가 바뀌면 재시도가 필요하므로 배포 순서·관측·롤백을 한 런북으로 묶어야 한다. 본문 4절

1. ‘CRD 버전만 바꾸면 끝나지 않는 이유’ 저장 형식과 제공 API의 간극

Kubernetes 프로젝트는 2026년 8월 31일 v1.37에서 StorageVersionMigration(SVM)을 GA로 전환하고 기본 활성화했다고 발표했다. 이 기능은 storagemigration.k8s.io/v1StorageVersionMigration 객체와 제어 플레인 내장 컨트롤러로 구성된다. 즉 프리뷰나 별도 애드온이 아니라, v1.37 클러스터에서 사용할 수 있는 정식 제어 플레인 기능이다.

이 사건이 중요한 이유는 CRD의 served 버전과 실제 저장 버전이 같은 문제가 아니기 때문이다. 예를 들어 v1beta1v1을 모두 제공하다가 v1을 저장 버전으로 바꾸면, 앞으로 기록되는 객체의 형식은 바뀔 수 있다. 그러나 etcd에 이미 있던 객체가 자동으로 모두 재기록되는 것은 아니다. 오래된 저장 버전이 남은 채로 클라이언트·컨트롤러·변환 웹훅을 정리하면, 업그레이드와 롤백의 위험 경계가 흐려진다.

그동안 팀은 임시 스크립트로 객체를 읽고 다시 쓰거나, 컨트롤러를 수정하거나, 마이그레이션 타이밍을 운영 절차에 묻어 두곤 했다. SVM은 이 작업을 Kubernetes API 객체로 선언하고, 컨트롤러가 기존 리소스를 현재 기본 저장 버전으로 이관하며, 상태로 진행 결과를 노출한다. 최신 발표의 본질은 ‘새 API 하나’가 아니라 저장 형식 전환이 다시 시도하고 관측할 수 있는 플랫폼 작업이 된 것이다.

🔍 10초 자가진단: 저장 버전 전환이 필요한 클러스터인가?
  • [ ] CRD에서 더 이상 쓰지 않을 API 버전을 제거하거나 변환 웹훅을 단순화하려는가?
  • [ ] `.status.storedVersions`에 현재 기본 버전 외의 항목이 남아 있는가?
  • [ ] 객체 재기록을 일회성 스크립트나 사람이 실행하는 `kubectl` 절차에 의존하는가?
  • [ ] CRD 배포와 운영자 컨트롤러 배포가 서로 다른 릴리스 파이프라인에 있는가?
👉 두 항목 이상 해당한다면, 저장 버전 이관을 일반 배포가 아닌 별도 검증 작업으로 다뤄야 합니다.

그렇다면 선언 하나가 어떤 방식으로 etcd의 기존 객체까지 옮길까요? 핵심은 API 버전의 노출 순서가 아니라, 이관 대상 리소스를 명시하는 제어 플레인 워크플로입니다.


2. ‘누가 기존 객체를 다시 쓰는가?’ StorageVersionMigrator의 선언형 실행 경로

SVM의 입력은 특정 그룹과 리소스를 가리키는 객체다. 운영자는 CRD에서 원하는 버전을 storage: true로 바꾼 뒤, 이관 객체를 적용한다. 제어 플레인의 StorageVersionMigrator 컨트롤러는 이를 감시하고 해당 API의 기존 객체를 기본 저장 버전으로 자동 이관한다. 애플리케이션이 모든 객체를 순회하는 코드나, 별도 잡이 재기록 권한을 과도하게 갖는 구조와는 다르다.

apiVersion: storagemigration.k8s.io/v1
kind: StorageVersionMigration
metadata:
  name: crontabs-migration
spec:
  resource:
    group: example.com
    resource: crontabs

이 객체가 의미하는 것은 ‘crontabs 리소스의 모든 기존 인스턴스를 현재 저장 버전으로 수렴시켜 달라’는 선언이다. 중요한 점은 이관 대상이 특정 네임스페이스나 일부 객체가 아니라 리소스 종류라는 점이다. 그래서 대규모 CRD를 운영한다면 리소스 수, API 서버 부하, 변환 웹훅의 비용, 백업·복구 창을 먼저 계산해야 한다. SVM이 수동 절차를 없애도 데이터 재기록의 I/O와 제어 플레인 부하는 사라지지 않는다.

[CRD: v1 storage=true]
           |
           v
[StorageVersionMigration 선언]
           |
           v
[StorageVersionMigrator controller]
           |
           +--> 기존 객체 읽기·현재 저장 버전으로 재기록
           |
           v
[status.conditions: Succeeded] --> [storedVersions 검증]

여기서 팀이 얻는 운영 이점은 책임 경계의 명확화다. CRD 스펙은 저장 버전의 목표 상태를 선언하고, 이관 객체는 데이터 이동 의도를 선언하며, 컨트롤러는 실행을 담당하고, 상태는 결과를 제공한다. 각각을 다른 임시 스크립트와 개인의 실행 기록으로 분산하지 않아도 된다.

하지만 실행 성공만 보고 오래된 버전을 제거하면 위험하다. SVM은 이관을 요청하는 API이지, 모든 동시 변경을 마법처럼 직렬화하는 트랜잭션은 아니다. 따라서 다음 단계의 검증이 전환의 실제 완료 조건이 된다.


3. ‘Succeeded가 왜 배포 완료보다 중요한가?’ 상태 조건과 storedVersions의 이중 검증

CRD 스키마 카드가 이관 객체와 제어 플레인 게이트를 거쳐 성공 상태가 붙은 대상 저장소로 이동하고 변경 시 재시도하는 흐름

▲ SVM은 선언을 적용한 시점이 아니라, 컨트롤러의 상태와 CRD 저장 버전 목록이 같은 결론을 가리킬 때 완료된다.

공식 안내에 따르면 컨트롤러는 이관 진행 중 StorageVersionMigration의 상태를 갱신한다. 완료된 이관은 Succeeded=True 조건으로 확인할 수 있다. 그러나 이 상태만 읽고 CRD의 이전 버전을 즉시 제거하면 안 된다. CRD의 .status.storedVersions도 현재 선호 버전만 포함하는지 확인해야 한다. 이 값이 갱신되지 않았다면, 공식 문서는 이관 중 CRD가 변경됐을 가능성을 지적하며 재시도를 권한다.

확인 지점정상 신호경고 신호다음 조치
CRD 선언목표 버전만 `storage: true`여러 버전의 저장 의도가 혼재이관 객체 생성 전 CRD 변경을 분리·검토
SVM 상태`Succeeded=True`Running이 지속되거나 실패 조건 발생API 서버·변환 웹훅·객체 규모를 관측하고 원인 제거
storedVersions현재 선호 버전만 남음이전 버전이 유지됨도중 CRD 변경 여부를 확인하고 이관을 재시도
제거 단계구 클라이언트·웹훅 영향 확인호환성 소비자가 남아 있음served 제거 전에 호출 경로와 롤백 조건을 확인

이 이중 검증은 형식적인 체크리스트가 아니다. Succeeded는 컨트롤러가 이관 작업을 끝냈다는 실행 신호이고, storedVersions는 CRD가 저장된 객체의 버전 상태를 어떻게 보고 있는지의 메타데이터 신호다. 둘이 어긋나면 성공처럼 보이는 이관이 다음 정리 단계에서 문제를 만들 수 있다.

성능 수치에 대해선 과장할 근거가 없다. Kubernetes 공식 발표는 SVM의 처리량이나 대규모 객체 수별 완료 시간을 보편적 수치로 제시하지 않는다. 그래서 운영팀은 ‘자동화됐으니 즉시 끝난다’고 가정하지 말고, 비운영 클러스터에서 실제 CRD 객체 수와 변환 비용으로 소요 시간·API 서버 포화·재시도 동작을 측정해야 한다. GA는 기능의 정식 상태를 뜻하지, 각 워크로드의 무제한 처리량을 보증하지 않는다.

4. ‘GA가 됐으니 바로 구버전을 지워도 될까?’ 전환 순서와 안티패턴

첫 번째 안티패턴은 CRD에서 이전 served 버전을 먼저 제거하는 것이다. 저장 버전을 바꾸는 일과 외부에 제공하는 API 계약을 없애는 일은 다르다. 기존 클라이언트, GitOps 매니페스트, 변환 웹훅, 백업 데이터를 먼저 조사하지 않으면, 데이터는 이관됐어도 사용자 경로가 깨질 수 있다.

두 번째는 스키마 변경·새 컨트롤러 배포·이관·기존 버전 제거를 한 배포 묶음으로 처리하는 것이다. 문제가 생겼을 때 어느 변경이 원인인지 분리할 수 없고, 이관 중 CRD가 갱신되어 재시도가 필요해지는 상황을 스스로 만들 수 있다. 목표 저장 버전 선언과 호환성 검증을 먼저 안정화하고, SVM을 실행해 상태를 확인한 뒤, 마지막으로 제공 버전을 정리하는 단계가 안전하다.

세 번째는 SVM을 백업 대체 수단으로 오해하는 것이다. SVM은 저장 형식을 현재 버전으로 수렴시키는 이관 작업이지, 장애 복구 계획이나 스키마 의미 변화의 보정기가 아니다. 필드 의미를 바꾸는 변환이나 데이터 손실 가능성이 있는 변경에는 백업 검증, 변환 웹훅의 호환성 테스트, 롤백 불가능 지점의 명시가 별도로 필요하다.

시니어 아키텍트의 실전 방어 수칙: SVM은 ‘버전 삭제 버튼’이 아닙니다
이관 객체 적용을 API 버전 폐기의 승인으로 취급하지 마세요. 먼저 저장 버전 수렴을 검증하고, 그다음 클라이언트·웹훅·백업 복구의 호환성 경계를 확인해야 합니다. 이관 중 CRD 변경이 감지되면 상태가 성공처럼 보여도 `storedVersions`를 확인한 뒤 재시도 판단을 하세요.
💡 실무 원칙: 이관 런북의 완료 조건을 ‘객체 적용’이 아닌 `Succeeded=True`와 `storedVersions` 정합성, 그리고 구 API 소비자 제거 확인의 세 신호로 고정하세요.

5. 한 릴리스 안에 저장 버전 전환을 검증하는 3단계

단계핵심 실행 과제산출물 및 검증 지표
Phase 1대상 CRD의 `served`·`storage`·`storedVersions`와 변환 웹훅, 구 API 호출자를 목록화합니다. 스테이징에서 목표 저장 버전만 하나로 선언합니다.호환성 매트릭스, 객체 수 기준의 실행 창, 백업·롤백 확인 기록
Phase 2하나의 저위험 CRD에 SVM을 적용하고 컨트롤러 상태, API 서버 지연, 웹훅 오류, storedVersions 변화를 관측합니다. CRD 변경이 있는 배포와 분리합니다.`Succeeded=True` 상태, 목표 버전만 남은 storedVersions, 부하 측정 결과
Phase 3구 API 소비자와 백업 복구를 재검증한 뒤에만 이전 served 버전과 변환 경로를 정리합니다. 예외 리소스는 재시도 대상으로 남깁니다.제거 승인 기록, 재시도 목록, 다음 CRD에 재사용할 이관 런북

Kubernetes v1.37의 SVM GA는 운영자가 CRD 버전 전환을 덜 위험하게 만들 수 있는 기반을 제공한다. 다만 그 기반은 실행 책임을 제어 플레인으로 옮겨 줄 뿐, 호환성 판단과 부하 검증까지 대신하지는 않는다. 데이터가 현재 저장 버전으로 수렴했다는 상태를 확인하고, 이전 API를 소비하는 경로를 차례로 걷어내는 팀만이 이 기능을 실제 업그레이드 안전성으로 바꿀 수 있다.

운영 지표도 전환 단계에 맞춰 나눠 보는 편이 좋습니다. 이관 전에는 대상 객체 수, 현재 storedVersions, 변환 웹훅의 오류율과 지연을 기준선으로 남깁니다. 이관 중에는 API 서버 요청 지연, 컨트롤러의 진행 상태, 웹훅 타임아웃, 재시도 횟수를 관찰합니다. 이관 후에는 새 버전으로 읽기·쓰기·백업 복구가 모두 가능한지와 구 버전을 요청하는 호출이 남았는지를 확인합니다. 이 신호를 하나의 대시보드에 억지로 합칠 필요는 없지만, 같은 릴리스 체크리스트에 연결해야 담당자가 바뀌어도 완료 판단이 흔들리지 않습니다.

또한 클러스터 업그레이드와 CRD 이관을 같은 유지보수 창에 넣을 때는 원인 분리를 우선해야 합니다. 제어 플레인 버전 업그레이드가 끝난 직후 SVM을 실행하고, 상태가 수렴하는 것을 본 뒤 다음 변경으로 넘어가면 문제 발생 시 되돌아볼 경계가 선명해집니다. 반대로 여러 CRD를 동시에 이관하면 API 서버와 변환 웹훅에 가해지는 부하뿐 아니라, 실패한 한 리소스를 다시 실행할 때의 관측 난이도도 커집니다. 처음에는 대표성이 있으면서 객체 수가 제한적인 CRD 하나로 런북을 검증하고, 그 결과를 다음 이관의 실행 창과 경보 기준에 반영하는 것이 현실적인 순서입니다.

좋은 마이그레이션은 새 버전을 선언하는 순간이 아니라, 모든 기존 객체와 소비자가 새 계약에 수렴했음을 증명하는 순간에 끝난다.

공식 참고 자료

원문 참고 자료

이 글의 사실 확인과 추가 읽기를 위한 원문입니다. Kubernetes Blog — Storage Version Migration Enabled by Default

테크 아키텍처 데스크
IT & Mind Trends 에디토리얼 팀 — 클라우드 분산 아키텍처 및 행동 과학 트렌드를 연구하고 실무 트레이드오프를 검증하여 전달합니다.
이전 글
다음 글