지난 글에 이어서 파드에 관한 남은 주제를 다뤄보자.
- Pod의 개념과 Single Container Pod 실행 방법
- Multi Container Pod
- livenessProbe를 이용한 Self-healing Pod 생성하기
- Init Container
- Infra Container(pause) 이해하기
- Static Pod 생성하기
- Pod에 리소스(cpu, memory) 할당하기
- Pod의 환경변수 설정하기
init container는 파드의 앱 컨테이너들이 실행되기 전에 미리 동작시키는 특수한 컨테이너이다. 본 컨테이너(main container)가 실행되기 전에 사전 작업이 필요한 경우 사용한다.
init container는 다음과 같은 특징을 제외하고는 일반 컨테이너와 매우 유사하다고 한다.
- 초기화 컨테이너는 항상 완료를 목표로 실행된다.
- 각 초기화 컨테이너는 다음 초기화 컨테이너가 시작되기 전에 성공적으로 완료되어야 한다.
만약 파드의 초기화 컨테이너가 실패하면 kubelet은 초기화 컨테이너가 성공할 때까지 반복적으로 재시작한다.
예를들어 로그인 기능이 존재하는 컨테이너는 로그인을 위해서 DB에 존재하는 회원정보를 불러와야한다. 이때 DB에 접속하여 회원정보를 우선으로 가져오는 컨테이너를 생성할 수 있는데 해당 컨테이너가 바로 init container가 되고 로그인 컨테이너가 main container가 된다.
이 컨테이너들을 하나의 파드로 동작시키면 회원정보를 가져오는 init container가 성공해야지만 main container를 동작시켜주는 구조이다.
init container에 관한 설정을 다음과 같이 설정하고 파드의 상태를 관찰해보자.
// init-container-exam.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app.kubernetes.io/name: 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.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
$ kubectl create -f init-container-exam.yaml
pod/myapp-pod created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:0/2 0 3s
STATUS 값이 Init:0/2로 확인되는 것을 볼 수 있는데 이는 yaml 파일에 설정된 init container에 대한 작업이 완료되면 Running으로 변경될 것이다.
describe의 event 로그를 확인해보자.
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 62s default-scheduler Successfully assigned default/myapp-pod to test-cluster-worker2
Normal Pulling 61s kubelet Pulling image "busybox:1.28"
Normal Pulled 57s kubelet Successfully pulled image "busybox:1.28" in 4.424s (4.424s including waiting). Image size: 766512 bytes.
Normal Created 57s kubelet Created container init-myservice
Normal Started 57s kubelet Started container init-myservice
Normal Pulled 56s kubelet Container image "busybox:1.28" already present on machine
Normal Created 56s kubelet Created container init-mydb
Normal Started 56s kubelet Started container init-mydb
Normal Pulled 55s kubelet Container image "busybox:1.28" already present on machine
Normal Created 55s kubelet Created container myapp-container
Normal Started 55s kubelet Started container myapp-container
순차적으로 init-myservice 컨테이너 실행 -> init-mydb 컨테이너 실행 이후 myapp-container 컨테이너가 실행되어 파드의 상태가 정상적으로 동작되었다.
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 6m21s
파드는 컨테이너로 구성되어 있으며 파드가 생성될 때 기본적으로 infra container(pause)가 함께 생성된다. 해당 컨테이너는 파드에 대한 Infra(IP, hostname)을 생성하고 관리하는 역할을 한다.

주로 파드 내의 네트워크 통신 및 파일 시스템 공유를 관리하는데 사용되고 여러 컨테이너가 함께 실행되는 경우 일부 동직을 지원하기도 한다.
Network Namespace 공유 : 파드 내의 모든 다른 컨테이너들이 동일한 네트워크 네임스페이스를 공유할 수 있도록 하는 역할을 한다. 이를 통해 같은 파드에 속한 컨테이너들이 동일한 네트워크 인터페이스 및 IP 주소를 사용할 수 있다.
IPC (Inter-Process Communication) 공유 : 다른 컨테이너 간의 프로세스 통신을 위해 IPC 네임스페이스를 공유하는 데 사용된다. 이를 통해 같은 파드 내의 다른 컨테이너들이 서로 통신할 수 있다.
Volume 마운트 공유 : 파드 내의 다른 컨테이너들이 공유하는 Volumn을 마운트하는 역할을 한다. 이를 통해 파드 내의 컨테이너들이 동일한 파일 시스템을 사용할 수 있다.
Static Pod는 API 서버 없이 특정 노드에 있는 kubelet 데몬에 의해 직접 관리된다. Control-Plane에 의해 관리되는 파드와는 달리 kubelet이 각각의 static pod를 감시하기 때문에 항상 특정 노드에 있는 하나의 kubelet에 매여있는 것이 특징이다.
static pod의 예제는 쿠버네티스 공식 문서에서 자세히 설명하고 있기 때문에 링크로 대체하도록 하겠다.
유의할 점으로는 kubelet의 설정 파일에서 staticPodPath의 경로를 확인한 다음에 쿠버네티스 yaml 파일을 생성해야한다.
(일반적으로 staticPodPath는 /etc/kubernetes/manifests를 사용함)
쿠버네티스는 파드를 어느 노드에 배포할지 스케줄러가 정하는데 스케줄러는 새로운 파드를 각 노드의 리소스 사용량에 따라 배치 기준을 판단한다.
쿠버네티스는 CPU와 Memory를 관리하고 기본적으로 컨테이너 단위로 리소스를 제한한다. 이때 리소스에 제한을 두지않으면 해당 노드에 할당된 컨테이너가 노드의 모든 리소스를 사용할 수 있는데 이는 새로운 파드가 스케줄링되지 않는 경우가 발생 수 있다.
따라서 해당 파드의 리소스 사용량을 결정하고 Limit를 적절하게 걸어주어야 한다. 예시 파일을 통해 설정하는 방법에 대해 알아보자.
// pod-nginx-resorce.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod-resource
spec:
containers:
- name: nginx-container
image: nginx:1.14
ports:
- containerPort: 80
protocol: TCP
resources:
requests:
cpu: 200m
memory: 250Mi
limits:
cpu: 1
memory: 500Mi
yaml 파일 하단을 보면 resources 항목을 확인할 수 있다. 여기서 파드의 리소스를 요청하고 제한할 수 있는데 각 설정 값이 의미하는 바는 다음과 같다.
설정된 리소스에 대해서는 describe 명령어를 통해 자세한 확인이 가능하다.
$ kubectl describe pod nginx-pod-resource
Name: nginx-pod-resource
Namespace: default
.
.
.
Limits:
cpu: 1
memory: 500Mi
Requests:
cpu: 200m
memory: 250Mi
requests에 설정한 리소스만큼 여유가 있는 노드에 배치해달라고 요청한다. requests의 경우 limits는 자동으로 설정되지 않는다.
파드가 사용할 수 있는 최대 리소스 양을 제한하는 것이기 때문에 requests 값이 Limits와 동일한 값으로 설정된다.
파드 내의 컨테이너가 실행될 때 필요한 변수를 컨테이너 제작 시 yaml 파일로 미리 정의 할 수 있다.
// pod-nginx-env.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod-env
spec:
containers:
- name: nginx-container
image: nginx:1.14
ports:
- containerPort: 80
protocol: TCP
env:
- name: MYVAR
value: "testvaule"
yaml 파일을 통해 환경변수가 설정된 파드를 실행하고 컨테이너 내에 적용이 잘 됐는지 확인할 수 있다.
exec 명령어를 통해 컨테이너 내부로 접속해보자.
$ kubectl exec nginx-pod-env -it -- /bin/bash

이렇게 내부에서 사전에 설정한 환경변수가 적용된 것을 확인할 수 있다!