k8s - Pod!
개요
Pod : 고래의 떼(pod of whales)
파드는 쿠버네티스 애플리케이션의 기본 실행 단위,
쿠버네티스 객체 모델 중 만들고 배포할 수 있는 가장 작고 간단한 단위.
아래와 같은 특성을 가진다.
- 파드에는 하나 이상의 컨테이너가 들어있다.
- 파드안의 컨테이너는 반드시 동일한 노드에 배치된다.
- 어플리케이션 스케일 아웃은 파드단위로 이루어진다.
- 파드안의 컨테이너는 네트워크와 스토리지를 공유한다.
- 각 파드에는 고유한 IP 주소가 할당되며 파드 내부의 컨테이너는 해당 IP 를 공유한다.
- 파드는 컨테이너뿐 아니라 스토리지도 가지고 있으며 공유 볼륨을 통행 컨테이너끼리 스토리지를 통해 데이터를 주고받을 수 있다.

생명주기는 아래와 같다.
Pending- 파드 생성중(이미지 다운, 컨테이너 생성중)Running- 파드안 모든 컨테이너가 실행중, 시자, 재시작 중Succeeded- 파드안 모든 컨테이너가 정상 종료 완료Failed- 파드안 컨테이너중 비정상 종료Unknown- 파드의 상태 확인 불가, 노드 통신 불가시 발생
생명주기는 kubelet 컴포넌트가 주기적으로 진단한다.
매니페스트
아래 명령으로 파드 매니페스트 속성 종류 및 설명 검생 가능
kubectl explain pods
kubectl explain pods.metadata
kubectl explain pods --recursive
pods.spec
| 필드 | 타입 | 설명 |
|---|---|---|
pods.spec.containers |
Container[] |
파드에 속하는 컨테이너 목록 |
pods.spec.imagePullSecrets |
LocalObjectReference[] |
컨테이너 이미지 취득을 위한 인증정보 |
pods.spec.initContainers |
Container[] |
초기화 처리를 하는 컨테이너 |
pods.spec.nodeName |
String |
해당 라벨의 노드에 파드를 배치(스케줄링) |
pods.spec.nodeSelector |
Object |
해당 라벨의 노드에 파드를 배치(스케줄링) |
pods.spec.priority |
Integer |
파드의 우선순위 지정, 클수록 높음 |
pods.spec.restartPolicy |
String |
재시작 정책(Always, OnFailure, Never), 기본값은 Always |
pods.spec.volumes |
Volume[] |
파드의 마운트할 볼륨 지정 |
pods.spec.containers
파드 매니페스트 속성의 containers 에 들어가는 객체 배열 Container 에 어떤 속성이 있는지 알아보자.
| 필드 | 타입 | 설명 |
|---|---|---|
pods.spec.containers.args |
String[] |
컨테이너에 송신할 인수 |
pods.spec.containers.env |
EnvVar[] |
컨테이너에 설정한 환경변수 |
pods.spec.containers.image |
String |
컨테이너 이미지와 해당 경로 |
pods.spec.containers.imagePullPolicy |
String |
컨테이너 이미지 취득시 규칙(Always, ifNotPresent, Never). 기본값은 pods.spec.containers.ifNotPresent 기존 이미지가 있으면 새로 취득하지 않는다. Always 설정시 항상 이미지 갱신 |
pods.spec.containers.name |
String |
컨테이너 이름, 컨테이너 내부간에 통신할때 사용(DNS_LABEL) |
pods.spec.containers.ports |
ContainerPort 배열 |
컨테이너 공개파드 |
pods.spec.containers.resources |
ResourceRequirements |
컨테이너에 CPU, Memory 같은 리소스 할당 |
pods.spec.containers.volumeMounts |
VolumeMount 배열 |
컨테이너 마운트 볼륨 지정 |
pods.spec.containers.workingDir |
String |
작업 디렉토리 |
pods.spec.containers.livenessProbe |
Probe |
컨테이너 감시 |
pods.spec.containers.readlinessProbe |
Probe |
컨테이너 감시 |
pods.spec.initContainers
초기화 컨테이너
앱 컨테이너가 실행되기 전 파드를 초기화,
apiVersion: v1
kind: Pod
metadata:
name: kubernetes-simple-pod
labels:
app: kubernetes-simple-pod
spec:
initContainers:
- name: init-myservice
image: arisu1000/simple-container-app:latest
command: ['sh', '-c', 'sleep 2; echo helloworld01;']
- name: init-mydb
image: arisu1000/simple-container-app:latest
command: ['sh', '-c', 'sleep 2; echo helloworld02;']
containers:
- name: kubernetes-simple-pod
image: arisu1000/simple-container-app:latest
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
pods.spec.containers.livenessProbe
파드가 제대로 동작하는지, 파드 내부의 서비스가 제대로 동작하는지 감시 하기 위해
메니페스트에서 livenessProbe 속성을 추가한다.
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness-test-pod
name: liveness-http
spec:
containers:
- name: liveness-test-pod
image: k8s.gcr.io/liveness
args:
- /server
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: X-Custom-Header
value: Awesome
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe 를 통해 컨테이너에 /healthz URI 에 5초주기(periodSeconds)로 요청을 날리고 200 ~ 400 사이의 값이 반환될 경우 정상으로 간주한다.
그 이외의 값이 반환될 경우 kublet 에 의해 컨테이너가 재시작 된다.
서비스가 실행될 때 까지의 텀(initialDelaySeconds)을 10초로 설정한다.
k8s.gcr.io/liveness 이미지에는 10초동안만 status code 200 을 반환하고 그 이후로는 status code 500을 반환하도록 설정되어있다.
10초 후 아래 명령어를 실행하면
kubectl get pods --output wide
kubectl describe pod liveness-http
CrashLoopBackOff 상태값과 로그에 Liveness probe failed: HTTP probe failed with statuscode: 500 가 찍혀있는걸 확인 가능하다.
http 를 통한 파드 상태확인 외에도 tcp소켓, 명령 실행 등을 통해서도 상태확인이 가능하다.
https://kubernetes.io/ko/docs/concepts/workloads/pods/pod-lifecycle/#컨테이너-프로브-probe
pods.spec.containers.readinessProbe
컨테이너가 실행된 후 실제 서비스 요청에 응답할 수 있을지 설정.
자바 어플리케이션 처럼 실행하는데 시간이 걸릴 경우 유용함.
파드 CRUD
먼저 간단한 이미지를 빌드하고 private registry 에 등록
docker build -t photo-view:v2.0 .
docker image tag photo-view:v2.0 mydomain:5000/photo-view:v2.0
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mydomain:5000/photo-view v2.0 05e6c8ef4559 About a minute ago 924MB
photo-view v2.0 05e6c8ef4559 About a minute ago 924MB
docker image push mydomain:5000/photo-view:v2.0
https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
해당 private registry 를 kubectl 로 사용할 수 있도록 secret 쿠버네티스 리소스 생성
docker login 을 통해 $HOME/.docker/config.json 파일에 인증데이터를 업데이트 후 해당 파일로 secret 리소스를 생성하자.
kubectl create secret generic regcred \
--from-file=.dockerconfigjson=$HOME/.docker/config.json \
--type=kubernetes.io/dockerconfigjson
맥의 경우 key 정보가 config.json 에 저장되는 것이 아닌 별도의 키체인에 저장되어 있어 위의 명령을 사용해봤자 auth faild 오류가 발생할것이다.
맥의 경우 바로 kubectl 에 secret 생성하는 아래의 명령 사용
kubectl create secret docker-registry regcred \
--docker-server=mydomain:5000 \
--docker-username=admin \
--docker-password=admin
--namespace=''옵션을 생략했기에 기본적으로 default 에 적용된다.
해당 이미지로 파드 create
# pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: photoview-pod
labels:
app: photo-view
env: stage
spec:
containers:
- image: mydomain:5000/photo-view:v2.0
name: photoview-container
ports:
- containerPort: 80
imagePullSecrets:
- name: regcred # 생성한 secret name 설정
kubectl apply -f Pod/pod.yaml
pod/photoview-pod created
kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
photoview-pod 1/1 Running 0 2m13s app=photo-view,env=stage
kubectl describe pods photoview-pod
// 상세정보 확인 가능
항상 imagePullSecrets를 매니페스트 파일에 적용해야만 다운이 가능한데 이를 service account 에 포함하여 생략할 수 있다.
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "regcred"}]}'
새로운 이미지 photo-view:v1.0 을 빌드, 태그, private-registry 에 push
docker build -t photo-view:v1.0 .
docker image tag photo-view:v1.0 mydomain:5000/photo-view:v1.0
docker image push mydomain:5000/photo-view:v1.0
위에 생성한 photoview-pod의 이미지를 photo-view:v1.0 로 변경해보자.
매니페스트 파일의 image 속성을 변경
# pod.yaml
apiVersion: v1
kind: Pod
...
spec:
containers:
- image: mydomain:5000/photo-view:v1.0
...
...
kubectl apply -f Pod/pod.yaml
pod/photoview-pod configured
apply 명령으로 생성/수정이 가능하다.
파드 삭제
kubectl delete -f Pod/pod.yaml
파드 스케줄링 구조
스케줄링은 쿠버네티스 마스터 서버 API Server 에서 관리한다.
파드가 마스터 서버에 의해 어떤 노드에 전개(스케줄링)될지 알아보자.
API Server는 클러스터 안의 쿠버네티스 리소스를 관리(CRUD), etcd 에 접근지원 하기 위해 Restfule 인터페이스를 지원한다.
파드가 생성되는 루틴은 대략적으로 아래와 같다.
kubectl명령 실행 -API Server의RestAPI요청.- 클러스터 구성 정보 갱신 -
kubectl로 인해 변경된 매니페스트 내용을etcd에 저장. - 클러스터 구성 변경 - 젼달받은 매니페스트와
etcd의 데이터간 변화가 있다면API Server에게 통지. - 파드의 작성 -
API Server가 통지받은 내용이 있다면 워커노드에 파드 업데이트 하도록 명령 송신, 노드내의kubelet은 전달받은 명령을 수행한다(새로운 파드 생성).
3번과 4번 과정 사이에서 파드를 어떤 노드에 스케줄링할지 결정한다.
스케줄링은 아래 2가지 규칙에 의해 결정된다.
- 노드의 필터링
- 파드에
NodeSelector를 설정하고 있는지 검사 - 파드에 설정된 리소스 요구에 매칭되는 노드 필터링
- 파드에
- 노드의 우선순위
- CPU, Memory 사용량에 따라 노드의 우선순위 결정
- 우선순위별로 파드를 배치
파드 스케줄링 제어
위의 nodeSelector 속성을 정의해 명시적으로 노드를 정해주지 않고도 스케줄링할 수있는 방법이 여럿 있다.
Affinity
https://kubernetes.io/ko/docs/concepts/configuration/assign-pod-node/#어피니티-affinity-와-안티-어피니티-anti-affinity
Affinity 는 친밀감이란 뜻으로 서로다른 2개의 파드를 왠만하면 같은노드에 배치시키고 싶을때(podAffinity)
혹은 다른노드에 배치시키고 싶을때(podAntiAffinity) 사용한다.
또한 특정 조건을 갖춘 노드에서만 동작하도록 하는 nodeAffinity 도 있다.
Taints, Tolerations
https://kubernetes.io/ko/docs/concepts/configuration/taint-and-toleration/
Taints: 오염시키다 Tolerations: 용인,관용
서로 상반되는 역할을 하는 명령
Taints는 노드에 설정하는 것으로 파드를 스케줄링 하거나 조건에 맞는 파드만 스케줄링 하도록 할 수 있다.
Taints가 설정된 노드에 파드를 배치하고 싶다면 Tolerations 설정이 필요하다.
파드 리소스 설정
CPU, Memory 리소스는 매니페스트 파일에서 설정 가능하다.
apiVersion: v1
kind: Pod
metadata:
name: requests-pod
spec:
containers:
- image: busybox
command: ["dd", "if=/dev/zero", "of=/dev/null"]
name: main
resources:
requests:
cpu: 50m
memory: 300Mi # (K M G T P), (Ki Mi Gi Ti Pi) 사용 가능
Minikube 에서 생성된 node 의 CPU Limits 는 100m, Memory Limits는 390Mi남아있다.
위의 매니페스트 설정대로 파드를 생성하고 줄어드는 Limits 를 확인
requests 속성을 파드의 최소 리소스 요청 단위를 뜻한다.
kubectl create -f Pod/pod-request.yaml
pod/requests-pod created
kubectl get pods --output wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
requests-pod 1/1 Running 0 39s 172.18.0.2 minikube-m03 <none> <none>
kubectl describe node minikube-m03 명령으로 남은 리소스를 확인해보면 정확인 CPU 50m, Memory 300Mi 만큼 Limits 가 줄어있다.
쿠버네티스에서 파드를 스케줄링할때 실제 노드의 리소스사용량이 아닌 메니페스트에 설정된 리소스 설정으로 스케줄링 됨을 알 수 있다.
파드에 많은 리소스를 할당하게 되면 그만큼 다른 파드를 노드에 설정할 수 없다.
만약 파드에 설정한 resources 사용량을 넘게되면 쿠버네티스에서 어떻게 처리하는지 알아보자.
apiVersion: v1
kind: Pod
metadata:
name: limits-pod
spec:
containers:
- name: main
image: polinux/stress
resources:
limits:
cpu: 90m
memory: 300Mi
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "500M", "--vm-hang", "1"]
stress 프로그램으로 Memory에 300M를 넘는 500M 를 설정하여 실행
limits 속성은 파드 요청 제한 단위를 뜻한다.
kubectl get pods --output wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
limits-pod 0/1 ContainerCreating 0 6s <none> minikube-m03 <none> <none>
kubectl get pods --output wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
limits-pod 1/1 Running 0 9s 172.18.0.2 minikube-m03 <none> <none>
kubectl get pods --output wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
limits-pod 0/1 OOMKilled 0 9s 172.18.0.2 minikube-m03 <none> <none>
kubectl get pods --output wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
limits-pod 0/1 CrashLoopBackOff 2 43s 172.18.0.2 minikube-m03 <none> <none>
kubectl describe pod limits-pod
# 상세 로그 확인.
쿠버네티스에선 복구기능을 갖고 있기에 오류가 감지되면 기본적으로 재시작한다.
restartPolicy속성 에 따라 옵션이 다르며 기본값은 Always 이다.
kubectl get pods --output wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
limits-pod 0/1 CrashLoopBackOff 6 7m15s 172.18.0.2 minikube-m03 <none> <none>
시간이 지남에 따라 RESTARTS 횟수가 계속 늘어나고 있다.