TT Lab
블로그

한국어 English 日本語 中文

시작하기
블로그

블로그

Dynamo 오퍼레이터를 깔기 전에 볼 것: 웹훅 범위, 설치 방식 둘, 반입 목록

상태: 초안 (2026-11-14), 실측. Dynamo v1.6.2(차트 dynamo-platform-1.6.2, 오퍼레이터 이미지 kubernetes-operator:1.6.2)를 쿠버네티스 v1.34, Helm v3.18 에 2026-11-13 에 직접 설치하며 적은 글입니다. 리소스 수는 helm template 출력에서 세었고, 오류 문구는 실제 출력 그대로입니다. 전역 방식은 그려 보기만 했고 설치하지 않았습니다. 전역 방식의 파드 웹훅이 다른 네임스페이스의 파드 생성에 주는 지연은 미실측입니다. 작성 규칙: 실측 데이터가 기본이고, 못 잰 것은 「미실측」, 확인하지 못한 것은 「미확인」으로 표시합니다.

목차

1. vLLM 만 쓸 때는 없던 것

vLLM 은 Deployment 와 Service 만 있으면 뜹니다. 클러스터 범위의 리소스를 하나도 만들지 않습니다.

Dynamo 는 다릅니다. 워커와 프런트엔드를 DynamoGraphDeployment 라는 사용자 정의 리소스 한 장으로 적고, 오퍼레이터가 그것을 읽어 Deployment 와 Service 를 만듭니다. 그러려면 CRD, 오퍼레이터, 승인 웹훅, 그리고 그 권한을 클러스터에 먼저 두어야 합니다. 여러 팀이 함께 쓰는 클러스터라면 이 부분이 엔진 성능보다 먼저 검토할 대상입니다.

차트의 기본값부터 적습니다. 1.6.2 에서 etcd, NATS, Grove, KAI 스케줄러, snapshot 은 모두 꺼져 있습니다. 디스커버리는 쿠버네티스 API 로, 요청 평면은 TCP 로, KV 이벤트는 ZMQ 로 하는 것이 기본이기 때문입니다. 저장소의 문서 여러 곳이 아직 NATS 와 etcd 를 필수처럼 적고 있지만, 넷 다 없이 설치해서 3편의 측정을 끝까지 돌렸습니다.

2. 전역 방식: 모든 파드 생성에 웹훅이 걸린다

기본 설치는 오퍼레이터 하나가 클러스터 전체를 보는 전역 방식입니다. 설치하기 전에 helm template 으로 그려서 만들어지는 것을 세었습니다(체크포인트 기능은 끈 값).

종류 전역 방식 네임스페이스 제한 방식
ClusterRole 12 7
ClusterRoleBinding 10 7
Role 1 6
RoleBinding 1 6
ServiceAccount 2 5
웹훅(변형 4 + 검증 4) 8, 선택자 없음 8, 대상 네임스페이스 선택자
PodMonitor 5 5

전역 방식의 웹훅 여덟 개에는 namespaceSelector 도 objectSelector 도 없습니다. 일곱 개는 Dynamo 의 사용자 정의 리소스만 보므로 다른 팀에 영향이 없습니다. 남은 하나가 문제입니다.

mpodcheckpointrestore.kb.io   resources: pods   operations: CREATE
failurePolicy: Ignore         timeoutSeconds: 10

클러스터의 모든 파드 생성이 이 웹훅을 거칩니다. 체크포인트 기능을 꺼도(checkpoint.enabled: false) 등록됩니다. failurePolicy 가 Ignore 라서 오퍼레이터가 죽어 있어도 파드 생성이 막히지는 않습니다. 다만 그때는 API 서버가 웹훅 응답을 기다리는 시간이 파드 생성마다 붙을 수 있습니다. 그 지연이 실제로 얼마인지는 전역 방식을 설치하지 않아 재지 못했습니다(미실측).

시험용으로 들이는 오퍼레이터를 다른 팀의 파드 생성 경로에 끼워 넣고 싶지 않았습니다. 그래서 웹훅을 시험 네임스페이스로 좁히려 했습니다.

3. 웹훅은 값으로 좁힐 수 없다

차트에는 webhook.namespaceSelector 라는 값이 있습니다. 여기에 선택자를 적어 설치하면 Helm 이 거부합니다.

VALIDATION ERROR: webhook.namespaceSelector must be empty. Helm manages admission
scope: cluster-wide webhooks cover every namespace and namespace-restricted
webhooks cover only their target namespace.

웹훅의 범위는 설치 방식이 정하고 사용자가 따로 고르지 못한다는 뜻입니다. 남은 길은 네임스페이스 제한 방식(namespaceRestriction.enabled: true)뿐입니다. 이 방식으로 그리면 웹훅 여덟 개 모두에 다음 선택자가 붙습니다.

namespaceSelector:
  matchLabels:
    kubernetes.io/metadata.name: <대상 네임스페이스>

제한 방식은 CRD 자동 갱신과 함께 쓸 수 없습니다. 둘을 같이 켜면 이것도 거부됩니다.

VALIDATION ERROR: namespaceRestriction.enabled=true is incompatible with
upgradeCRD=true. Set upgradeCRD=false so the namespaced release does not install
or update cluster-wide CRDs.

그리고 오퍼레이터는 제한 방식으로 뜰 때 로그에 큰 띠를 찍습니다. 「DEVELOPMENT AND TESTING ONLY: Namespace-restricted mode is not supported for production.」 차트의 검증 문구도 제한 방식을 「전역 오퍼레이터 옆에 개발·시험용으로 함께 두는 것」으로 설명합니다. 운영에서 지원되는 길은 전역 방식 하나이고, 그 방식을 고르면 2절의 파드 웹훅을 받아들여야 합니다.

4. 제한 방식을 단독으로 쓰면 빠지는 것 셋

전역 오퍼레이터 없이 제한 방식만 설치하니 세 가지가 비어 있었습니다. 전역 오퍼레이터가 해 주던 일이기 때문입니다.

CRD 가 없습니다. upgradeCRD: false 가 필수라서 CRD 를 직접 넣어야 합니다. 저장소의 deploy/operator/config/crd/bases/ 에서 여섯 개를 가져왔습니다. 가장 큰 파일이 3,038,832바이트입니다. 클라이언트 쪽 kubectl apply 는 적용한 내용 전체를 주석(annotation)에 다시 담으므로 이 크기를 넘기지 못합니다. kubectl apply --server-side 로 넣었습니다.

변환 웹훅이 가리키는 서비스 이름이 다릅니다. CRD 원본의 변환 웹훅은 dynamo-system 네임스페이스의 dynamo-operator-webhook-service 를 가리킵니다. 차트가 만드는 서비스의 이름은 <릴리스 전체 이름>-webhook-service 이고, 릴리스 이름을 dynamo-platform 으로 하면 dynamo-platform-dynamo-operator-webhook-service 가 됩니다. CRD 를 넣기 전에 이 이름과 네임스페이스를 실제 값으로 고쳐야 합니다.

변환 웹훅의 CA 가 들어가지 않습니다. 웹훅 인증서는 오퍼레이터가 스스로 만들어 Secret 에 넣지만, 그 CA 를 CRD 의 caBundle 에 넣는 권한은 전역 오퍼레이터에만 있습니다. 설치한 뒤 Secret 에서 ca.crt 를 꺼내 CRD 네 개(dynamocomponentdeployments, dynamographdeploymentrequests, dynamographdeployments, dynamographdeploymentscalingadapters)에 직접 넣었습니다.

셋을 다 메우고 나서야 v1beta1 리소스를 만들 수 있었습니다.

5. 네임스페이스를 나누자 오퍼레이터가 161번 죽었다

오퍼레이터는 dynamo-system 에, 워크로드는 다른 네임스페이스에 두었습니다. 권한을 가진 프로세스와 모델 서버를 떼어 놓는 평범한 배치입니다. 제한 방식에서 이 배치를 쓰면 오퍼레이터가 오래 살지 못했습니다.

failed to list *v1.Secret: secrets is forbidden: User "system:serviceaccount:
dynamo-system:dynamo-platform-dynamo-operator-controller-manager" cannot list
resource "secrets" in API group "" in the namespace "dynamo-system"
...
problem running manager  {"error": "failed to wait for cert-rotator caches to sync
kind source: *v1.Secret: timed out waiting for cache to be synced ..."}

오퍼레이터 안의 인증서 회전기는 자기 네임스페이스의 Secret 을 지켜봅니다. 지켜보려면 목록 조회(list)와 감시(watch) 권한이 필요합니다. 차트가 릴리스 네임스페이스에 만드는 Role 은 이렇게 생겼습니다.

rules:
- apiGroups: [""]
  resources: [secrets]
  resourceNames: [webhook-server-cert]
  verbs: [get, list, watch, update, patch]

resourceNames 로 이름을 묶은 규칙은 이름을 지정하지 않은 목록 조회를 허용하지 못합니다. 쿠버네티스 RBAC 의 알려진 성질입니다. 그래서 캐시 동기화가 끝나지 않고, 제한 시간이 지나면 프로세스가 스스로 끝납니다.

전역 방식에서는 ClusterRole 이, 릴리스 네임스페이스와 대상 네임스페이스가 같은 제한 방식에서는 대상 네임스페이스의 Role 이 Secret 목록 조회를 허용하므로 이 문제가 가려집니다. 두 네임스페이스가 다를 때만 드러납니다.

실제로 본 모습은 이렇습니다.

원인이 권한이므로 고치는 방법은 릴리스 네임스페이스에 Secret 의 get·list·watch 를 허용하는 Role 을 하나 더 두는 것입니다. 또는 오퍼레이터와 워크로드를 같은 네임스페이스에 둡니다. 이 글의 측정은 Role 을 더하지 않고 오퍼레이터가 살아 있는 때를 기다려 적용하는 방식으로 끝냈으므로, 두 방법 모두 적용해서 확인하지는 않았습니다(미실측).

Running 과 CrashLoopBackOff 를 오가는 파드는 잠깐 보면 정상으로 보입니다. 오퍼레이터를 설치한 뒤에는 재시작 횟수를 몇 분 간격으로 두 번 봐야 합니다.

6. 폐쇄망에 들일 것

바깥에서 받아 온 것은 넷입니다.

무엇 이름 크기 꼭 필요한가
런타임 이미지 nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.6.2 10,203,035,478바이트 예. 워커와 프런트엔드가 같이 씀
오퍼레이터 이미지 nvcr.io/nvidia/ai-dynamo/kubernetes-operator:1.6.2 94,673,132바이트 예
차트 dynamo-platform-1.6.2.tgz 516,410바이트 예
모델 Qwen/Qwen3-0.6B, 리비전 고정 1,519,209,243바이트 예. 워커 노드마다
프런트엔드 전용 이미지 dynamo-frontend:1.6.2 약 3.76GiB 아니오. 런타임 이미지로 대신함
NATS, etcd, Grove, KAI 아니오. 기본값이 꺼짐

런타임 이미지 안에는 vLLM 0.31.0, ai-dynamo 1.6.2, PyTorch 2.13.0+cu130, NIXL 1.4.1 이 들어 있습니다. 부하 도구 AIPerf 는 런타임 이미지에 없고 프런트엔드 전용 이미지에만 있습니다.

들이면서 걸린 것이 셋 있습니다.

10GB 이미지는 같은 노드의 다른 배포를 세웁니다. 런타임 이미지를 받는 데 노드당 약 11분이 걸렸습니다. 컨테이너 런타임이 이미지를 한 번에 하나씩 받도록 설정된 노드에서는 그동안 다른 이미지가 줄을 섭니다. 실제로 같은 노드에 떠야 하던 다른 배포 하나가 12분 11초를 기다리다 진행 제한 시간을 넘겨 실패했습니다. 큰 이미지는 배포가 없는 시간에 미리 받아 둡니다.

리비전을 해시로 받으면 오프라인에서 모델을 못 찾습니다. snapshot_download(..., revision="<커밋 해시>") 로 받으면 캐시에 refs/main 이 생기지 않습니다. 그 상태에서 HF_HUB_OFFLINE=1 로 --model Qwen/Qwen3-0.6B 를 주면 저장소 이름을 스냅숏으로 풀지 못합니다. 받은 뒤 refs/main 파일에 그 해시를 적어 두었습니다. 리비전을 고정하지 않는 쪽은 권하지 않습니다. 이름만 적으면 다음 달에 다른 파일을 가리킬 수 있습니다.

모델 디렉터리는 읽기 전용으로 붙여도 됩니다. 워커가 캐시 색인 파일 하나를 쓰려다 Permission denied 경고를 남기지만 로딩은 끝납니다.

7. 정리: 설치 전에 정할 것

물음 전역 방식 네임스페이스 제한 방식
운영에서 지원되는가 예 아니오(개발·시험 전용이라고 로그에 찍힘)
다른 팀의 파드 생성에 닿는가 예. 파드 CREATE 변형 웹훅, Ignore, 10초 아니오
CRD 를 누가 넣는가 오퍼레이터 사람이 직접
변환 웹훅 주소와 CA 오퍼레이터가 맞춤 사람이 직접
오퍼레이터와 워크로드의 네임스페이스 분리 가능 Role 을 하나 더 넣어야 함
클러스터 범위 권한 ClusterRole 12개 ClusterRole 7개 + Role 6개

시험 삼아 넣어 볼 때는 제한 방식이 다른 팀에 닿지 않아 안전하지만 손이 많이 갑니다. 운영에 넣을 때는 전역 방식이고, 그 전에 파드 웹훅의 범위가 클러스터 전체라는 사실을 클러스터 관리자와 합의해야 합니다. 어느 쪽이든 오퍼레이터가 죽어도 이미 떠 있는 서빙은 계속된다는 점은 확인했습니다.

참고

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

댓글

아직 댓글이 없습니다.

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