# 5장. 파드
## 파드의 필요성
서비스 레벨에 차이가 있으면서 한 머신에 있어야 할 공생 관계를 가진 경우를 컨트롤 하기 위해서
- local filesystem을 공유하는 git 동기화 컨테이너와 웹 서빙 컨테이너
- MSA에서 각 어플리케이션과 해당 어플리케이션의 정보 및 네트워크를 컨트롤하는 사이드카
## 쿠버네티스에서의 파드
- 쿠버네티스 컨테이너의 배포 단위로 같은 파드에 속한 컨테이너 들은 모두 같은 머신 혹은 node에 속한다.
- 동일 파드
- 동일 ip
- 포트
- 네트워크 네임스페이스
- 호스트 명(UTS 네임스페이스)
- UTS 네임스페이스 - 리눅스 커널의 네임스페이스 중 하나로 시스템의 호스트명과 도메인 이름을 격리하는 역할을 함, kubernetes에서 pod안의 모든 컨테이너들은 동일한 uts네임스페이스를 공유하고 그 결과 pod내의 모든 컨테이너들은 동일한 호스트명을 가짐. 이를 통해 하나의 pod내에서 실행 중인 여러 컨테이너들은 같은 호스트를 사용할 수 있게 되고 이것이 네트워크 상호작용을 간단하게 만드는 효과를 만든다고 한다.
- 프로세스 간 통신 채널로 동일 파드에 속하는 컨테이너는 서로 소통 가능
## 파드에 대한 생각
- 파드 안의 존재들은 모두 같은 스케일링 전략을 가져야 한다.
- 각기 다른 머신에 존재하여도 문제없이 실행될 수 있다면 같은 pod에 놓는 것은 좋지 못한 선택일 수 있다.
- ex) database와 웹서버
## 파드 매니페스트
- 정의: 쿠버네티스 api 객체를 단순히 텍스트 파일 형태로 표현한 것
- declarative configuration
- 상태를 지정하고 해당 상태를 유지하도록 조치를 취하는 서비스로 제출하는 것
- 처리과정
1. 매니페스트 파일을 API 서버에 제출
2. 매니페스트 검증 및 수락 + 처리
3. 영구 저장소(etcd)에 저장
1. etcd: Kubernetes의 분산 키-값 저장소로, 클러스터의 상태 정보를 모두 저장합니다. 이에는 파드 매니페스트를 비롯한 클러스터 내의 모든 오브젝트의 상태(예: 파드, 서비스, 컨피그맵, 시크릿, 노드 정보 등)가 포함됩니다.(gpt)
4. 스케줄러가 노드에 파드를 배치
5. kubelet에 의해 파드 실행
6. 매니페스트 파일에 기반하여 실제 객체를 지속적으로 관리
## 파드 생성
- kubectl run
```bash
user@AL02502768 kind % kubectl run kuard --generator=run-pod/v1 \
--image=gcr.io/kuar-demo/kuard-amd64:blue
pod/kuard created
```
- —generator 옵션
- 종류
- `run-pod/v1`: Pod를 생성하기 위한 생성기.
- `deployment/apps.v1`: Deployment를 생성하기 위한 생성기.
- 구 버전에서 쓰이는 방식이고 현재는 다음과 같은 방식으로 대체되었다고 한다.
```bash
kubectl run --image= --restart=Never
```

- 생성된 pods 확인
```bash
user@AL02502768 kind % kubectl get pods
NAME READY STATUS RESTARTS AGE
kuard 1/1 Running 0 15m
```
- 특정 파드 삭제
```bash
user@AL02502768 kind % kubectl delete pods/kuard
pod "kuard" deleted
```
## 파드 매니페스트 생성
- yaml이나 json으로 생성 가능하지만 주로 yaml 사용(comment)
- key-value 스타일
- metadata vs spec section
- metadata section: 파드와 그 라벨에 대한 설명
- spec: 컨테이너 목록 설명
- 예시코드:
```yaml
apiVersion: v1
kind: Pod
metadata:
name: kuard
spec:
containers:
- image: gcr.io/kuar-demo/kuard-amd64:blue
name: kuard
ports:
- containerPort: 8080
name: http
protocol: TCP
```
## 파드 실행
- apply 명령 사용
```bash
user@AL02502768 kind % kubectl apply -f kuard-pod.yaml
pod/kuard created
```
## 파드 조회
- get 명령 사용
```bash
user@AL02502768 kind % kubectl get pods
NAME READY STATUS RESTARTS AGE
kuard 1/1 Running 0 20s
```
## 파드 세부 사항
- describe 명령어 사용
```bash
user@AL02502768 kind % kubectl describe pods kuard
# 파드에 대한 기본적인 정보
Name: kuard
Namespace: default
Priority: 0
Node: kind-control-plane/10.89.1.4
Start Time: Mon, 02 Sep 2024 01:28:18 +0900
Labels:
Annotations: kubectl.kubernetes.io/last-applied-configuration:
""{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"kuard","namespace":"default"},"spec":{"containers":[{"image":"gcr.io/..."
Status: Running
IP: 10.244.0.6
IPs:
IP: 10.244.0.6
## 파드 내 컨테이너에 대한 설명
Containers:
kuard:
Container ID: containerd://33deba34b9f3e27905b686f25d97bd5b46e4af1d184231f74e7bcd183187e2a7
Image: gcr.io/kuar-demo/kuard-amd64:blue
Image ID: gcr.io/kuar-demo/kuard-amd64@sha256:1ecc9fb2c871302fdb57a25e0c076311b7b352b0a9246d442940ca8fb4efe229
Port: 8080/TCP
Host Port: 0/TCP
State: Running
Started: Mon, 02 Sep 2024 01:28:18 +0900
Ready: True
Restart Count: 0
Environment:
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-5btk2 (ro)
Conditions:
Type Status
PodReadyToStartContainers True
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
kube-api-access-5btk2:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional:
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors:
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
## 이벤트 정보
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 8m58s default-scheduler Successfully assigned default/kuard to kind-control-plane
Normal Pulled 8m58s kubelet, kind-control-plane Container image "gcr.io/kuar-demo/kuard-amd64:blue" already present on machine
Normal Created 8m58s kubelet, kind-control-plane Created container kuard
Normal Started 8m58s kubelet, kind-control-plane Started container kuard
```
- man page
```bash
user@AL02502768 kind % kubectl describe --help
Show details of a specific resource or group of resources
Print a detailed description of the selected resources, including related resources such as events or controllers. You
may select a single object by name, all objects of that type, provide a name prefix, or label selector. For example:
$ kubectl describe TYPE NAME_PREFIX
will first check for an exact match on TYPE and NAME_PREFIX. If no such resource exists, it will output details for
every resource that has a name prefixed with NAME_PREFIX.
Use "kubectl api-resources" for a complete list of supported resources.
Examples:
# Describe a node
kubectl describe nodes kubernetes-node-emt8.c.myproject.internal
# Describe a pod
kubectl describe pods/nginx
# Describe a pod identified by type and name in "pod.json"
kubectl describe -f pod.json
# Describe all pods
kubectl describe pods
# Describe pods by label name=myLabel
kubectl describe po -l name=myLabel
# Describe all pods managed by the 'frontend' replication controller (rc-created pods
# get the name of the rc as a prefix in the pod the name).
kubectl describe pods frontend
Options:
-A, --all-namespaces=false: If present, list the requested object(s) across all namespaces. Namespace in current
context is ignored even if specified with --namespace.
-f, --filename=[]: Filename, directory, or URL to files containing the resource to describe
-k, --kustomize='': Process the kustomization directory. This flag can't be used together with -f or -R.
-R, --recursive=false: Process the directory used in -f, --filename recursively. Useful when you want to manage
related manifests organized within the same directory.
-l, --selector='': Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)
--show-events=true: If true, display events related to the described object.
Usage:
kubectl describe (-f FILENAME | TYPE [NAME_PREFIX | -l label] | TYPE/NAME) [options]
Use "kubectl options" for a list of global command-line options (applies to all commands).
```
- 관련 설명 필요
## 파드 삭제
```bash
user@AL02502768 kind % kubectl delete pods/kuard
pod "kuard" deleted
```
## 파드에 접근
### 로그를 통해 더 많은 정보 얻기
- logs 명령어 사용
```bash
user@AL02502768 kind % kubectl logs kuard
2024/09/01 16:45:52 Starting kuard version: v0.10.0-blue
2024/09/01 16:45:52 **********************************************************************
2024/09/01 16:45:52 * WARNING: This server may expose sensitive
2024/09/01 16:45:52 * and secret information. Be careful.
2024/09/01 16:45:52 **********************************************************************
2024/09/01 16:45:52 Config:
{
"address": ":8080",
"debug": false,
"debug-sitedata-dir": "./sitedata",
"keygen": {
"enable": false,
"exit-code": 0,
"exit-on-complete": false,
"memq-queue": "",
"memq-server": "",
"num-to-gen": 0,
"time-to-run": 0
},
"liveness": {
"fail-next": 0
},
"readiness": {
"fail-next": 0
},
"tls-address": ":8443",
"tls-dir": "/tls"
}
2024/09/01 16:45:52 Could not find certificates to serve TLS
2024/09/01 16:45:52 Serving on HTTP on :8080
```
### exec을 사용해 컨테이너에서 명령 실행
```bash
user@AL02502768 kind % kubectl exec -it kuard -- ash
~ $ exit
```
- 참고사항: bash는 없음
```bash
user@AL02502768 kind % kubectl exec -it kuard -- bash
error: Internal error occurred: error executing command in container: failed to exec in container: failed to start exec "56fbf70a8f69023e46ca86000a3415fa23e0d3302d0e5598aa361169953148ba": OCI runtime exec failed: exec failed: unable to start container process: exec: "bash": executable file not found in $PATH: unknown
```
### 컨테이너 내외부로 파일 복사
- 안티패턴이지만 장애를 빠르게 해결하는 방안으로는 사용 가능
- 단 사용 후 이미지에 반영하여야 함
## 상태 검사
- 프로세스 상태 검사 → 파드를 항상 살아 있는 상태로 유지할 수 있음
- 검사 실패 시 프로세스 재시작
- 그러나 주요 프로세스를 항상 실행하게 하는 단순한 방식이어서 데드락 같은 상황을 처리할 수 없음
- 각 어플리케이션 별로 특화된 상태 검사가 필요
- 프로브라고 불리며 매니페스트에 정리
### 활성 프로브
- 활성 프로브를 추가한 매니페스트
```yaml
apiVersion: v1
kind: Pod
metadata:
name: kuard
spec:
containers:
- image: gcr.io/kuar-demo/kuard-amd64:blue
name: kuard
livenessProbe:
httpGet:
path: /healthy
port: 8080
initialDelaySeconds: 5
periodSeconds: 1
failureThreshold: 3
ports:
- containerPort: 8080
name: http
protocol: TCP
```
- 강제 실패 시:
```bash
87s Normal Created pod/kuard Created container kuard
87s Normal Started pod/kuard Started container kuard
87s Warning Unhealthy pod/kuard Liveness probe failed: HTTP probe failed with statuscode: 500
87s Normal Killing pod/kuard Container kuard failed liveness probe, will be restarted
```
### 준비 프로브
- 사용자 요청을 받을 수 있는 상태인지에 대한 체크
- 실패시 성공할 때까지 로드밸런서에서 제외, 주기적으로 시도하여 성공시 다시 트래픽 받음
### 시작 프로브
- 컨테이너가 시작될 때 한 번 실행됨. 이 프로브가 성공할 때까지 쿠버네티스는 컨테이너가 정상적으로 시작되고 있다고 가정하며, 성공하면 준비 및 라이브니스 프로브가 활성화됨
- 만약 시작 프로브가 실패하면, 컨테이너는 재시작되거나 실패 상태로 간주될 수 있음.
### 상태 검사의 기타 기입
tcp와 exec 프로브 존재
```yaml
apiVersion: v1
kind: Pod
metadata:
name: kuard
spec:
containers:
- image: gcr.io/kuar-demo/kuard-amd64:blue
name: kuard
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 1
livenessProbe:
httpGet:
path: /healthy
port: 8080
initialDelaySeconds: 5
periodSeconds: 1
failureThreshold: 3
ports:
- containerPort: 8080
name: http
protocol: TCP
```
## 리소스 관리
### 리소스 관리가 필요한 이유
- 컴퓨트 노드의 전체 사용률을 높여서 비용 효율성을 높이기 위해
- 이를 위해서는 각 컨테이너가 필요한 리소스를 쿠버네티스에 알려주어야 할 필요성이 있음
### 기호 표기 방법
- literals:
- 메모리 자원을 설정할 때 사용하는 표기 방식으로 기본 단위는 byte
- MB/GB/PB와 MiB/GiB/PiB의 차이 비교
- 1 MB = 1000KB
- 1 MIM = 1024KIB
- millicores:
- CPU 리소스를 설정할 때 사용하는 단위
- 1 core == 1000m
### 리소스 요청
- 개념: 해당 어플리케이션이 보장받아야 하는 최소 리소스 량
- 예시코드
```yaml
apiVersion: v1
kind: Pod
metadata:
name: kuard
spec:
containers:
- image: gcr.io/kuar-demo/kuard-amd64:blue
name: kuard
resources:
requests:
cpu: "500m"
memory: "128Mi"
ports:
- containerPort: 8080
name: http
protocol: TCP
```
- 리눅스 커널 cpu-shares:
- [관련링크](https://www.redhat.com/sysadmin/cgroups-part-two)
### 리소스 제한
- 개념: 해당 어플리케이션이 받을 수 있는 최대 리소스 량
- 예시코드
```yaml
apiVersion: v1
kind: Pod
metadata:
name: kuard
spec:
containers:
- image: gcr.io/kuar-demo/kuard-amd64:blue
name: kuard
resources:
requests:
cpu: "500m"
memory: "128Mi"
limits:
cpu: "800m"
memory: "256Mi"
ports:
- containerPort: 8080
name: http
protocol: TCP
```
## 볼륨을 통한 데이터 보존
### 파드에서 볼륨 사용
- 해당 파드 매니페스트에서 컨테이너가 접근할 수 있는 모든 볼륨을 정의
- 예시
```yaml
apiVersion: v1
kind: Pod
metadata:
name: kuard
spec:
volumes:
- name: "kuard-data"
hostPath: #워커 노드 임의의 위치를 컨테이너에 마운트 할 수 있는 예약 볼륨
path: "/var/lib/kuard"
```
### 컨테이너에서 볼륨 사용
- 특정 컨테이너에 마운트될 볼륨과 각 볼륨들이 마운트될 경로 정의
- 예시
```yaml
apiVersion: v1
kind: Pod
metadata:
name: kuard
spec:
volumes:
- name: "kuard-data"
hostPath: #워커 노드 임의의 위치를 컨테이너에 마운트 할 수 있는 예약 볼륨
path: "/var/lib/kuard"
containers:
- image: gcr.io/kuar-demo/kuard-amd64:blue
name: kuard
volumeMounts:
- mountPath: "/data"
name: "kuard-data"
ports:
- containerPort: 8080
name: http
protocol: TCP
```
## 파드에서 볼륨을 사용하는 다양한 방법
### 통신/동기화
- 두 컨테이너 사이의 볼륨 공유
```yml
apiVersion: v1
kind: Pod
metadata:
name: shared-volume-pod
spec:
volumes:
- name: shared-data
emptyDir: {} # 이 예제에서는 emptyDir을 사용합니다. Pod의 수명 동안만 데이터를 저장합니다.
containers:
- name: container-1
image: nginx
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html # 첫 번째 컨테이너에서의 마운트 경로
- name: container-2
image: busybox
command: [ "sh", "-c", "echo 'Hello from container-2' > /shared-data/message.txt && sleep 3600" ]
volumeMounts:
- name: shared-data
mountPath: /shared-data
```
### 캐시
- emptyDir 볼륨 공유
```yml
apiVersion: v1
kind: Pod
metadata:
name: empty-dir-example
spec:
containers:
- name: busybox
image: busybox
command: ["/bin/sh", "-c", "sleep 3600"]
volumeMounts:
- mountPath: /tmp/emptydir
name: temp-storage
volumes:
- name: temp-storage
emptyDir: {}
```
- emptydir
- pod가 생성될 때 자동으로 만들어지며, Pod가 삭제되면 함께 삭제됩
- 일반적으로는 로컬 디스크에 데이터를 저장하지만 메모리를 기반으로 저장할 수도 있음
```yml
volumes:
- name: temp-storage
emptyDir:
medium: Memory
```
### 영구데이터
- 클라우드 같은 원격 네트워크 스토리지 볼륨 사용
### 호스트 파일 시스템 필요시
- hostPath라는 볼륨을 사용
```yml
apiVersion: v1
kind: Pod
metadata:
name: hostpath-example
spec:
containers:
- name: hostpath-container
image: nginx
volumeMounts:
- mountPath: /usr/share/nginx/html
name: hostpath-volume
volumes:
- name: hostpath-volume
hostPath:
path: /data/nginx
type: Directory
```