[k8s] Pod: 사이드카 패턴
관련 포스트
https://blog.naver.com/sssang97/223024811152
쿠버네티스에서 Pod는 하나의 여러종류의 컨테이너를 적재할 수 있다.
단일 pod에 단일 컨테이너를 두는게 일반적인 사용사례이긴 한데, 경우에 따라서 멀티컨테이너를 사용하는게 유리할 때도 있다.
같은 Pod에 들어있는 컨테이너끼리는 같은 리소스를 공유한다.
EmptyDir 타입 볼륨을 통해 스토리지를 공유할 수 있으며, 같은 내부 IP를 공유한다. 그래서 localhost로도 서로 통신이 가능하다.
멀티컨테이너를 사용하는 대표적인 사용사례 중 하나가 사이드카(Sidecar)를 구현하는 것이다.
메인 컨테이너의 보조적인 역할로서, 프록시나 로그 시스템을 버스 컨테이너를 부착하는 것이다.
그에 대한 사용법을 간단히 다뤄보도록 하겠다.
예제: 프록시 사이드카
사이드카 패턴을 적용하는 가장 대표적인 사례가, nginx 등을 이용한 프록시 및 앰버서더를 중간에 두는 것이다.
이를 통해 메인 애플리케이션과 프록시 시스템을 별도로 관리한다.
보통은 프록시에 잡다한 기능을 추가하기 위해 넣는거라서, 프록싱 외에도 로깅이나 인증 기능 등을 붙여서 쓸 일이 많을 것이다.
프록시 중에서도 메인앱의 인풋/아웃풋을 전부 독점해서 프록싱하는 형태를 앰버서더라고 부르기도 한다.
테스트를 위해 서버용 이미지와 프록시용 이미지를 하나씩 말아봤다.
우선 메인서버는 nodejs 기반으로 3000 포트에 서버를 시작하게 구성해놨다. 이미지 이름은 myyrakle/node-server-for-sidecar고, 소스코드는 여기에 있다.
https://github.com/myyrakle/infrastructures/tree/master/Dockerfiles/examples/node-server-for-sidecar
프록시는 nginx를 말아넣었고, 로컬호스트 3000 포트를 그대로 포워딩하도록 했다.
error_log /dev/stdout info;
events {
worker_connections 4096;
}
http {
include mime.types;
access_log /dev/stdout;
server {
listen 80 ;
listen [::]:80 ;
server_name _;
location / {
proxy_pass http://localhost:3000;
}
}
}
동일 pod에서는 localhost로 바로 접근이 가능하다는 점을 이용한 심플한 구현이다.
그리고 저걸 동시에 띄우는 yaml 구성이다.
apiVersion: v1
kind: Pod
metadata:
name: sidecar
labels:
name: sidecar
spec:
containers:
- name: sidecar-proxy
image: myyrakle/sidecar-nginx
imagePullPolicy: Always
ports:
- containerPort: 80
- name: main-server
image: myyrakle/node-server-for-sidecar
imagePullPolicy: Always
별로 복잡할 것은 없다.
저걸 올리고

서비스를 개방하면
kubectl expose pod sidecar --type=LoadBalancer --name=sidecar-lb --port=80


동작을 확인할 수 있을 것이다.

그럼 사이드카 프록시 -> 메인 앱 컨테이너 순으로 호출이 이루어질 것이다.
nginx 로그도 잘 찍히고 잘 도는 것을 확인할 수 있다.
예제: 로깅 사이드카
또 하나의 대표적인 사용례는 볼륨을 이용한 부수적인 log 처리 작업이다.
같은 pod의 컨테이너들끼리는 emptydir volume을 이용해서 스토리지 공유를 쉽게 할 수 있는데,
이를 통해서 앱에서 로그를 뱉으면 사이드카에서 로그를 가공하거나 다른데로 쏘는 식의 구현을 하는 것이다.
아래는 그에 대한 간단한 예제다.
apiVersion: v1
kind: Pod
metadata:
name: log-sidecar
spec:
containers:
- name: main-app
image: busybox:1.28
args:
- /bin/sh
- -c
- >
i=0;
while true;
do
echo "$(date) INFO $i" >> /var/log/1.log;
i=$((i+1));
sleep 1;
done
volumeMounts:
- name: varlog
mountPath: /var/log
- name: sidecar
image: busybox:1.28
args: [/bin/sh, -c, 'tail -n+1 -F /var/log/1.log']
volumeMounts:
- name: varlog
mountPath: /var/log
volumes:
- name: varlog
emptyDir: {}
우선 emptyDir 볼륨을 통해 /var/log 경로를 공유하게 설정했다.
그리고 메인 앱 컨테이너는 쉘코드로 루프돌면서 공유된 경로의 로그파일에 쓰게 하고, 사이드카에서는 그 파일을 읽어서 표준 출력에 쏴주도록 했다.
예제의 단순성을 위해서 여기서는 tail로 표준에 긁어주기만 했지만, 프로덕션 앱에 응용할때는 사이드카에서 중앙화된 로그서버에 쏴주면서 쌓인 로그를 적절히 삭제해주는 기능까지 포함하게 될 것이다.
아무튼 저대로 실행을 해보면
파드가 뜰 것이고
사이드카 컨테이너는
로그를 잘 읽어줄 것이다.
참조
https://seongjin.me/kubernetes-multi-container-pod-design-patterns/
https://kubernetes.io/docs/concepts/workloads/pods/
https://kubernetes.io/docs/concepts/storage/volumes/#emptydir-configuration-example
https://kubernetes.io/ko/docs/concepts/cluster-administration/logging/