LabHub

CRD 와 오퍼레이터 · CR 로 애플리케이션 배포하기 · 실습

CR 한 장에서 하위 리소스와 상태 만들기

LabHub 에서 이어서 보기

목표

CR 한 장을 입력으로 삼아 하위 리소스를 만들고, 그 결과를 status 에 되돌려 적어, kubectl get 한 줄이 배포 상태를 말해 주는 구조를 손으로 완성합니다.

왜 중요한가

CR 을 배포 인터페이스로 쓸 때 지켜야 할 규율은 네 가지입니다. 첫째, spec 은 사용자가 쓰고 status 는 컨트롤러가 씁니다. 컨트롤러가 spec 을 건드리면 Git 저장소와 클러스터가 어긋나 다음 동기화가 그것을 지웁니다. 둘째, status 는 반드시 별도 경로로 씁니다. 서브리소스가 켜져 있는데 일반 update 로 쓰면 status 가 조용히 무시되기 때문에, "분명히 썼는데 반영이 안 된다"는 증상으로 나타납니다. 셋째, 자식에는 소유자 참조를 답니다. 부모가 지워질 때 가비지 컬렉터가 자식을 자동으로 정리해 주고, 컨트롤러는 "내가 만든 것"만 관리하면 되므로 정리 로직이 단순해집니다. 이때 연결 고리는 이름이 아니라 uid 입니다 — 같은 이름의 부모를 지웠다 다시 만들면 uid 가 바뀌고 옛 uid 를 가리키는 자식은 즉시 수거됩니다. 넷째, observedGeneration 으로 시차를 드러냅니다. 이 값이 metadata.generation 보다 작으면 "status 는 아직 옛 명세 기준"이라는 뜻이고, 이 한 쌍이 없으면 사용자는 status 를 믿어도 되는지 알 수 없습니다.

단계

시작 전 준비: 실습 파드는 실습마다 새로 뜨므로 앞 실습의 클러스터 상태는 남아 있지 않습니다. kubectl get crd webservices.apps.labhub.io 가 비어 있으면 CRD 를 다시 작성해 적용하고 kubectl create ns crd-lab 도 하세요. 이 실습에는 v1 의 additionalPrinterColumns(Image/Replicas/Tier/Age), subresources.status, subresources.scale(.spec.replicas/.status.replicas/.status.selector), 그리고 properties.status 아래 replicas·selector·observedGeneration·conditions 정의가 모두 필요합니다. status 스키마가 없으면 patch 해도 pruning 으로 잘려 나갑니다.

1. /root/crd/deploy/minimal.yamlmetadata.name: minimal(네임스페이스 crd-lab)이고 spec.image: nginx:1.27 만 있는 WebService 를 쓰고 적용하세요. spec.replicas적지 마세요. 저장된 오브젝트의 spec.replicas 가 1 이어야 합니다.
2. /root/crd/deploy/storefront.yamlmetadata.name: storefront, metadata.labels.tier: prod, spec.image: nginx:1.27, spec.replicas: 4, spec.tier: prod 인 WebService 를 쓰고 적용하세요.
3. crd-lab 에 ConfigMap storefront-config 를 만들고 metadata.ownerReferences[0]apiVersion: apps.labhub.io/v1, kind: WebService, name: storefront, controller: true, 그리고 uidkubectl get webservice storefront -n crd-lab -o jsonpath='{.metadata.uid}' 로 조회한 실제 값을 넣으세요.
4. storefront 의 status 에 replicas: 4selector: app=storefront 를 쓰세요. 반드시 --subresource=status 를 붙인 patch 로 써야 하며, 사용한 명령줄 전체를 /root/crd/deploy/out/status-patch.txt 에 저장하세요.
5. 같은 status 에 conditions 를 추가하세요. type: Ready, status: "True", reason: AllReplicasReady, message 는 자유 문장, lastTransitionTimedate -u +%Y-%m-%dT%H:%M:%SZ 형식의 RFC3339 시각입니다. 함께 status.observedGenerationmetadata.generation 과 같은 값으로 쓰세요.
6. /opt/lab/fixtures/crd/sample-cr.yamlcrd-lab 에 적용해 sample 을 추가하세요(이로써 WebService 가 3개가 됩니다). 그다음 kubectl label webservice minimal -n crd-lab tier=dev 로 라벨을 붙이고, kubectl get webservice -n crd-lab -l tier=prod 의 출력을 /root/crd/deploy/out/selected.txt 로 저장하세요. 이 파일에 storefront 는 있고 minimal 은 없어야 하며, tier=prod 로 걸리는 것은 정확히 하나여야 합니다.
7. kubectl get webservice -n crd-lab -o custom-columns=NAME:.metadata.name,IMAGE:.spec.image,TIER:.spec.tier 의 출력을 /root/crd/deploy/out/columns.txt 로 저장하세요. 머리글 한 줄에 리소스 3줄 이상, 총 4줄 이상이어야 합니다.
8. crd-lab 에 ConfigMap storefront-desired 를 만드세요. data.image, data.replicas, data.tier 세 키의 값은 storefrontspec 에서 읽은 값과 문자열로 정확히 같아야 하고, 3번과 같은 방식으로 storefront 를 소유자로 지정하세요. 이 단계 후에도 status.observedGenerationmetadata.generation 과 같아야 합니다.

참고

단계 8개

  1. 최소 명세로 CR 만들기
  2. 전체 명세를 채운 CR 만들기
  3. 소유자 참조로 자식 묶기
  4. status 서브리소스에 관측값 쓰기
  5. 표준 conditions 와 observedGeneration 채우기
  6. 라벨 셀렉터로 CR 고르기
  7. custom-columns 로 원하는 필드만 뽑기
  8. CR 명세에서 원하는 상태 오브젝트 만들기