서론
CKA 를 준비하면서, 쿠버네티스를 공부하고 있는데 확실히 공부하지 않았을 때 설계하던 내용과 알면 알수록 더 잘 활용할 수 있는게 쿠버네티스라는 생각이 들었다.
처음 도커를 접하고 특정 세팅이 끝난 이후에 다음 컨테이너가 실행되게 하고 싶었는데, 아는 내용이 없어서 docker-compose 에서 sleep 을 넣어서 수행했던 기억이 난다.
하지만 역시 이렇게 만든 구조는 에러를 반드시 발생시켰던 것 같았고 그 당시에는 이러한 기능이 없나 했는데 initContainer 같은 기능이 있더라.
지금은 쿠버네티스에서 서비스를 관리하는 업무를 하고 있는데, 멀티컨테이너 기능을 활용해서 서비스 기동 시 안정적으로 App 이 구성될 수 있도록 구성된 걸 보면서 멀티 컨테이너를 활용하는 방법에 대해 정리하면 좋을 것 같다고 생각했다.
멀티 컨테이너 파드 (Multi-Container Pods)
이전에 모노리스 아키텍처 였던 구조에서 마이크로 서비스로 바뀌면서 각 서비스들이 Pod 로 구성되고, Pod 내부엔 보통 단일 컨테이너로 기동하기 마련이다.
하지만 하나의 Pod 에 여러 컨테이너를 띄우는 멀티 컨테이너 방식도 존재한다. 각 서비스들이 별도의 라이프사이클을 갇기 위해서 마이크로 서비스 아키텍처가 나온 것인데, 멀티 컨테이너는 언제 사용하는 것일까?
이에 대한 다양한 디자인 패턴이 존재하더라.
SIDECAR, ADAPTER, AMBASSADOR 등이 존재하는데 CKA 에서는 그리 깊게 다루지 않고 상위 내용에서 다룬다고 한다.
간단히 정리해보면
SIDECAR 디자인은 파드의 파일시스템을 공유하는 형태의 보조 컨테이너라고 한다.
로그를 수집하는 사이드카 컨테이너는 서버가 로그를 내보내면, 별도의 로그 관리 서비스가 접근하는 식이다.
Adapter 디자인은 파드에탑재된 특정 App 의 출력 규격을 일치시키는 용도로 쓰인다고 한다.
로그 포맷이 다를 때 json 형태 등으로 변환하여 수집에 용이하도록 돕는 역할을 한다.
Ambassador 디자인은 파드 외부 서비스에 대한 엑세스를 간소화 한다고 한다.
메인 컨테이너가 수행해야 할 네트워크 통신을 대신해주는 프록시 역할이다.
이러한 디자인은 나중에 더 깊게 공부할 일이 있을 때 자세히 정리해보려고 하고, CKA 범위 정도인
Init Container 에 대해 공부해보려고 한다.
Init Container
앞에 작성했던 멀티 컨테이너 디자인은 모두 함께 살아있음을 가정하는 컨테이너 즉, 라이프사이클이 같이 돈다고 볼 수 있다. 하지만 Init Container 는 초기화 컨테이너로 서비스를 기동하기 전에 특정 작업을 완료하고 싶을 때 사용할 수 있다.
예를 들어 메인 APP 을 사용하기 전 코드나 바이너리를 가져오는 프로세스, 혹은 DB 작업 등 Pod 가 처음 생성될 때 한번만 실행되는 작업을 주로 담당한다.
initContainer 는 Pod 에서 구성되지만 containers 가 아닌 initContainers 로 작성한다.
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox
command: ['sh', '-c', 'git clone <some-repository-that-will-be-used-by-application> ;']
실제 메인을 담당하는 container 가 시작되기전에 initContainers 가 완료되기를 기다리기 때문에
해당 yaml 파일을 가진 Pod 를 실행하면 initContainers 부분이 먼저 실행된다.
위 코드에서 보면 git clone 동작이 먼저 수행되고 해당 작업이 완료되어야 myapp-container 가 실행된다고 보면 된다.
이러한 initContainer 는 여러개를 사용할 수 있다.
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
init-myservice 가 수행되고, init-mydb 가 수행된 이후에 myapp-container 가 수행된다고 보면 된다.
initContainer 는 반드시 수행이 성공해야 다음 initContainer 를 수행하게 되며, 완료되지 못한 작업은 반복적으로 다시 시작한다. 그렇기 때문에 하나라도 수행되지 못하면 메인 App 은 기동될 수 없다.
추가적으로 restartPolicy 를 추가할 수 있는데, (spec > restartPolicy)
만약 Never 로 지정되어 있다면 해당 pod 를 시작하는 동안 init 컨테이너가 실패하면 전체 Pod 를 실패한 것으로 처리한다.
동작
kubelet 은 네트워킹과 스토리지가 준비될 때 까지 init container 실행을 지연, 준비가 완료되면 init container 를 순서대로 실행한다.
각 init container 는 다음 container 가 실행되기 전에 완료 상태로 종료되어야 한다. 실패되면 실패된 시점의 init container 가 재시작된다.
모든 init container 가 완료되지 않으면 메인 App container 는 기동되지 않으며, Pod 가 재시작되면 모든 init container 가 재시작되게 된다.
edit 을 하게 되도 init container 필드를 변경하면 Pod 가 재시작 되지 않는다.
init container 는 실패 시 재시작 되기 때문에 반복 실행되도 문제 없는 멱등적 구조를 가지고 있어야 한다.
activeDeadlineSeconds 를 활성화하면 영원히 실패하는 것을 방지할 수 있지만 init 작업이 완료된 후에도 효과가 있으므로 애플리케이션을 job 으로 배포하는 경우에만 사용하는 것이 좋다고 함, 올바르게 실행 중이더라도 종료될 수 있음
init container 와 sidecar container 와의 차이점
Init 컨테이너는 메인 App 컨테이너가 시작되기 전에 실행 및 작업을 완료한다.
Sidecar 컨테이너와 달리 메인 App 컨테이너와 함께 지속적으로 실행되지 않는다.
init 컨테이너는 livenessProve, readinessProbe, startupProbe 등을 지원하지 않지만
Sidecar 컨테이너는 이러한 모든 프로브를 지원하여 수명주기를 제어한다.
init container 의 사용
sed, awk, python dig 등의 패키지 처럼 App image 에없는 설정을 위한 유틸리티나 사용자 정의 코드를 포함할 수 있음
App 컨테이너에 보안적인 문제를 발생할 수 있는 유틸리티나 사용자 지정 코드를 안전하게 실행할 수 있게 됨
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:0/2 0 6m
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 9m
init 컨테이너를 실행하면, 위와 같이 Init:0/2 같은 상태를 볼 수 있다. 현재 InitContainer 를 수행 중이며 몇 개의 컨테이너가 진행 중이다 라는 뜻을 가지고 있다.
init container 가 실행이 완료되고 메인 App container 가 기동되면 Running 상태로 변경된다.
kubectl logs myapp-pod -c init-myservice # Inspect the first init container
kubectl logs myapp-pod -c init-mydb # Inspect the second init container
이런식으로 init container 의 이름을 지정해서 로그를 확인할 수 있다고 한다.
참고
https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
'DevOps > ✏️ Cloud' 카테고리의 다른 글
Network Namespace (1) | 2025.05.15 |
---|---|
drain, cordon, uncordon 명령 (0) | 2025.03.27 |
K8S Controller (ReplicaSet, Deployment) (0) | 2024.12.11 |
grafana 에 prometheus 연결하기 (0) | 2024.12.08 |
k3s 에 grafana, prometheus 설치하기 (0) | 2024.12.08 |