[CKA] Kubernetes init & infra & static container
pod 안에 init container, main container 를 같이 두고 반드시 실행 되어야 하는 컨테이너는 init 컨테이너로 지정하여 init 컨테이너가 정상일때 main container가 실행 되도록 해야할때 사용한다.
init 컨테이너는 아래와 같이 spec.initContainers 에 컨테이너를 지정한다.
apiVersion: v1
kind: Pod
metadata:
name: myapp
labels:
app: myapp
spec:
containers:
- name: main-app
image:
initContainers:
- name: init-app
image:
쿠버네티스 홈페이지에 예시가 있어 해당 예시로 실습을 진행해보도록 하자!
https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
아래와 같은 test.yaml 을 만든다.
# test.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"]
init 컨테이너 보면 until 이라는것은 ~까지 라는 뜻으로 그 뒤에 나오는 조건이 맞을때 까지 do-done 안에 구문을 반복한다는 뜻이다.
오브젝트가 서비스인 파드를 띄우면 해당 서비스는 Core-DNS를 통해 DNS가 부여되고 해당 DNS를 통해 통신한다.
이를 이용하여 오브젝트가 Service인 myservice를 띄우면 관련 DNS가 myservice.[namespace].svc.cluster.local로 셋팅 되므로 nslookup DNS 를 통해 해당 DNS가 생성 되었는지 확인하여 해당 서비스를 띄울때까지 init 컨테이너는 시작 완료 되지 않도록 한다.
이제 해당 파드를 띄워보면 아래와 같이 STATUS 에 Init 컨테이너가 2개 인데 현재 까지 띄워지지 않음을 알 수 있다.
[node1 ~]$kubectl create -f test.yaml
pod/myapp-pod created
[node1 ~]$ kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:0/2 0 6s
이제 myservice 관련 yaml 파일을 생성하고
# myservice.yaml
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
해당 yaml 파일을 통해 서비스를 띄운다.
[node1 ~]$ kubectl create -f myservice.yaml
service/myservice created
이제 상태 정보를 다시 보면 Init 컨테이너 하나가 성공 되었음을 알 수 있다.
[node1 ~]$ kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:1/2 0 2m26s
이제 mydb 까지 띄워 보자
# mydb.yaml
apiVersion: v1
kind: Service
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
[node1 ~]$ kubectl create -f mydb.yaml
service/mydb created
파드 상태를 보면 PodInitializing 으로 변경 된것을 볼 수 있다.
[node1 ~]$ kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 PodInitializing 0 3m48s
조금 더 기다려보면 메인 컨테이너가 Running 상태임을 볼 수 있다.
[node1 ~]$ kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 5m16s
이제 infra container을 알아보자!
우리가 파드를 만들면 기본으로 pause 컨테이너가 생성되며 파드에 대한 IP Hostname을 생성/관리하는 컨테이너이다.
우선 우리가 사용하고 있는 컨테이너 런타임을 알아야 하는데
아래와 같이 노드 정보를 조회하면 container runtime 을 확인할 수 있으며 docker가 아닌 containerd이다.
[node1 ~]$ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
node1 Ready control-plane 50m v1.27.2 192.168.0.18 <none> CentOS Linux 7 (Core) 4.4.0-210-generic containerd://1.6.21
node2 Ready <none> 50m v1.27.2 192.168.0.17 <none> CentOS Linux 7 (Core) 4.4.0-210-generic containerd://1.6.21
node2에 가서 컨테이너 런타임을 통해 떠있는 프로세스를 확인 하기 위해서는 아래와 같이 입력한다.
# docker
$ docker ps
# containerd
[node3 ~]$ ctr -namespace k8s.io -address /var/run/docker/containerd/containerd.sock containers ls
CONTAINER IMAGE RUNTIME
213fca27006914841f104ef6f9daa3cb24442b81e3dc54bfef61f5d0193e5a57 docker.io/cloudnativelabs/kube-router:latest io.containerd.runc.v2
747865a326c5945d458e515c36f46b152bd6dcad6f26ff8f10284fa70a18cc96 registry.k8s.io/pause:3.6 io.containerd.runc.v2
9bffb4d6108bd330e3a788a3a624009d2fee71f4c1cea4dd17bd285b3996a3bb registry.k8s.io/pause:3.6 io.containerd.runc.v2
b815da08a2ee94b670b94704454c2f657672bc8bab897581986548496c6f3fbe docker.io/cloudnativelabs/kube-router:latest io.containerd.runc.v2
e6285095bdbf5be320983fa63c7ed43febfe9b26c124ef3d44b5612983fe9aff registry.k8s.io/kube-proxy:v1.27.5 io.containerd.runc.v2
우선 기본 필요에 의해 설치된 파드가 있어 pause 컨테이너가 2개 떠있는것을 확인 하였다.
이제 nginx 파드를 생성한뒤 pause 컨테이너가 추가로 뜨는지 확인해보자!
마스터 노드에서 nginx 파드를 띄우며
[node1 ~]$ kubectl run my-nginx --image=nginx --port=90
pod/my-nginx created
우리가 생성한 nginx의 경우 node2에 생성 되었으며
[node1 ~]$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
my-nginx 1/1 Running 0 76s 10.5.1.3 node2 <none> <none>
해당 파드가 떠있는 node2에 접속해서 containerd 런타임을 통해 컨테이너를 조회하면 pause 컨테이너가 하나더 추가되어 3개가 떠있음을 알 수 있으며 nginx 컨테이너도 추가 된것을 확인 할 수 있다.
[node2 ~]$ ctr -namespace k8s.io -address /var/run/docker/containerd/containerd.sock containers ls
CONTAINER IMAGE RUNTIME
213fca27006914841f104ef6f9daa3cb24442b81e3dc54bfef61f5d0193e5a57 docker.io/cloudnativelabs/kube-router:latest io.containerd.runc.v2
5a94cabe9b5826cc2e021c919cbd34603e02bc2bccfc52857eab23beb8a0e833 registry.k8s.io/pause:3.6 io.containerd.runc.v2
747865a326c5945d458e515c36f46b152bd6dcad6f26ff8f10284fa70a18cc96 registry.k8s.io/pause:3.6 io.containerd.runc.v2
9bffb4d6108bd330e3a788a3a624009d2fee71f4c1cea4dd17bd285b3996a3bb registry.k8s.io/pause:3.6 io.containerd.runc.v2
b815da08a2ee94b670b94704454c2f657672bc8bab897581986548496c6f3fbe docker.io/cloudnativelabs/kube-router:latest io.containerd.runc.v2
b9207ac11abf5140d8248c163e46878d3b129a57fc3d5ee97e0d14033569a47d docker.io/library/nginx:latest io.containerd.runc.v2
e6285095bdbf5be320983fa63c7ed43febfe9b26c124ef3d44b5612983fe9aff registry.k8s.io/kube-proxy:v1.27.5 io.containerd.runc.v2
런타임이 docker 의 경우 아래와 같이 입력한다.
$ docker ps
이제 해당 파드를 제거하며
[node1 ~]$ kubectl delete pod my-nginx
pod "my-nginx" deleted
파드 제거시 pause 컨테이너도 제거 되며 직접 확인해보면 제거되어 pause 컨테이너가 하나 제거 되었으며 nginx 컨테이너가 제거 되었음을 확인 할 수 있다.
[node3 ~]$ ctr -namespace k8s.io -address /var/run/docker/containerd/containerd.sock containers ls
CONTAINER IMAGE RUNTIME
213fca27006914841f104ef6f9daa3cb24442b81e3dc54bfef61f5d0193e5a57 docker.io/cloudnativelabs/kube-router:latest io.containerd.runc.v2
5a94cabe9b5826cc2e021c919cbd34603e02bc2bccfc52857eab23beb8a0e833 registry.k8s.io/pause:3.6 io.containerd.runc.v2
9bffb4d6108bd330e3a788a3a624009d2fee71f4c1cea4dd17bd285b3996a3bb registry.k8s.io/pause:3.6 io.containerd.runc.v2
b815da08a2ee94b670b94704454c2f657672bc8bab897581986548496c6f3fbe docker.io/cloudnativelabs/kube-router:latest io.containerd.runc.v2
e6285095bdbf5be320983fa63c7ed43febfe9b26c124ef3d44b5612983fe9aff registry.k8s.io/kube-proxy:v1.27.5 io.containerd.runc.v2
이제 static Pod 에 대해서 알아보자!
마스터에 있는 api server 컨테이너에게 요청을 보내지 않고 pod를 생성/삭제 하는 파드이다.
어떻게 api server 없이 파드를 생성/삭제 할까 ?
kubelet 데몬이 바라보는 디렉토리에 yaml 파일을 생성하면 kubelet이 알아서 파드를 생성하고 yaml 파일이 없으면 pod를 제거한다.
이를 통해서 파드를 생성/삭제하는 pod 를 static 파드라고 한다!
kubelet 데몬이 바라보는 디렉토리의 위치는 config.yaml 에 저장 되어 있는데 쭉 보다 보면 staticPodPath 부분에 디렉토리 확인 가능하다!
[node1 ~]$ cat /var/lib/kubelet/config.yaml
staticPodPath: /etc/kubernetes/manifests
이제 node2에 해당 디렉토리로 간뒤
[node2 ~]$cd /etc/kubernetes/manifests/
[node2 manifests]$ ll
total 0
nginx.yaml 을 생성한다.
apiVersion: v1
kind: Pod
metadata:
labels:
run: webserver
name: webserver
spec:
containers:
- image: nginx:1.14
name: webserver
ports:
- containerPort: 80
정상적으로 파일을 생성하였고
[node2 manifests]$ ll
total 4
-rw-r--r-- 1 root root 179 Aug 24 13:20 nginx.yaml
이제 파드 항목을 보면 [container명]-[서버명] 으로 파드가 생성 된것을 볼 수 있다.
[node1 ~]$ kubectl get pods
NAME READY STATUS RESTARTS AGE
webserver-node2 1/1 Running 0 55s
우리는 api server 도움 없이 노드에서 직접 파드를 생성한것이다!
이제 해당 파드를 삭제하고 싶다면 node2에 가서 yaml 파일을 삭제하면
[node2 manifests]$ rm -rf nginx.yaml
[node2 manifests]$
파드가 삭제 되었다.
[node1 ~]$ kubectl get pods
No resources found in default namespace.
[node1 ~]$
슬레이브 노드인 node2의 static 경로에는 yaml파일이 없었으나
마스터 노드인 node1의 static 디렉토리 경로에 가보면 아래와 같이 우리가 알고 있는 필수 컴포넌트에 대한 yaml 파일이 있다.
[node1 ~]$ cd /etc/kubernetes/manifests/
[node1 manifests]$
[node1 manifests]$ ll
total 16
-rw------- 1 root root 2385 Aug 24 13:15 etcd.yaml
-rw------- 1 root root 3361 Aug 24 13:15 kube-apiserver.yaml
-rw------- 1 root root 2875 Aug 24 13:15 kube-controller-manager.yaml
-rw------- 1 root root 1463 Aug 24 13:15 kube-scheduler.yaml
이를 통해 기본 컴포넌트는 static pod 를 통해 생성이 되었구나~ 를 알 수 있다.
끝!