[쿠버네티스 입문] 5-1. 파드
파드 개념
쿠버네티스는 파드라는 단위로 컨테이너를 묶어서 관리
보통 파드 안에 컨테이너 하나가 아닌 여러 개의 컨테이너로 구성됨
파드로 컨테이너 여러 개를 한꺼번에 관리할 때는 컨테이너마다 역할을 부여할 수 있음
파드 하나에 속한 컨테이너들은 모두 노드 하나 안에서 실행 (노드란?)
-> 파드의 역할 중 하나가 컨테이너들이 같은 목적으로 자원을 공유하는 것이므로 가능
파드 하나 안에 컨테이너들이 IP 하나를 공유함
파드에 192.168.10.10 이라는 IP 로 접근하며, 파드안 컨테이너와 통신할 때는 컨테이너마다 다르게 설정한 포트(Port)를 사용함
파드 사용하기
# pod-sample.yaml
apiVersion: v1
kind: Pod
metadata:
name: kubernetes-simple-pod
labels:
app: kubernetes-simple-pod
spec:
containers:
- name: kubernetes-simple-pod
image: arisu1000/simple-container-app:latest
ports:
- containerPort: 8080
- .metadata.name : 파드 이름을 설정
- .metadata.labels.app : 오브젝트를 식별하는 레이블을 설정. 여기서는 해당 파드가 앱 컨테이너
- .spec.containers[].name : 컨테이너 이름을 설정
- .spec.containers[].image : 컨테이너에서 사용할 이미지 지정
- .spec.containers[].ports[].containerPort : 해당 컨테이너에 접속할 포트 번호를 설정
작성한 템플릿으로 Pod 생성
$ kubectl apply -f pod-sample.yaml
# 생성된 Pod 확인
$ kubectl get pods
파드 생명 주기
파드 생명주기 공식 문서 : https://kubernetes.io/ko/docs/concepts/workloads/pods/pod-lifecycle/
파드는 생성부터 삭제까지의 과정에 생명 주기가 존재
아래는 pod 의 status 목록이다.
- Pending: 쿠버네티스 시스템에 파드를 생성하는 중인 상태
- 컨테이너 이미지 다운로드 후, 전체 컨테이너 실행하는 중
- Running: 파드 안 모든 컨테이너가 실행 중인 상태.
- 1개 이상의 컨테이너가 실행 중 이거나 시작 또는 재시작 상태일 수 있습니다.
- Succeeded: 파드 안 모든 컨테이너가 정상 실행 종료된 상태.
- Failed: 파드 안 모든 컨테이너 중 정상적으로 실행 종료되지 않은 컨테이너가 있는 상태
- 컨테이너 종료 코드가 0이 아니면 비정상 종료이거나 시스템이 직접 컨테이너를 종료한 것
- Unknown: 파드의 상태를 확인할 수 없는 상태
- 보통 파드가 있는 노드와 통신할 수 없을 때
현재 파드 생명 주기 확인
$ kubectl describe pods {파드 이름}
# 명령어 실행 후 Status 항목 확인
Conditions 항목은 파드의 현재 상태 정보를 나타냄
Conditions 의 Type 의미
- Initialized: 모든 초기화 컨테이너가 성공적으로 시작 완료되었다는 뜻
- Ready: 파드는 요청들을 실행할 수 있고 연결된 모든 서비스의 로드밸런싱 풀에 추가되어야 한다는 뜻
- ContainersReady: 파드 안 모든 컨테이너가 준비 상태라는 뜻
- PodScheduled: 파드가 하나의 노드로 스케줄을 완료했다는 뜻
- Unscheduleable: 스케줄러가 자원의 부족이나 다른 제약 등으로 지금 당장 파드를 스케줄 할 수 없다는 뜻
Conditions 의 Status 는
- True: 상태 활성화
- False: 상태 비활성화
- Unknown: 상태 알 수 없음
kubelet 으로 컨테이너 진단하기
컨테이너 실행된 후 kubelet 이 컨테이너를 주기적으로 진단함
( kubelet 공식 문서 : https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/ )
이때 Probe라는 개념이 등장하는데, kubelet 에 의해 컨테이너의 상태를 주기적 진단을 의미한다.
- livenessProbe: 컨테이너가 실행됐는지 확인
- livenessProbe 실패 시, 컨테이너를 종료시키고, 재시작 정책에 따라 컨테이너를 재시작함
- 기본 상태값은 Success
- readinessProbe: 컨테이너가 실행된 후 실제로 서비스 요청에 응답할 수 있는지 진단
- 진단 실패 시, endpoint controller 는 해당 파드에 연결된 모든 서비스를 대상으로 엔드포인트에서 파드의 IP 정보를 제거함
- 첫 번째 readinessProbe를 하기 전까지 기본 상태 값은 Failure
- readinessProbe 를 지원하지 않는 컨테이너라면 기본 상태값은 Success 이다.
- startupProbe: 컨테이너 안 애플리케이션이 시작되었는지 나타냄.
- stageupProbe 진단이 성공할 때까지 나머지 브로브는 활성화되지 않음
- 진단이 실패하면 kubelet이 컨테이너를 종료시키고, 컨테이너 재시작 정책에 따라 처리함
- startupProbe 가 없는 컨테이너라면 기본 상태값은 Success 이다.
readinessProbe를 지원하는 컨테이너는 실행직후 바로 트래픽을 받지 않음.
실제 트래픽을 받을 준비가 됐음을 확인 후 트래픽을 받을 수 있음
자바 애플리케이션처럼 프로세스가 시작된 후 앱이 초기화될 때까지 시간이 걸리는 상황에 유용
# Probe 설정 예시
apiVersion: v1
kind: Pod
metadata:
name: kubernetes-simple-pod
labels:
app: kubernetes-simple-pod
spec:
containers:
- name: kubernetes-simple-pod
image: arisu1000/simple-container-app:latest
ports:
- containerPort: 8080
# readinessProbe 설정
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
# livenessProbe 설정
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
컨테이너 진단은 컨테이너가 구현한 핸들러(handler)를 kubelet이 호출해서 실행
핸들러에는 3가지가 존재
- ExecAction: 컨테이너 안에 지정된 명령을 실행하고 종료 코드가 0일때 Success라고 진단
- TCPSocketAction: 컨테이너 안에 지정된 IP와 포트로 TCP 상태를 확인하고 포트가 열려있으면 Success라고 진단
- HTTPGetAction: 컨테이너 안에 지정된 IP, 포트, 경로로 HTTP GET 요청을 보냄. 응답 상태 코드가 200 ~ 400 사이면 Success 로 진단
진단 결과도 세 가지
- Success: 컨테이너 진단에 성공
- Failure: 컨테이너가 진단에 실패
- Unknown: 진단 자체가 실패해서 컨테이너 상태를 알 수 없음
초기화 컨테이너
초기화 컨테이너는 앱 컨테이너가 실행되기 전 파드를 초기화하는 용도로 사용
보안상 이유로 앱 컨테이너 이미지와 같이 두면 안 되는 앱의 소스코드를 별도로 관리할 때 유용
- 초기화 컨테이너는 여러 개 구성 가능 (여러개 라면 템플릿에 명시한 순서대로 초기화 컨테이너가 실행됨)
- 초기화 컨테이너 실행이 실패하면 성공할 때까지 재시작함
- 초기화 컨테이너가 모두 실행된 후 앱 컨테이너 실행이 시작됨
초기화 컨테이너의 특징을 활용하면, 파드 실행 시 앱 컨테이너가 외부의 특정 조건을 만족할 때까지 대기했다가 실행하도록 만들 수 있음
초기화 컨테이너는 이전에 소개한 Probe 는 지원하지 않음 (파드가 모두 준비되기 전에 실행한 후 종료되는 컨테이너이기 때문)
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']
kubernetes-simple-pod 라는 파드를 생성하기 전 초기화 컨테이너로 init-service 와 init-mydb를 실행
파드 인프라 컨테이너
모든 파드에서 항상 실행되는 pause 라는 파드 인프라 컨테이너가 존재
pause 는 파드 안 기본 네트워크로 실행, 프로세스 식별자가 1(PID 1)로 설정됨.
다른 컨테이너의 부모 역할. 파드 안 다른 컨테이너는 pause 가 제공하는 네트워크를 공유해서 사용함
pause 외 다른 컨테이너가 재시작되면 파드의 IP는 유지되지만, pause 컨테이너 재시작 시 파드 안 모든 컨테이너가 재시작됨
kubelet 명령 옵션으로 --pod-infra-container-image 가 있는데, 이는 pause 가 아닌 다른 컨테이너를 파드 인프라 컨테이너로 지정할 때 사용함.
스태틱 파드
kube-apiserver를 통하지 않고, kubelet이 직접 실행하는 파드
kubelet 설정의 --pod-manifest-path라는 옵션에 지정한 디렉터리에 실행하려는 스태틱 파드들을 넣어두면 kubelet이 감지하여 파드로 실행함
kube-apiserver로 스태틱파드를 조회할 수 있지만, 스태틱 파드에 어떤 명령을 실행할 수는 없다.
보통 스태틱 파드는 kube-apiserver 라던가 etcd 같은 시스템 파드를 실행하는 용도로 많이 사용됨
아래는 도커 데스크탑의 가상머신 내부로 들어가 스태틱 파드 정보를 조회한 결과
- etcd.yaml / kube-apiserver.yaml / kube-controller-manager.yaml / kube-scheduler.yaml 을 확인할 수 있음
파드에 CPU 와 메모리 자원 할당
노드 하나에 여러 개 파드를 실행하는 일이 있을 때, 노드 하나에 자원 사용량이 많은 파드가 모여있다면 파드들의 성능이 나빠질 수 있다.
전체 클러스터의 자원 사용 효율도 낮으므로 조정이 필요함
어떤 노드는 파드가 없어서 CPU나 메모리같은 자원이 남지만, 어떤 노드에는 파드들이 많아서 사용해야하는 자원이 부족할 수 있다.
쿠버네티스에는 이런 상황을 막는 여러 방법이 있다.
가장 기본적인 방법으로는 파드를 설정할 때 파드 안 각 컨테이너가 CPU나 메모리를 얼마나 사용할 수 있을지 조건을 지정하는 것
아래 4개 필드 값을 통해 조절 가능
- spec.containers[].resource.limits.cpu : 최대 cpu 허용량
- spec.containers[].resource.limits.memory : 최대 메모리 허용량
- spec.containers[].resource.requests.cpu : 최소 cpu 할당량
- spec.containers[].resource.requests.memory : 최대 메모리 할당량
cpu 는 CPU 코어 하나의 연산 능력 기준 단위. 1이면 코어 하나의 연산 능력 단위 ex) 1.5, 0.1, 1.1
memory 는 바이트 단위 용량 ex) 100M, 1G
# pod-resource.yaml
apiVersion: v1
kind: Pod
metadata:
name: kubernetes-simple-pod
labels:
app: kubernetes-simple-pod
spec:
containers:
- name: kubernetes-simple-pod
image: arisu1000/simple-container-app:latest
resources:
requests:
cpu: 0.1
memory: 200M
limits:
cpu: 0.5
memory: 1G
ports:
- containerPort: 8080
파드에 환경변수 설정
.spec.containers[].env[] 하위 필드를 확인
# 파드 환경변수 설정 예시
apiVersion: v1
kind: Pod
metadata:
name: kubernetes-simple-pod
labels:
app: kubernetes-simple-pod
spec:
containers:
- name: kubernetes-simple-pod
image: arisu1000/simple-container-app:latest
ports:
- containerPort: 8080
# 환경변수 나열
env:
- name: TESTENV01
value: "testvalue01"
- name: HOSTNAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: CPU_REQUEST
valueFrom:
resourceFieldRef:
containerName: kubernetes-simple-pod
resource: requests.cpu
- name: CPU_LIMIT
valueFrom:
resourceFieldRef:
containerName: kubernetes-simple-pod
resource: limits.cpu
value 와 valueFrom 의 차이를 잘 보자
- name: 사용할 환경변수의 이름을 설정
- value: 문자열이나 숫자 형식의 값을 설정
- valueFrom: 값을 직접 할당하는 것이 아닌 다른 곳에서 참조하는 값을 설정
- fieldRef: 파드의 현재 설정 내용을 값으로 설정
- fieldPath: .fieldRef 에서 어디서 값을 가져올 것인지 지정. 값을 참조하려는 항목의 위치
- resourceFieldRef: 컨테이너에 CPU, 메모리 사용량을 얼마나 할당했는지에 관한 정보를 가져옴
- containerName: 환경 변수 설정을 가져올 컨테이너 이름을 설정
- resource: 어떤 자원의 정보를 가져올지 설정
# 파드 환경 변수 설정 내용 확인하기
$ kubectl apply -f pod-env.yaml
# pod 내부 터미널로 이동
$ kubectl exec -it kubenetes-simple-pod -- sh
# env 입력으로 환경변수 확인
~ # env
# 특정 env 검색
~ # env | grep {검색할 환경변수 이름}
prefix 가 KUBERNETES_ 인 환경변수들은 쿠버네티스 안에서 현재 사용중인 자원 관련 정보
파드 구성 패턴
파드로 여러개의 컨테이너를 묶어서 구성, 실행할 때 몇가지 패턴
- 사이드카 패턴 : 기본 컨테이너는 원래 목적의 기능에 집중하도록 구성하고, 나머지 부가 기능들은 사이드카 컨테이너를 추가해서 사용
- 앰배서더 패턴 : 파드 안에서 프록시 역할을 하는 컨테이너 추가하는 패턴. 파드 안에서 외부서버에 접근할 때는 프록시 컨테이너를 통하도록 구성할 수 있음
- 어댑터 패턴 : 파드 외부로 노출되는 정보를 표준화하는 어댑터 컨테이너를 사용한다는 뜻