본 문서의 2.1(Mutating Admission Policy GA)과 3.9(갈래 B)를 실제 EKS 1.36에서 검증한 기록입니다. 예시 ①의 컨트롤러가 런타임 자동 resize를 담당한다면, MAP는 그 전제조건인 resizePolicy를 생성 시점에 webhook 없이 자동 주입합니다. 아래 매니페스트로 그대로 재현 가능합니다.

0. 핵심 (TL;DR)

resizePolicy 를 MutatingAdmissionPolicy(GA)로 생성 시점에 자동 주입 — webhook 서버 제거.


1. 동작 원리

Pod CREATE 요청
  → MAP matchConstraints: pods/CREATE 대상
  → matchConditions: resize.example.com/enabled == "true" 일 때만
  → mutations(JSONPatch, CEL): 각 컨테이너에 resizePolicy add
  → API Server 내부 처리 (webhook 네트워크 왕복 제거)
  → 주입된 spec 으로 Pod 생성

왜 JSONPatch 인가: resizePolicy 는 스키마상 atomic 리스트라 ApplyConfiguration(구조적 SSA 병합)으로는 바꿀 수 없습니다(may not mutate atomic arrays). 이 경우 JSONPatch patchType 을 씁니다.


2. 전체 매니페스트

MutatingAdmissionPolicy + Binding

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicy
metadata: { name: inject-resizepolicy }
spec:
  failurePolicy: Fail
  reinvocationPolicy: Never
  matchConstraints:
    resourceRules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        operations: ["CREATE"]
        resources: ["pods"]
  matchConditions:
    - name: only-resize-enabled
      expression: >-
        has(object.metadata.annotations) &&
        ("resize.example.com/enabled" in object.metadata.annotations) &&
        object.metadata.annotations["resize.example.com/enabled"] == "true"
  mutations:
    # resizePolicy 는 atomic 리스트 → JSONPatch 로 add (indexOf 로 다중 컨테이너 일반화)
    - patchType: JSONPatch
      jsonPatch:
        expression: >-
          object.spec.containers.map(c, JSONPatch{
            op: "add",
            path: "/spec/containers/" + string(object.spec.containers.indexOf(c)) + "/resizePolicy",
            value: [
              {"resourceName": "cpu",    "restartPolicy": "NotRequired"},
              {"resourceName": "memory", "restartPolicy": "RestartContainer"}
            ]
          })
---
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicyBinding
metadata: { name: inject-resizepolicy-binding }
spec:
  policyName: inject-resizepolicy
  matchResources:
    namespaceSelector:
      matchLabels: { map-demo: "true" }   # ← 이 라벨 네임스페이스에만 적용 (전역 차단)

⚠️ 안전 — 반드시 범위 제한: MAP matchConstraints 는 기본 클러스터 전역입니다. Binding 의 matchResources.namespaceSelector 로 대상 네임스페이스를 한정하지 않으면 클러스터 모든 Pod 생성에 개입합니다. failurePolicy: Fail 은 범위를 좁힌 뒤에만 안전합니다.

테스트 Pod

# 양성: annotation 有, resizePolicy 無 → MAP 가 주입
apiVersion: v1
kind: Pod
metadata:
  name: with-annotation
  namespace: map-demo
  annotations: { resize.example.com/enabled: "true" }
spec:
  containers:
    - name: app
      image: public.ecr.aws/docker/library/busybox:1.36
      command: ["sh","-c","sleep 3600"]
      resources:
        requests: { cpu: 100m, memory: 32Mi }   # req==limit → Guaranteed
        limits:   { cpu: 100m, memory: 32Mi }
# 음성(대조군): annotation 無 → 주입 안 됨 (동일 spec, annotation만 제거)

3. 실측 결과

환경: EKS 1.36.1 노드, MutatingAdmissionPolicy 가 admissionregistration.k8s.io/v1(GA)로 서빙.