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
횟수가 계속 늘어나고 있다.