LabHub
배우기 러닝패스 코스

CKAD — Kubernetes Application Developer

Multi-Container Pods — init, Sidecar, Ambassador, Adapter

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

한 파드 안에 여러 컨테이너를 놓아야 하는 이유를 패턴별로 구분하고, init 컨테이너·네이티브 사이드카·앰배서더·어댑터를 매니페스트로 직접 작성할 수 있게 된다.

왜 중요한가

파드 안에 컨테이너를 두 개 두는 결정은 공짜가 아니다. 두 컨테이너는 함께 스케줄되고, 함께 재시작되고, 함께 삭제된다. 그래서 "같은 노드에 있어야 하는가"와 "생명주기가 같아야 하는가"를 둘 다 만족할 때만 한 파드에 넣는다. 로그 수집기는 앱이 쓴 파일을 읽어야 하므로 같은 노드여야 하고, 앱이 사라지면 읽을 게 없으므로 생명주기도 같다. 반면 캐시 서버는 여러 앱이 공유하므로 별도 파드다.

init 컨테이너와 사이드카를 가르는 기준은 끝나는가이다. 끝나야 하는 일(마이그레이션, 설정 준비, 선행 서비스 대기)은 init 이고, 끝나면 안 되는 일(로그 전송, 프록시)은 사이드카다. 예전에는 사이드카를 containers 에 넣을 수밖에 없어서 시작 순서가 보장되지 않았고 Job 이 끝나지 않는 문제가 있었다. 지금은 initContainers 에 넣고 restartPolicy: Always 를 주면 "먼저 시작하고, 계속 살아 있고, 메인이 끝나면 같이 끝나는" 컨테이너가 된다.

앰배서더와 어댑터는 방향이 다르다. 앰배서더는 나가는 트래픽을, 어댑터는 나가는 데이터 형식을 대신 처리한다. 둘 다 앱 코드를 건드리지 않고 환경 차이를 흡수하는 것이 목적이다.

단계

  1. 네임스페이스 ckad-multi 를 만든다.
  2. 파드 app-init 을 만든다. init 컨테이너 prep(이미지 busybox:1.36, command: ["/bin/sh","-c","echo ready > /work/state"])과 메인 컨테이너 app(이미지 nginx:1.27)이 emptyDir 볼륨 workdir 를 둘 다 /work 에 마운트한다.
  3. 파드 ordered-init 을 만든다. init 컨테이너를 순서대로 wait-config, migrate 두 개 두고(둘 다 busybox:1.36, command["/bin/sh","-c","true"]), 메인 컨테이너 appnginx:1.27.
  4. 파드 log-shipper 를 만든다. 네이티브 사이드카 loggerinitContainers 에 넣고 restartPolicy: Always 를 준다(이미지 busybox:1.36, command: ["/bin/sh","-c","tail -F /var/log/nginx/access.log"]). 메인 컨테이너 webnginx:1.27. emptyDir 볼륨 varlog 를 두 컨테이너 모두 /var/log/nginx 에 마운트한다.
  5. 파드 ambassador-pod 를 만든다. 메인 컨테이너 app(busybox:1.36, command: ["/bin/sh","-c","sleep 3600"])에 환경변수 REDIS_ADDR=localhost:6379 를 주고, 두 번째 컨테이너 proxy(nginx:1.27)에 containerPort: 6379, name: redis-proxy 를 지정한다.
  6. 파드 adapter-pod 를 만든다. 메인 컨테이너 app(busybox:1.36, command: ["/bin/sh","-c","sleep 3600"])과 어댑터 컨테이너 metrics-adapter(nginx:1.27)가 emptyDir 볼륨 applog둘 다 /var/log/app 에 마운트한다. 어댑터에는 containerPort: 9113, name: metrics 를 지정한다.
  7. 파드 graceful 을 만든다. 네이티브 사이드카 drainer(initContainers 안, restartPolicy: Always, busybox:1.36, command: ["/bin/sh","-c","sleep 3600"])와 메인 컨테이너 web(nginx:1.27)을 두고, 파드의 terminationGracePeriodSeconds45 로 설정한다. 메인 컨테이너 web 에는 preStop 훅으로 exec 명령 ["/bin/sh","-c","sleep 10"] 을 건다.

참고

실습 네임스페이스 만들기

네임스페이스 ckad-multi 를 만든다.

kubectl create namespace 한 줄이면 된다. 이후 모든 리소스는 이 네임스페이스 안에 만든다.

init 컨테이너와 공유 emptyDir

파드 app-init 을 만든다. init 컨테이너 prep(이미지 busybox:1.36, command: ["/bin/sh","-c","echo ready > /work/state"])과 메인 컨테이너 app(이미지 nginx:1.27)이 emptyDir 볼륨 workdir 를 둘 다 /work 에 마운트한다.

spec.initContainersspec.containers 와 같은 높이의 배열이다. 두 컨테이너가 같은 볼륨을 보려면 spec.volumes 에 한 번 선언하고 각 컨테이너의 volumeMounts 에서 같은 볼륨 이름을 참조한다.

init 컨테이너 두 개의 실행 순서

파드 ordered-init 을 만든다. init 컨테이너를 순서대로 wait-config, migrate 두 개 두고(둘 다 busybox:1.36, command["/bin/sh","-c","true"]), 메인 컨테이너 appnginx:1.27.

init 컨테이너는 배열에 적힌 순서대로 하나씩 실행되고, 앞의 것이 성공해야 다음이 시작한다. 순서가 채점 대상이니 배열 인덱스를 확인한다.

네이티브 사이드카 (restartPolicy: Always)

파드 log-shipper 를 만든다. 네이티브 사이드카 loggerinitContainers 에 넣고 restartPolicy: Always 를 준다(이미지 busybox:1.36, command: ["/bin/sh","-c","tail -F /var/log/nginx/access.log"]). 메인 컨테이너 webnginx:1.27. emptyDir 볼륨 varlog 를 두 컨테이너 모두 /var/log/nginx 에 마운트한다.

네이티브 사이드카는 initContainers 목록에 넣되 그 컨테이너에만 restartPolicy: Always 를 준다. 컨테이너 수준 restartPolicy 는 이 용도로만 쓰인다.

앰배서더 패턴 — 바깥으로 나가는 길을 대신 뚫기

파드 ambassador-pod 를 만든다. 메인 컨테이너 app(busybox:1.36, command: ["/bin/sh","-c","sleep 3600"])에 환경변수 REDIS_ADDR=localhost:6379 를 주고, 두 번째 컨테이너 proxy(nginx:1.27)에 containerPort: 6379, name: redis-proxy 를 지정한다.

메인 컨테이너는 항상 localhost 의 고정 포트로만 붙고, 옆 컨테이너가 실제 목적지를 안다. 파드 안 컨테이너들은 네트워크 네임스페이스를 공유하므로 localhost 가 서로에게 닿는다.

어댑터 패턴 — 출력 형식을 바깥에 맞추기

파드 adapter-pod 를 만든다. 메인 컨테이너 app(busybox:1.36, command: ["/bin/sh","-c","sleep 3600"])과 어댑터 컨테이너 metrics-adapter(nginx:1.27)가 emptyDir 볼륨 applog둘 다 /var/log/app 에 마운트한다. 어댑터에는 containerPort: 9113, name: metrics 를 지정한다.

메인이 쓰는 파일을 어댑터가 읽어 다른 형식으로 노출한다. 두 컨테이너가 같은 경로에 같은 볼륨을 마운트해야 하고, 어댑터에는 노출 포트를 이름과 함께 지정한다.

종료 시간 예산과 preStop (종합)

파드 graceful 을 만든다. 네이티브 사이드카 drainer(initContainers 안, restartPolicy: Always, busybox:1.36, command: ["/bin/sh","-c","sleep 3600"])와 메인 컨테이너 web(nginx:1.27)을 두고, 파드의 terminationGracePeriodSeconds45 로 설정한다. 메인 컨테이너 web 에는 preStop 훅으로 exec 명령 ["/bin/sh","-c","sleep 10"] 을 건다.

terminationGracePeriodSeconds 는 파드 수준 필드로, SIGTERM 이후 SIGKILL 까지의 초다. preStop 훅은 컨테이너의 lifecycle 밑에 있고, 이 훅이 도는 시간도 그 예산 안에서 소모된다.