LabHub

한국어

시작하기
블로그

블로그

쿠버네티스 CRD 와 오퍼레이터로 LLM 서빙 배포 자동화하기

상태: 초안 (2026-10-07 갱신). 공식 문서로 확인한 서술이 바탕이고, **8절의 격리된 환경 시험과 끝의 「kopf 오퍼레이터 직접 시험」, 「LWS 직접 시험」**만 직접 확인한 값입니다. 나머지는 아직 실측하지 않았습니다. 글 끝의 「확인한 버전과 날짜」와 「확인하지 못한 것」을 먼저 읽으십시오. 작성 규칙: 실측 데이터가 기본이고, 못 잰 것은 「미실측」으로 표시합니다.

쿠버네티스 CRD 와 오퍼레이터로 LLM 서빙 배포 자동화하기

LLM 서빙 배포에는 Deployment 가 표현하지 못하는 요구가 모여 있습니다. 여러 노드에 걸친 리더와 워커, 가중치 로딩이라는 선행 단계, 비율을 지켜야 하는 롤아웃, GPU 토폴로지, 파드 하나가 아니라 묶음을 단위로 하는 스케일입니다. 쿠버네티스는 이를 CRD(Custom Resource Definition)와 오퍼레이터로 확장합니다. 이 글은 그 API의 현재 모양과 오퍼레이터의 핵심 패턴을 정리하고 격리된 실습 환경에서 확인한 동작을 근거로 붙입니다. 프로덕션 규모의 Go 오퍼레이터를 운영한 경험은 제게 없다는 점을 먼저 밝힙니다.

이 글을 읽고 나면 면접에서 설명할 수 있는 것

  1. Deployment 로 LLM 서빙을 표현하기 어려운 이유와, LeaderWorkerSet(LWS), KServe, Dynamo 가 각각 어떤 추상화를 더하는지.
  2. 조정(reconcile) 루프의 멱등성, 레벨 기반 트리거, 소유 참조와 finalizer, 상태 조건, 백오프, 리더 선출이 왜 그렇게 설계되었는지.
  3. CRD 버전 전환 절차, 롤아웃 전략, Argo CD 와 오퍼레이터가 같은 필드를 두고 싸우는 문제의 해결 방법.

1. 왜 Deployment 하나로는 부족한가

2. LWS, KServe, Dynamo 의 API 모양

프로젝트(확인한 버전) CRD(API 그룹/버전) 눈여겨볼 필드
LWS v0.11.1 LeaderWorkerSet (leaderworkerset.x-k8s.io/v1) replicas(그룹 수), leaderWorkerTemplate.size, restartPolicy, rolloutStrategy.rollingUpdateConfiguration(maxUnavailable 기본 1, maxSurge 기본 0, partition), groupIdentity(변경 불가), scale 서브리소스
LWS v0.11.1 DisaggregatedSet (disaggregatedset.x-k8s.io/v1) roles[]마다 LWS 하나, 롤아웃을 역할 전체에서 조정
KServe v0.21.0 InferenceService(v1beta1), ServingRuntime(v1alpha1) predictor 등, 런타임이 지원 모델 형식을 선언
KServe v0.21.0 LLMInferenceService(v1alpha1, 저장은 v1alpha2) model, template, worker(다중 노드면 LWS), prefill, router, rolloutStrategy, kvCacheOffloading(v1alpha2에만)
Dynamo v1.5.0 DynamoGraphDeployment(nvidia.com, 저장은 v1beta1) components[](v1alpha1에서는 services 맵), restart, topologyConstraint
Dynamo v1.5.0 DynamoComponentDeployment, DynamoGraphDeploymentRequest, DynamoGraphDeploymentScalingAdapter, DynamoModel 컴포넌트 배포, SLA 기반 요청(프로파일링 후 DGD 생성), HPA용 scale, 모델 등록

KServe 문서는 InferenceService 를 전통적 예측 모델용으로 두고, 프리필/디코드 분리와 다중 노드, 접두사 인식 라우팅은 LLMInferenceService 가 맡는다고 밝힙니다(0.20 페이지를 열었습니다). Dynamo의 CRD 이름과 필드는 v1.5.0 태그의 CRD YAML에서 직접 읽었습니다.

 DynamoGraphDeployment (dgd)  ← 사용자가 선언: 컴포넌트 목록, 복제 수, 재시작 id
        │ 오퍼레이터가 만듦
        ▼
 DynamoComponentDeployment (dcd)  ← 컴포넌트마다, 이름에 worker hash 접미사
        │ 배포 모드에 따라
        ├─▶ Deployment (단일 노드)
        └─▶ Grove PodCliqueSet 또는 LWS (다중 노드, 갱 스케줄링)

3. 오퍼레이터의 핵심 패턴

 API Server ─watch▶ Informer(로컬 캐시) ─▶ WorkQueue(키 중복 제거, 백오프) ─▶ Reconcile(키)
      ▲                                                                        │
      └────── 변경(자식 생성, status 기록) ◀── 관측 → 비교 → 행동 → 보고 ◀────┘

레벨 기반 조정. controller-runtime 소스(v0.25.2)의 주석은 조정이 이벤트가 아니라 apiserver나 캐시에서 읽은 실제 상태로 구동된다고 적습니다. Request 에는 이름과 네임스페이스만 있고 무엇이 바뀌었는지는 없어서, 파드 삭제 이벤트를 받아도 조정 함수는 「파드가 없다」를 읽어서 알아냅니다. kubebuilder 책의 Good practices 장도 이벤트별로 로직을 쓰면 리소스가 막혀 사람 손이 필요해진다고 경고합니다. kopf는 핸들러가 생성, 변경, 삭제라는 원인별로 호출되는 모델이어서 감시하지 않는 자식의 변화는 타이머로 보완해야 합니다(9절). 다만 가동 중단 중의 변경은 시작할 때 모든 객체를 나열해 마지막 상태만 처리하는 레벨 기반으로 다룹니다.

멱등성. 「생성하라」가 아니라 「원하는 모습으로 존재하게 하라」로 작성합니다. 이미 맞으면 아무것도 쓰지 않아야 하위 오브젝트의 resourceVersion 이 그대로이고 불필요한 감시 이벤트가 생기지 않습니다. 리더 선출이 있어도 순간적으로 리더가 둘일 수 있어 필수입니다.

소유 참조와 finalizer. 쿠버네티스 문서에 따르면 자식의 ownerReferences 는 같은 네임스페이스의 소유자 이름과 UID를 가리키며, 네임스페이스를 넘는 참조는 설계상 금지되고 가비지 컬렉터가 OwnerRefInvalidNamespace 경고 이벤트를 남깁니다. finalizer 가 있으면 삭제 요청은 deletionTimestamp 만 찍고, 컨트롤러가 정리를 끝내고 finalizer 를 빼야 실제 삭제됩니다. kubebuilder 책은 삭제가 갱신으로 바뀌므로 finalizer 추가와 정리 로직을 모두 멱등하게 쓰라고 합니다.

상태와 조건. status.conditions 와 observedGeneration 으로 상태를 표준 형식으로 노출합니다. Dynamo의 DGD도 conditions, observedGeneration, state, rollingUpdate 를 status 에 둡니다. Argo CD 문서는 CRD의 status 형식이 제각각이라 사용자 정의 건강 검사가 필요하고, observedGeneration 을 쓰면 조정이 끝나기 전의 오판을 막는다고 안내합니다.

재시도와 백오프. 조정 함수가 오류를 반환하면 워크큐가 지수 백오프로 다시 넣고, RequeueAfter 는 지정한 시간 뒤에 다시 넣으며, Requeue 필드는 deprecated 입니다. TerminalError 는 재큐하지 않습니다. 「아직 준비 안 됨」은 오류가 아니라 지연 재큐로 표현하는 것이 맞습니다.

리더 선출. controller-runtime 매니저는 LeaderElection, LeaderElectionID, LeaderElectionNamespace 옵션으로 Lease 를 잡습니다(Dynamo의 main.go 에서 확인했고, LMCache 오퍼레이터 설치 YAML에도 leader-election Role 이 있습니다). 쿠버네티스 문서는 Lease가 노드 하트비트와 컨트롤 플레인 리더 선출에 쓰인다고 설명합니다.

웹훅 검증. 단순 규칙은 CRD 스키마의 CEL(x-kubernetes-validations)로 충분하고, 복잡한 규칙과 주입은 웹훅입니다. Dynamo는 검증 웹훅에서 field.ErrorList 로 독립 오류를 모두 모아 반환하는 규칙을 문서화했고, LMCache 오퍼레이터는 변경 웹훅으로 vLLM 파드에 연결 설정을 주입하며 웹훅 인증서를 cert-manager 로 발급합니다.

4. Go(controller-runtime/kubebuilder) 대 Python(kopf)

항목 Go: controller-runtime v0.25.2, kubebuilder v4.16.0 Python: kopf 1.44.6 (2026-06-03)
모델 타입 있는 클라이언트, 인포머 캐시, 워크큐, 매니저 데코레이터 핸들러, 상태를 객체의 어노테이션이나 status에 저장
코드 생성 controller-gen 으로 CRD 생성(Dynamo는 v0.17.3) CRD YAML을 직접 작성
중복 방지 Lease 리더 선출 KopfPeering과 우선순위
생태계 Dynamo 오퍼레이터는 Kubebuilder 로 만들었다고 README가 밝히고, 변환은 conversion.Convertible 인터페이스로 구현. LWS, KServe, LMCache CRD도 controller-gen 으로 생성됨 상태를 객체에 두고 kopf.adopt 같은 도구 제공, kopf 스스로 Kubernetes 클라이언트 라이브러리가 아니라고 밝힘

제 판단입니다. 변환 웹훅과 대규모 감시가 필요한 업스트림급 CRD는 Go 생태계가 기본값이고, 한두 팀이 쓰는 내부 자동화는 팀이 가장 잘 쓰는 언어가 득입니다. 저는 Go 오퍼레이터를 운영한 경험이 없어, 위 비교는 문서와 코드를 읽은 결과입니다.

5. CRD 스키마 설계 원칙

6. 롤아웃 전략

7. GitOps(Argo CD)와의 충돌

충돌은 Git에 적힌 필드를 오퍼레이터나 HPA가 바꿀 때 생깁니다. replicas 를 Git에 적으면 HPA와 싸웁니다(HPA가 늘리면 Argo가 되돌리고 다시 HPA가 늘림). 해결 수단은 다음과 같습니다.

흔히 겪는 함정은 건강 검사입니다. 앱의 건강이 하위 리소스의 상태로 정해지고 동기화가 그 건강을 기다리는 구조에서는, 내장 검사가 어떤 리소스(예: 한 번 실패한 CronJob)를 Degraded 로 판정하면 동기화가 건강을 기다리다 실패해 새 변경이 반영되지 못할 수 있습니다. 검사 규칙은 Lua 로 재정의해 풀 수 있습니다(이 동작이 어느 버전에서 나타나는지는 확인하지 않았습니다). ApplicationSet 에서도 자식 애플리케이션의 자동화를 꺼도 부모 템플릿이 다시 켜는, 두 조정기의 충돌이 생기며 해법은 필드 하나만 이름과 경로로 좁혀 예외를 두는 것입니다.

8. 격리된 환경에서 확인한 동작

아래는 격리된 실습 환경(kwok 클러스터나 개인 VM)에서 실제 쿠버네티스 컨트롤러로 확인한 내용이며, 제 프로덕션 장애 기록이 아닙니다.

한계. 위는 실습이 확인한 쿠버네티스 자체의 동작이며, 특정 오퍼레이터 구현이나 Go 프로덕션 오퍼레이터의 장애 대응이 아닙니다.

9. 직접 해 보기

로컬 kind 클러스터 하나에서만 진행합니다. 모든 명령이 kind-op-lab 컨텍스트를 명시하므로 다른 클러스터에는 닿지 않습니다. 끝나면 마지막 줄로 클러스터째 지웁니다.

kind create cluster --name op-lab
kubectl --context kind-op-lab create ns op-lab
cat <<'EOF' | kubectl --context kind-op-lab apply -f -
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata: {name: modelcaches.labs.example.dev}
spec:
  group: labs.example.dev
  scope: Namespaced
  names: {kind: ModelCache, plural: modelcaches, singular: modelcache, shortNames: [mc]}
  versions:
  - name: v1
    served: true
    storage: true
    subresources: {status: {}}
    additionalPrinterColumns:
    - {name: Phase, type: string, jsonPath: .status.phase}
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            required: [model]
            properties:
              model: {type: string}
              replicas: {type: integer, default: 1, minimum: 0, maximum: 8}
            x-kubernetes-validations:
            - {rule: "self.model.size() > 0", message: "model must not be empty"}
          status:
            type: object
            x-kubernetes-preserve-unknown-fields: true
EOF

최소 조정 루프(op.py)는 CR 하나에 ConfigMap 하나를 소유 참조로 묶어 둡니다. kopf는 pip install kopf kubernetes 로 설치합니다.

import kopf, kubernetes as k8s

@kopf.on.resume("labs.example.dev", "v1", "modelcaches")
@kopf.on.create("labs.example.dev", "v1", "modelcaches")
@kopf.on.update("labs.example.dev", "v1", "modelcaches")
@kopf.timer("labs.example.dev", "v1", "modelcaches", interval=30, idle=10)
def reconcile(spec, name, namespace, patch, **_):
    cm = {"apiVersion": "v1", "kind": "ConfigMap",
          "metadata": {"name": f"{name}-cfg"},
          "data": {"model": spec["model"], "replicas": str(spec.get("replicas", 1))}}
    kopf.adopt(cm)                      # ownerReferences: 이 CR의 이름과 uid
    api = k8s.client.CoreV1Api()
    try:
        api.create_namespaced_config_map(namespace, cm)
    except k8s.client.ApiException as e:
        if e.status != 409:
            raise
        api.patch_namespaced_config_map(f"{name}-cfg", namespace, cm)   # 멱등
    patch.status["phase"] = "Ready"

@kopf.on.delete("labs.example.dev", "v1", "modelcaches")
def cleanup(name, logger, **_):
    logger.info("%s: 외부 자원 정리 자리", name)     # 삭제 핸들러가 있으면 kopf 가 finalizer 를 붙인다
kubectl config current-context            # kind-op-lab 인지 확인(kind 가 만들면서 바꿉니다)
kopf run --standalone --namespace op-lab op.py &
kubectl --context kind-op-lab -n op-lab apply -f - <<'EOF'
apiVersion: labs.example.dev/v1
kind: ModelCache
metadata: {name: demo}
spec: {model: tiny-llm}
EOF
kubectl --context kind-op-lab -n op-lab get mc,cm -o wide
kubectl --context kind-op-lab -n op-lab get cm demo-cfg -o jsonpath='{.metadata.ownerReferences}'
# 에지 대 레벨 관찰: 자식을 지워도 CR 이벤트가 없으므로 타이머(30초 주기)가 되살립니다
kubectl --context kind-op-lab -n op-lab delete cm demo-cfg && sleep 40 && kubectl --context kind-op-lab -n op-lab get cm
# CEL 검증: spec.model 을 빈 문자열로 넣은 CR 을 적용하면 "model must not be empty" 로 거절됩니다
# 정리
kill %1; kind delete cluster --name op-lab

이어서 해 볼 것: ownerReferences 의 uid를 일부러 틀리게 쓴 ConfigMap이 지워지는지 보고, CR 삭제 중 deletionTimestamp 와 finalizer 목록을 확인합니다. 이 스켈레톤은 자식 변경을 감시하지 않으므로 타이머로 보완한 학습용입니다.

10. 면접에서 나올 만한 질문

  1. LLM 서빙에 Deployment 대신 LWS 를 쓰는 이유는? 복제본이 리더와 워커 묶음이어서 스케일, 롤링 업데이트, 장애 복구, 토폴로지 배치를 그룹 단위로 해야 하기 때문입니다. 한 파드가 실패하면 집합 통신이 깨지므로 그룹 전체를 재생성하는 정책이 기본입니다.
  2. 조정 루프가 이벤트를 놓쳐도 괜찮은 이유는? 요청에 이벤트 내용이 없고 매번 현재 상태를 읽어 차이를 메우기 때문입니다. 컨트롤러가 죽었다 살아나도 처음부터 다시 돌려 끝나지 않은 부분만 마저 하므로 모든 쓰기가 멱등해야 합니다.
  3. ownerReference 와 finalizer 의 차이는? 전자는 자식이 부모를 가리켜 가비지 컬렉터가 정리를 맡기는 장치이며 uid가 틀리면 자식이 지워집니다. 후자는 외부 자원 정리를 위해 삭제를 늦추는 장치이며 컨트롤러 없이 떼면 정리를 건너뜁니다.
  4. CRD를 v1alpha1 에서 v1beta1 으로 올리는 절차는? 새 버전을 served 로 추가하고 필요하면 변환 웹훅을 붙이며, storage 를 옮기고 기존 객체를 모두 다시 쓴 뒤 storedVersions 를 정리하고 옛 버전을 끕니다. 전략 None 은 필드 모양이 같을 때만 안전합니다.
  5. Argo CD 가 오퍼레이터가 바꾼 필드를 되돌리면? Git에서 그 필드를 빼고, 어렵다면 ignoreDifferences 로 비교에서, RespectIgnoreDifferences 로 동기화에서 제외합니다. 건강은 CR 용 Lua 검사로 observedGeneration 을 반영합니다.

11. 흔한 오해

외부 근거

주장 자료 확인한 내용
조정은 이벤트가 아니라 현재 상태로 구동된다 controller-runtime pkg/reconcile/reconcile.go 의 Request·Reconciler 주석 Request 는 이름과 네임스페이스만 담고 이벤트 내용이 없음. 조정은 레벨 기반이며 apiserver 나 캐시에서 읽은 실제 상태로 구동된다고 적고, 파드가 지워졌다는 사실도 삭제 이벤트가 아니라 상태를 읽다가 알게 된다는 예를 듦. Requeue 필드는 deprecated, RequeueAfter 를 쓰라고 적음
이벤트별 로직은 안티패턴 kubebuilder 책, Good practices 이벤트별로 조정 로직을 쓰면 연산자 패턴에 어긋나고 리소스가 막혀 수작업이 필요해질 수 있다고 경고, 재조정이 몇 번 돌아도 같은 결과를 내도록 쓰라고 함
컨트롤러는 꺼져 있던 시간을 모른다 쿠버네티스 커뮤니티 문서(sig-api-machinery, controllers.md) 전이가 아닌 현재 상태를 관찰해야 하고, 인포머가 주기적으로 재동기화하며, 작업 큐에는 키만 넣어 중복을 제거하고 오류는 지수 백오프로 재큐
kopf 의 감시 범위와 타이머 kopf 문서(handlers, timers, continuity, errors) 핸들러는 diff 로 감지한 본질적 변화에만 반응하고 감시하지 않는 자식의 변화에 대한 서술은 없음. 타이머는 객체가 존재하는 동안 주기로 실행되고, 꺼진 동안의 변경은 재시작 때 나열해 마지막 상태만 처리하며, 일반 오류의 재시도 간격 기본값은 60초
「level-triggered」 용어의 출처 위 controller-runtime 주석과 커뮤니티 문서 kubernetes.io 의 컨트롤러 개념 페이지는 제어 루프와 「현재 상태를 원하는 상태에 가깝게」는 서술하지만 이 용어 자체는 쓰지 않음. 이 글은 용어를 controller-runtime 과 kubebuilder 책에 귀속함

참고 자료 (실제로 열어 본 것)

kopf 오퍼레이터 직접 시험

9절의 최소 조정 루프(op.py, 고친 것 없이 그대로)를 일회용 단일 노드 k3s(v1.36.5, 4 vCPU 가상 머신)에서 kopf 1.44.6 으로 실행해 3절의 패턴을 확인했습니다. 호출 횟수를 세려고 로그 한 줄만 더한 판(op2.py)을 중복 실행과 오류 시험에 썼습니다.

확인한 것 결과
CR 생성 후 자식 ConfigMap 이 생기기까지, status.phase=Ready 까지 각각 0.1초
자식의 소유 참조 CR 의 이름과 UID, controller: true, blockOwnerDeletion: true
스키마 기본값 replicas 를 안 쓰면 1 이 채워져 ConfigMap 에 "replicas":"1"
CEL 검증 빈 model 은 model must not be empty, model 누락은 Required value, replicas: 99 는 8 이하 규칙으로 거절됨(API 서버 단계)
finalizer kopf.zalando.org/KopfFinalizerMarker 가 붙음
자식 ConfigMap 을 지웠을 때 복구 시간(5회, 시작 위상을 흩뜨림) 2.5, 15.9, 24.9, 17.8, 26.9초
자식 내용을 바꿨을 때 원래 값으로 복구 29.9초
CR 스펙 변경이 ConfigMap 에 반영되기까지 0.1초
조정이 세 번 돌 동안(95초) 자식과 CR 의 resourceVersion 둘 다 불변(멱등)
오퍼레이터가 꺼진 동안 스펙 변경과 자식 삭제, 재기동 후 0.6초 만에 ConfigMap 복원(replicas=5 반영)
오퍼레이터 없이 CR 삭제 CR 이 deletionTimestamp 만 달린 채 남고 자식 ConfigMap 도 그대로. 오퍼레이터를 켜자 0.6초 뒤 CR 이 사라지고 자식은 가비지 컬렉션으로 0.1초 뒤 사라짐

오류 처리와 재시도 간격. 조정 함수가 항상 실패하도록 한 CR 을 100초 동안 두고 호출 시각을 기록했습니다(kopf 기본값).

던진 예외 100초 동안 호출 간격
일반 예외(RuntimeError) 4회 생성 핸들러가 실패하고 60초 뒤 재시도, 타이머도 따로 실패해 60초 뒤 재시도(호출 시각 +0, +10, +60, +70초)
kopf.TemporaryError(delay=5) 20회 5초마다
kopf.PermanentError 4회 생성 핸들러는 재시도하지 않음(0 succeeded; 1 failed). 그러나 타이머는 계속 돌아 30초마다 같은 오류를 냄(+10, +40, +70초)

LWS 직접 시험

일회용 단일 노드 k3s(v1.36.5, 4 vCPU, 4GiB 가상 머신)에 LWS v0.11.1 을 설치하고, busybox sleep 파드로 그룹의 구조와 복구, 롤링 업데이트, 스케일을 확인했습니다. GPU 와 모델은 쓰지 않았으므로 모델 적재 시간은 들어 있지 않고, 시간은 0.5초 간격으로 쟀습니다.

확인한 것 결과
설치 매니페스트 적용부터 컨트롤러 준비까지 17초. CRD 는 LeaderWorkerSet 외에 DisaggregatedSet, DisaggregatedSetRoleScaler 도 함께 설치됨
그룹 만들기 replicas: 2, size: 3 이면 파드 6개가 4.8초 만에 모두 Running. 이름은 리더 demo-0, 워커 demo-0-1, demo-0-2, 두 번째 그룹 demo-1, demo-1-1, demo-1-2
만들어진 하위 리소스 리더 StatefulSet 하나(demo, 그룹 수만큼), 그룹마다 워커 StatefulSet 하나(demo-0, demo-1), 모든 그룹이 공유하는 헤드리스 서비스 하나(demo). 파드의 소유자는 리더가 StatefulSet/demo, 워커가 StatefulSet/demo-0
파드 라벨 leaderworkerset.sigs.k8s.io/ 아래 name, group-index, worker-index, group-key(그룹마다 고유한 해시), template-revision-hash
주입된 환경 변수 LWS_LEADER_ADDRESS(예: demo-1.demo.default, 워커도 자기 그룹 리더의 주소), LWS_GROUP_SIZE=3, LWS_WORKER_INDEX(리더 0, 워커 1부터)
기본값 rolloutStrategy: RollingUpdate, maxSurge: 0, maxUnavailable: 1, partition: 0(6절 서술과 일치). startupPolicy: LeaderCreated, networkConfig.subdomainPolicy: Shared, restartPolicy: RecreateGroupOnPodRestart

한계: 가상 머신 한 대, 파드가 하는 일은 sleep, 이미지는 이미 받아 둔 busybox이고 준비 상태 검사가 없습니다. 노드 장애로 인한 그룹 복구와 DisaggregatedSet 은 시험하지 않았습니다(미실측).

확인한 버전과 날짜 (2026-10-05)

LWS v0.11.1(2026-10-01), KServe v0.21.0(2026-09-25, 문서는 0.20 페이지), Dynamo v1.5.0(2026-09-21), controller-runtime v0.25.2(2026-10-01), kubebuilder v4.16.0(2026-09-10), kopf 1.44.6(2026-06-03), Argo CD v3.5.3(2026-09-14), LMCache v0.5.5, Kubernetes v1.37.1(2026-09-23).

확인하지 못한 것. StorageVersionMigration 의 기본 활성 여부(쿠버네티스 문서 안에서 서술이 엇갈림), kopf의 대규모 클러스터 성능 한계, 컨트롤러 단위 시험 도구(envtest) 세부, ValidatingAdmissionPolicy 와 웹훅의 득실, KServe 최신 문서와 0.21.0 사이의 차이, Dynamo의 DGD 배포 모드별 정확한 하위 리소스 생성 경로(CRD 설명과 문서로 도식을 그렸으며 코드 경로는 추적하지 않음). 9절의 kopf 스켈레톤은 제가 문서를 보고 쓴 것으로 실제 클러스터에서 실행해 검증하지 않았습니다.

로그인하면 좋아요를 누를 수 있습니다

댓글

아직 댓글이 없습니다.

로그인하면 댓글을 쓸 수 있습니다