소개
사이드카 컨테이너는 애플리케이션 컨테이너와 동일한 파드 (Pod) 내에서 실행되며, 애플리케이션이 실행되는 동안 이를 보조하는 역할을 합니다. 이는 애플리케이션 시작 전에 반드시 완료되어야 하는 초기화 컨테이너 (init container) 와는 다릅니다. 사이드카는 주로 로그 수집, 프록시, 동기화 또는 파드의 생명주기를 함께 공유해야 하는 기타 보조 작업을 수행하는 데 사용됩니다.
이번 실습에서는 애플리케이션 컨테이너가 공유 emptyDir 볼륨에 로그를 기록하고, 사이드카 컨테이너가 해당 파일을 추적 (follow) 하는 멀티 컨테이너 파드를 생성합니다. 두 컨테이너를 검사하고 사이드카 로그를 읽어본 뒤, 동일한 사이드카 패턴을 디플로이먼트 (Deployment) 템플릿에 적용해 보겠습니다.
사이드카 실습을 위한 네임스페이스 준비
이 단계에서는 사이드카 실습을 위한 깨끗한 네임스페이스를 준비합니다.
/home/labex/project 디렉토리에서 시작합니다. 이 디렉토리에 파드 매니페스트와 디플로이먼트 매니페스트를 작성할 것입니다.
mkdir -p /home/labex/project
cd /home/labex/project
쿠버네티스 API 서버에 접근 가능한지 확인합니다. VM 이 막 시작되어 노드가 아직 준비되지 않았다면, 몇 초 기다린 후 명령어를 다시 실행하세요.
kubectl get nodes --request-timeout=5s
예상 출력:
NAME STATUS ROLES AGE VERSION
labex-v135 Ready control-plane ... v1.35...
워크로드를 생성하기 전에 클러스터 네트워킹 파드가 준비 (Ready) 상태가 될 때까지 기다립니다.
kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s
예상 출력:
pod/calico-node-... condition met
ckad-prep-sidecar라는 이름의 네임스페이스를 생성합니다:
kubectl create namespace ckad-prep-sidecar
이 네임스페이스를 현재 컨텍스트의 네임스페이스로 설정합니다:
kubectl config set-context --current --namespace=ckad-prep-sidecar
현재 네임스페이스를 확인합니다:
kubectl config view --minify --output 'jsonpath={..namespace}'; echo
예상 출력:
ckad-prep-sidecar
멀티 컨테이너 파드 생성
이 단계에서는 애플리케이션 컨테이너와 사이드카 컨테이너를 포함하는 파드를 생성합니다.
두 컨테이너 모두 /var/log/shared 경로에 동일한 emptyDir 볼륨을 마운트합니다. 애플리케이션 컨테이너는 /var/log/shared/app.log 파일에 로그를 기록합니다. 사이드카 컨테이너는 동시에 실행되며 tail -f 명령어를 사용하여 해당 파일을 스트리밍합니다. touch 명령어를 통해 tail -f가 시작되기 전에 파일을 미리 생성하므로, 애플리케이션이 아직 첫 번째 로그를 기록하지 않았더라도 사이드카가 안전하게 대기할 수 있습니다.
sidecar-pod.yaml 파일을 생성합니다:
cat > sidecar-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: sidecar-demo
labels:
app: sidecar-demo
spec:
terminationGracePeriodSeconds: 0
volumes:
- name: shared-logs
emptyDir: {}
containers:
- name: app
image: busybox:1.36
command:
- /bin/sh
- -c
- 'i=1; while true; do echo "app-line-${i}" >> /var/log/shared/app.log; i=$((i+1)); sleep 2; done'
volumeMounts:
- name: shared-logs
mountPath: /var/log/shared
- name: log-sidecar
image: busybox:1.36
command:
- /bin/sh
- -c
- 'touch /var/log/shared/app.log; tail -n +1 -f /var/log/shared/app.log'
volumeMounts:
- name: shared-logs
mountPath: /var/log/shared
EOF
매니페스트를 적용합니다:
kubectl apply -f sidecar-pod.yaml
예상 출력:
pod/sidecar-demo created
파드가 준비될 때까지 기다립니다. 멀티 컨테이너 파드는 모든 일반 컨테이너가 준비 상태가 되어야만 준비된 것으로 간주됩니다.
kubectl wait --for=condition=Ready pod/sidecar-demo --timeout=120s
예상 출력:
pod/sidecar-demo condition met
파드 내의 컨테이너 이름을 나열합니다:
kubectl get pod sidecar-demo -o 'jsonpath={.spec.containers[*].name}{"\n"}'
예상 출력:
app log-sidecar
사이드카 협업 검사
이 단계에서는 두 컨테이너가 모두 실행 중이며, 사이드카가 애플리케이션의 로그 파일을 스트리밍하고 있는지 확인합니다.
먼저 컨테이너의 준비 상태를 확인합니다. 출력 결과는 각 컨테이너의 이름과 준비 여부를 보여줍니다.
kubectl get pod sidecar-demo -o 'jsonpath={range .status.containerStatuses[*]}{.name}{" "}{.ready}{"\n"}{end}'
예상 출력:
app true
log-sidecar true
애플리케이션 컨테이너의 로그를 읽어봅니다. 애플리케이션은 셸 명령이 시작될 때만 표준 출력 (stdout) 을 기록하며, 반복되는 로그 라인은 공유 파일에 기록됩니다.
kubectl logs sidecar-demo -c app --tail=5
애플리케이션 컨테이너는 표준 출력으로 반복적인 라인을 출력하지 않을 수 있습니다. 중요한 증거는 공유 파일과 사이드카 로그에 있습니다.
애플리케이션 컨테이너를 통해 공유 파일을 읽어봅니다:
kubectl exec sidecar-demo -c app -- sh -c 'tail -n 3 /var/log/shared/app.log'
예상 출력에는 애플리케이션 로그 라인이 포함됩니다:
app-line-...
app-line-...
app-line-...
이제 사이드카 로그를 읽어봅니다. 사이드카는 동일한 파일을 추적하고 있으므로, 로그에는 동일한 종류의 라인이 포함되어야 합니다.
kubectl logs sidecar-demo -c log-sidecar --tail=3
예상 출력:
app-line-...
app-line-...
app-line-...
디플로이먼트에 사이드카 패턴 추가
이 단계에서는 사이드카 패턴을 디플로이먼트 템플릿에 적용합니다.
독립형 파드는 학습용으로는 유용하지만, 실제 애플리케이션은 일반적으로 컨트롤러를 통해 실행됩니다. 디플로이먼트는 대체 파드를 생성할 수 있으며, 각 대체 파드에는 템플릿에 정의된 애플리케이션 컨테이너와 사이드카 컨테이너가 모두 포함됩니다.
sidecar-deployment.yaml 파일을 생성합니다:
cat > sidecar-deployment.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: sidecar-worker
spec:
replicas: 1
selector:
matchLabels:
app: sidecar-worker
template:
metadata:
labels:
app: sidecar-worker
spec:
terminationGracePeriodSeconds: 0
volumes:
- name: shared-logs
emptyDir: {}
containers:
- name: app
image: busybox:1.36
command:
- /bin/sh
- -c
- 'i=1; while true; do echo "worker-line-${i}" >> /var/log/shared/worker.log; i=$((i+1)); sleep 2; done'
volumeMounts:
- name: shared-logs
mountPath: /var/log/shared
- name: log-sidecar
image: busybox:1.36
command:
- /bin/sh
- -c
- 'touch /var/log/shared/worker.log; tail -n +1 -f /var/log/shared/worker.log'
volumeMounts:
- name: shared-logs
mountPath: /var/log/shared
EOF
디플로이먼트를 적용합니다:
kubectl apply -f sidecar-deployment.yaml
예상 출력:
deployment.apps/sidecar-worker created
디플로이먼트가 사용 가능 (Available) 상태가 될 때까지 기다립니다:
kubectl wait --for=condition=Available deployment/sidecar-worker --timeout=120s
예상 출력:
deployment.apps/sidecar-worker condition met
디플로이먼트에 의해 생성된 파드를 찾습니다:
worker_pod="$(kubectl get pods -l app=sidecar-worker -o 'jsonpath={.items[0].metadata.name}')"
echo "$worker_pod"
예상 출력에는 생성된 파드 이름이 표시됩니다:
sidecar-worker-...
디플로이먼트로 생성된 파드에서 사이드카 로그를 읽어봅니다:
kubectl logs "$worker_pod" -c log-sidecar --tail=3
예상 출력:
worker-line-...
worker-line-...
worker-line-...
요약
애플리케이션 컨테이너와 사이드카 컨테이너를 포함하는 멀티 컨테이너 파드를 생성하고, emptyDir 볼륨을 사용하여 로그 파일을 공유하며, 두 컨테이너가 함께 실행되는 것을 확인했습니다. 또한 동일한 사이드카 패턴을 디플로이먼트 템플릿으로 옮겨보았습니다. 이제 사이드카가 언제 적합한지 알게 되었습니다. 사이드카는 애플리케이션이 실행되는 동안 애플리케이션을 보조하는 역할을 합니다.


