POD
- 쿠버네티스가 관리하는 가장 작은 컴퓨팅 단위로 하나 이상의 컨테이너 그룹이다.
- 컨테이너의 공동 배포된 그룹이며 쿠버네티스의 기본 빌딩 블록을 대표
- 쿠버네티스는 컨테이너를 개별적으로 배포하지 않고 컨테이너의 포드를 항상 배포하고 운영
- 일반적으로 포드는 단일 컨테이너만 포함하지만 다수의 컨테이너를 포함할 수 있음
- 포드는 다수의 노드에 생성되지 않고 단일 노드에서만 실행
- 여러 프로세스를 실행하기 위해서는 컨테이너 당 단일 프로세스가 적합
-
다수의 프로세스를 제어하려면? -> 다수의 컨테이너를 다룰 수 있는 그룹 필요
- 포드 관리의 장점
- 포드는 밀접하게 연관된 프로세스를 함께 실행하고 마치 하나의 환경에서 동작하는 것처럼 보임
- 그러나 동일한 환경을 제공하면서 다소 격리된 상태로 유지
- 동일한 포드의 컨테이너 사이의 부분 격리
- 포드의 모든 컨테이너는 동일한 네트워크 및 UTS 네임스페이스에서 실행
- 같은 호스트 이름 및 네트워크 인터페이스를 공유 (포드 충돌 가능성 있음)
- 포드의 모든 컨테이너는 동일한 IPC 네임스페이스 아래에서 실행되며 IPC를 통해 통신 가능
- 최신 쿠버네티스 및 도커 버전에는 동일한 PID 네임스페이스를 공유할 수 있지만 이 기능은 기본 활성화돼있지 않다.
- 플랫 인터 포드 네트워크 구조
- 쿠버네티스 클러스터의 모든 포드는 공유된 단일 플랫, 네트워크 주소 공간에 위치
- 포드 사이에는 NAT 게이트웨이가 존재하지 않는다.
- 컨테이너를 포드 전체에 적절하게 구성하는 방법
- 다수의 포드로 멀티티어 애플리케이션 분할
- 각각 스케일링이 가능한 포드로 분할
- ex) FE Process와 BE Process를 같은 포드에 구성하기 보다는 각각의 포드로 구성하는 것이 좋다.
- 밀접한 프로세스가 아닌 경우에는 한 포드에 여러 컨테이너를 사용하지 않는다.
- YAML로 POD Descriptor 만들기
- kubectl 실행 명령으로 간단한 리소스 작성 방법도 가능하지만 일부 항목에 대해서만 가능하며 용의하지 않다.
- 모든 쿠버네티스 객체를 YAML로 정의하면 버전 제어 시스템에 저장 가능
- 모든 API에 대한 내용: https://kubernetes.io/docs/reference 참고
- POD 정의 구성 요소
- apiVersion: 쿠버네티스 API의 버전을 가리킴
- kind: 어떤 리소스 유형인지 결정(포드 레플리카컨트롤러, 서비스 등)
- 메타데이터: 포드와 관련된 이름, 네임스페이스, 레이블, 그 밖의 정보 존재
- 스펙: 컨테이너, 볼륨등의 정보
- 상태: 포드의 상태, 각 컨테이너의 설명 및 상태, 포드 내부의 IP 및 그 밖의 기본 정보 등
POD Descriptor 작성
-
yaml 파일 작성
server1@server1-VirtualBox:~/yaml$ vi go-test.yaml apiVersion: v1 kind: Pod metadata: name: go-test spec: containers: - name: go-test image: devtak/test:v1.0 ports: - containerPort: 8080
- apiVersion: YAML 파일에서 정의한 오브젝트의 API 버전을 나타낸다.
- kind: 해당 리소스의 종류를 나타낸다.
- metadata: 라벨, 주석, 이름 등과 같은 리소스의 부가 정보를 입력
- spec: 리소스를 생성하기 위한 자세한 정보를 입력
-
yaml 파일로 deploy 생성하기
server1@server1-VirtualBox:~/yaml$ kubectl create -f go-test.yaml // server1@server1-VirtualBox:~/yaml$ kubectl apply -f go-test.yaml server1@server1-VirtualBox:~/yaml$ kubectl get pod -o yaml apiVersion: v1 items: - apiVersion: v1 kind: Pod metadata: creationTimestamp: "2021-04-02T06:41:26Z" managedFields: - apiVersion: v1 fieldsType: FieldsV1 fieldsV1: f:spec: f:containers: k:{"name":"go-test"}: .: {} f:image: {} f:imagePullPolicy: {} f:name: {} f:ports: .: {} k:{"containerPort":8080,"protocol":"TCP"}: .: {} f:containerPort: {} f:protocol: {} f:resources: {} f:terminationMessagePath: {} f:terminationMessagePolicy: {} f:dnsPolicy: {} f:enableServiceLinks: {} f:restartPolicy: {} f:schedulerName: {} f:securityContext: {} f:terminationGracePeriodSeconds: {} manager: kubectl-create operation: Update time: "2021-04-02T06:41:26Z" - apiVersion: v1 fieldsType: FieldsV1 fieldsV1: f:status: f:conditions: k:{"type":"ContainersReady"}: .: {} f:lastProbeTime: {} f:lastTransitionTime: {} f:status: {} f:type: {} k:{"type":"Initialized"}: .: {} f:lastProbeTime: {} f:lastTransitionTime: {} f:status: {} f:type: {} k:{"type":"Ready"}: .: {} f:lastProbeTime: {} f:lastTransitionTime: {} f:status: {} f:type: {} f:containerStatuses: {} f:hostIP: {} f:phase: {} f:podIP: {} f:podIPs: .: {} k:{"ip":"172.17.0.2"}: .: {} f:ip: {} f:startTime: {} manager: kubelet operation: Update time: "2021-04-02T06:41:29Z" name: go-test namespace: default resourceVersion: "12002" uid: 463e3c63-be3b-4563-805d-e158bacac1e8 spec: containers: - image: devtak/test:v1.0 imagePullPolicy: IfNotPresent name: go-test ports: - containerPort: 8080 protocol: TCP resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File volumeMounts: - mountPath: /var/run/secrets/kubernetes.io/serviceaccount name: default-token-8p5fp readOnly: true dnsPolicy: ClusterFirst enableServiceLinks: true nodeName: minikube preemptionPolicy: PreemptLowerPriority priority: 0 restartPolicy: Always schedulerName: default-scheduler securityContext: {} serviceAccount: default serviceAccountName: default terminationGracePeriodSeconds: 30 tolerations: - effect: NoExecute key: node.kubernetes.io/not-ready operator: Exists tolerationSeconds: 300 - effect: NoExecute key: node.kubernetes.io/unreachable operator: Exists tolerationSeconds: 300 volumes: - name: default-token-8p5fp secret: defaultMode: 420 secretName: default-token-8p5fp status: conditions: - lastProbeTime: null lastTransitionTime: "2021-04-02T06:41:26Z" status: "True" type: Initialized - lastProbeTime: null lastTransitionTime: "2021-04-02T06:41:29Z" status: "True" type: Ready - lastProbeTime: null lastTransitionTime: "2021-04-02T06:41:29Z" status: "True" type: ContainersReady - lastProbeTime: null lastTransitionTime: "2021-04-02T06:41:26Z" status: "True" type: PodScheduled containerStatuses: - containerID: docker://153a1cc21662b7620cc32fcb4638d607c24614c28d94280c321bcfe90ba49159 image: devtak/test:v1.0 imageID: docker-pullable://devtak/test@sha256:88b8e9599f84da43bfe13805bcce93e474a6b79c5564d535faa1b4b54eec6d99 lastState: {} name: go-test ready: true restartCount: 0 started: true state: running: startedAt: "2021-04-02T06:41:28Z" hostIP: 192.168.49.2 phase: Running podIP: 172.17.0.2 podIPs: - ip: 172.17.0.2 qosClass: BestEffort startTime: "2021-04-02T06:41:26Z" kind: List metadata: resourceVersion: "" selfLink: ""
- 컨테이너에서 호스트로 포트 포워딩
- 디버깅 혹은 다른 이유로 서비스를 거치지 않고 특정 포드와 통신하고 싶을 때 사용
- kubectl port-forward 명령 수행
- 컨테이너 8081 포트를 pod의 8080 포트로 전달 ``` server1@server1-VirtualBox:~/yaml$ kubectl port-forward go-test 8081:8080 Forwarding from 127.0.0.1:8081 -> 8080 Forwarding from [::1]:8081 -> 8080
http://127.0.0.1:8081/hello 연결 확인 ```
- 삭제도 가능하다.
server1@server1-VirtualBox:~/yaml$ kyubectl delete -f go-test.yaml server1@server1-VirtualBox:~/yaml$ kyubectl delete pod go-test
- 로그 확인도 가능하다.
server1@server1-VirtualBox:~/yaml$ kubectl logs go-test
- 포드에 주석 추가하기
- 각 포드나 API 객체 설명이 추가
- 클러스터를 사용하는 모든 사람이 각 객체의 정보를 빠르게 확인 가능
- 예를 들어 객체를 만든 사람의 이름을 지정
- 공동 작업 가능
- 총 256KB까지 포함 가능
server1@server1-VirtualBox:~/yaml$ kubectl annotate pod http-go key="test1234" pod/http-go annotated server1@server1-VirtualBox:~/yaml$ kubectl get pod http-go -o yaml
- 포드 삭제
- 만든 포드 조회
- 포드 삭제
server1@server1-VirtualBox:~/yaml$ kubectl delete pod <포드 이름>
- 전체 포드 삭제
server1@server1-VirtualBox:~/yaml$ kubectl delete pod --all
라이브니스, 레디네스, 스타트업 프로브 구성
- Liveness Probe
- 컨테이너 살았는지 판단하고 다시 시작하는 기능
- 컨테이너의 상태를 스스로 판단하여 교착 상태에 빠진 컨테이너를 재시작
- 버그가 생겨도 높은 가용성을 보입
- Readiness Probe
- 포드가 준비된 상태에 있는지 확인하고 정상 서비스를 시작하는 기능
- 포드가 적절하게 준비되지 않은 경우 로드밸런싱을 하지 않음
- Startup Probe
- 애플리케이션의 시작 시기 확인하여 가용성을 높이는 기능
- Liveness, Readiness의 기능 비활성화
- Liveness Command 설정 - 파일 존재 여부 확인
- 리눅스 환경에서 커맨드 실행 성공 시 0 (컨테이너 유지)
- 실패하면 그 외 값 출력 (컨테이너 재시작)
```
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
names: liveness-exec
spec:
containers:
- name: liveness
image: k8c.gcr.io/busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
livenessProve:
exec:
command:
- cat
- /tmp/healthy initialDelaySeconds: 5 periodSeconds: 5 ```
- initialDelaySeconds: 5 -> POD이 실행되고 5초 뒤부터 확인
- periodSeconds: 5 -> 5초마다 확인
- spec.containers.args 에서 /tmp/healthy를 생성하고 삭제했다.
- livenessProve는 /tmp/healthy를 확인한다. 즉, 30초 뒤에 삭제하기 때문에 30초 뒤에 컨테이너가 죽었다고 판단하고 다시 실행한다.
- 아래 명령어로 확인할 수 있다.
$ kubectl describe pod liveness-exec
- name: liveness
image: k8c.gcr.io/busybox
args:
- Liveness 웹 설정 - http 요청 확인
- Response Code가 200 이상, 400 미만: 컨테이너 유지
- Response Code가 그 외(500 server error): 컨테이너 재시작
```
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
names: liveness-http
spec:
containers:
- name: liveness
image: k8c.gcr.io/busybox
args:
- /server
livenessProve:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: Custom-Header value: Awesome initialDelaySeconds: 3 periodSeconds: 3 ```
- /server
livenessProve:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: liveness
image: k8c.gcr.io/busybox
args:
- TCP 설정
- TCP 연결로 확인
- Readiness TCP 설정
- 준비 프로브는 8080포트를 검사
- 5초 후부터 검사 시작
- 검사 주기는 10초 -> 서비스를 시작해도 된다.
- Liveness TCP 설정
- 활성화 프로브는 8080포트를 검사
- 15초 후부터 검사 시작
- 검사 주기는 20초 -> 컨테이너를 재시작하지 않아도 된다.
apiVersion: v1 kind: Pod metadata: names: goproxy labels: app: goproxy spec: containers: - name: goproxy image: k8c.gcr.io/goproxy:0.1 ports: - containerPort: 8080 readinessProve: tcpSocket: port: 8080 initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: tcpSocket: port:8080 initialDelaySeconds: 3 periodSeconds: 3
- Startup Probe
- 시작할 때까지 검사를 수행
- http 요청을 통해 검사
- 30번을 검사하며 10초 간격으로 수행
- 300(30 * 10)초 후에도 포드가 정상 동작하지 않는 경우 종료 -> 300초 동안 포드가 정상 실행되는 시간을 벌어준다.
ports: - name: liveness-port containerPort: 8080 hostPort: 8080 livenessProbe: httpGet: path: /healthz port: liveness-port failureThreshold: 1 periodSeconds: 10 startupProbe: httpGet: path: /healthz port: liveness-port failureThreshold: 30 periodSeconds: 10
포드와 도커 컨테이너
- 포드를 사용하는 이유
- 여러 리눅스 네임스페이스를 공유하는 여러 컨테이너들을 추상화된 집합으로 사용하기 위해서이다.
- 네트워크를 생각해보면, 도커에 컨테이너는 같은 네트워크 네임스페이스를 컨테이너 간에 공유해 사용할 수 있도록 설정하기 때문에 여러 컨테이너가 동일한 네트워크 환경을 갖는다.
- 포드는 네트워크 뿐만 아니라 여러 네임스페이스를 공유하여 사용할 수 있다.
완전한 애플리케이션으로써의 포드
- 실제 쿠버네티스 환경에서는 1개의 컨테이너로 구성된 포드를 사용하는 경우가 많다.
- 하나의 포드는 하나의 완전한 애플리케이션이다.
- 하지만 컨테이너가 실행되기 위해 부가적인 기능을 필요로 한다면?
- 사이드카(sidecar)포드에 정의된 부가적인 컨테이너를 포드내에 포함하여 생성할 수 있다.
** 참고: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
** 참고: 데브옵스를 위한 쿠버네티스 마스터
** 참고: 시작하세요 도커/쿠버네티스