일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 코드프레소
- REPLICATION
- Elastic Load Balancing
- NoSQL
- AWS
- springboot
- codepresso
- kubernetes
- 아키텍처
- TypeScript
- docker
- Redis
- ASG
- Typesript
- Auto Scaling Group
- Jenkins
- ELB
- k8s
- ci/cd
- Today
- Total
Study Note
쿠버네티스 Pod - [Kubernetes, k8s] 본문
Pod는 쿠버네티스의 최소 실행 단위입니다. 쿠버네티스는 Pod를 통해 기본 가상환경을 제공합니다.
가상환경 플롬폼 실행 단위 비교
- 가상머신 : Instance
- 도커 : Container
- 쿠버네티스 : Pod
Pod 특징
- 1개 이상의 컨테이너 실행
- Pod는 1개 이상의 컨테이너를 가질 수 있습니다. 보통 1개의 컨테이너를 실행하며, 3개 이상 넘어가는 경우는 거의 없습니다.
- 동일 노드에 할당
- Pod 내의 실행되는 컨테이너들은 반드시 동일한 노드에 할당되며 동일한 생명주기를 갖습니다.
[Pod 삭제 시 Pod 내의 모든 컨테이너 삭제]
- Pod 내의 실행되는 컨테이너들은 반드시 동일한 노드에 할당되며 동일한 생명주기를 갖습니다.
- 고유의 Pod IP
- Pod 리소스는 노드 IP와 별개로 클러스터 내에서 접근 가능한 고유 IP를 할당 받습니다.
- 다른 노드에 위치한 Pod(노드의 IP가 다름)라도 Pod 고유 IP를 이용하여 NAT(Network Address Translation) 통신 없이 접근이 가능합니다.
- IP 공유
- Pod 내에 있는 컨테이너들은 서로 IP를 공유하기 때문에 서로 localhost를 통해 접근이 가능합니다.
[이때 포트를 이용하여 구분할 수 있습니다.]
- Pod 내에 있는 컨테이너들은 서로 IP를 공유하기 때문에 서로 localhost를 통해 접근이 가능합니다.
- volumn 공유
- Pod 안의 컨테이너들은 동일한 볼륨과 연결이 가능하여 파일 시스템 기반으로 파일을 공유할 수 있습니다.
YAML을 통한 Pod 생성
다음 [--dry-run, -o yaml] 옵션을 통해 Pod를 실제로 생성하지 않고 템플릿 파일을 생성할 수 있습니다.
kubectl run mynginx --image nginx --dry-run=client -o yaml > mynginx.yaml
# mynginx.yaml
kind: Pod
metadata:
creationTimestamp: null
labels:
run: mynginx
name: mynginx
spec:
containers:
- image: nginx
name: mynginx
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
- apiVersion : 모든 리소스에 정의되어 있으며, 리소스의 이름이 동일한 경우 이름 충돌을 피하기 위한 목적입니다. 프로그래밍 언어의 패키지와 유사한 역할을 합니다.
- kind : 리소스의 타입을 정의합니다. [Pod, Service, Replicaset, Deployment]
- metadata : 리소스의 메타 데이터입니다.
- labels : 리소스의 라벨 정보입니다.
- name : 리소스의 이름 정보입니다.
- spec : 리소스의 스펙을 정의합니다. [리소스마다 조금씩 차이가 있습니다.]
- containers : 1개 이상의 컨테이너를 정의합니다.
- name : 컨테이너 이름 정보입니다.
- image : 컨테이너 이미지 주소를 지정합니다.
- containers : 1개 이상의 컨테이너를 정의합니다.
Pod 생성 순서
다음 명령을 통해 위에서 생성한 YAML 정의서를 통해 Pod를 생성할 수 있습니다.
kubectl apply -f mynginx.yaml
// 실행 구조 이미지 필요
- Kubectl 명령을 통해 Pod 정의를 쿠버네티스 마스터에 전달
- 쿠버네티스 마스터가 YAML 정의에 대해서 유효청 체크 (validation check) 후에 특정 노드에 사용자 요청에 따라 컨테이너를 실행하도록 명령
- 노드(kubelet)는 명령에 따라 요청 사항에 맞게 컨테이너를 노트에서 실행
라벨링 시스템
라벨 정보 부여
다음과 같은 방법을 사용하여 라벨 정보를 부여할 수 있습니다.
- label 명령을 이용하는 방법
kubectl label pod <NAME> <KEY>=<VALUE>
# ex)
kubectl label pod mynginx hello=world
- 선연형 명령(YAML)을 이용하는 방법
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
labels:
hello: world
run: mynginx
name: mynginx
spec:
containers:
- image: nginx
name: nginx
EOF
라벨 정보 삭제
다음과 같이 명령하면 label의 정보가 비워집니다.
kubectl label pod <NAME> <KEY>-
kubectl run <NAME> 명령을 수생하면 자동으로 run=<NAME> 라벨이 등록됩니다.
라벨 정보 확인
다음과 같은 방법을 통해 Pod의 라벨을 조회할 수 있습니다.
- 라벨 부분 조회 : kubectl get pod mynginx -L run
- 라벨 전체 조회 : kubectl get pod mynginx --show-labels
- 특정 라벨 필터링 조회 : kubectl get pod -l run=mynginx
라벨 부분 조회에서 [-L]은 꼭 대문자를 사용해야 합니다. [-l]은 라벨 조건 필터링에서 사용되는 키워드입니다.
nodeSelector를 이용한 노드 선택
기본적으로 Pod 생성시 쿠버네티스 마스터가 어떤 노드에 실행할지 판단하여 스케줄링 하지만 특정 노드나 노드그룹(ex. 디스크가 HDD인 노드)을 명시적으로 선택해서 실행시켜야 하는 경우 nodeSelector라는 property를 이용하여 노드를 선택할 수 있습니다.
다음은 nodeSelector를 사용하는 방법입니다.
# 마스터와 워커 노드에 다음과 같이 라벨을 등록합니다.
kubectl label node master disktype=ssd
kubectl label node worker disktype=hdd
# 노드의 라벨을 확인합니다.
kubectl get node --show-labels | grep disktype
# worker Ready <none> 23h v1.18.6+k3s1 ...disktype=hdd...
# master Ready master 24h v1.18.6+k3s1 ...disktype=ssd...
# nodeSelector property가 추가된 Pod YAML을 작성합니다.
apiVersion: v1
kind: Pod
metadata:
name: node-selector
spec:
containers:
- image: nginx
name: nginx
nodeSelector: // 선택하고자 하는 노드의 라벨을 지정합니다.
disktype: ssd
# 생성한 YAML을 통해 Pod를 생성합니다.
kubectl apply -f node-selector.yaml
# -o wide 옵션을 통해 Pod가 어느 노드에서 실행되고 있는지 확인합니다.
kubectl get pod node-selector -o wide
# node-selector 1/1 Running 0 16s 10.42.0.8 master <none> <none>
실행 명령 및 파라미터 지정
Pod 생성시 실행 명령(command), 파라미터(args)를 함께 지정할 수 있다.
echo 명령은 실행 후 종료되기 때문에 Always로 설정되어 있으면 계속 Pod가 재시작 됩니다.
apiVersion: v1
kind: Pod
metadata:
name: cmd
spec:
restartPolicy: OnFailure // Pod 재시작 정책
containers:
- image: nginx
name: nginx
commend: ["/bin/echo"] // 컨테이너의 시작 실행 명령 [Docker의 ENTRYPOINT]
args: ["hello"] // 실행 명령에 넘겨줄 파라미터 [Docker의 CMD]
restartPolicy는 Pod의 재시작 정책이며 다음과 같은 옵션이 있습니다.
- Always(Default) : Pod 종료 시 항상 재시작 시도
- Never : 재시작 시도를 하지 않음
- OnFailure : 실패 시에만 재시작 시도
환경변수 설정
env property를 사용하여 Pod의 환경변수를 전달할 수 있습니다. 또한 env property 뒤에 여러 환경변수를 한번에 설정할 수 있습니다.
apiVersion: v1
kind: Pod
metadata:
name: env
spec:
containers:
- image: nginx
name: nginx
env: // 환경변수를 설정하는 property
- name: hello // 환경변수 key 지정
value: "world!" // 환경변수 value 지정
볼륨 연결
Pod 내부 스토리지는 Pod가 사라지면 저장된 데이터도 삭제가 되기 때문에 Pod 생명주기와 상관없이 데이터를 유지하고 싶으면 볼륨을 따로 연결해야 합니다.
- host Volume: docker -v 옵션과 유사하게 호스트 서버의 디렉토리에 연결할 수 있는 설정 입니다.
apiVersion: v1
kind: Pod
metadata:
name: volume
spec:
containers:
- image: nginx
name: nginx
volumeMounts: // 컨테이너 내부에 사용될 볼륨 선언
- mountPath: /container-volume // 컨테이너 내부에 볼륨이 연결될 위치를 지정
name: my-volume // volumeMounts와 volumes를 연결하는 식별자
volumes: : // Pod에서 사용할 volume
- name: my-volume // volumeMounts와 volumes를 연결하는 식별자
hostPath: // 호스트 서버의 연결 위치
path: /home
- emptyDir volume : emptyDir volumne은 Pod 내에서 임시로 생성해서 사용하며 주로 컨테이너 끼리 파일 데이터를 주고 받을 때 자주 사용합니다.
apiVersion: v1
kind: Pod
metadata:
name: volume
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath:
name: my-volume
volumes: :
- name: my-volume
emptyDir: {} // 컨테이너가 디렉토리를 공유하는 공간으로, Pod의 생명주기를 따라가는 임시 volume
리소스 관리
쿠버네티스에서 컨테이너 실행에 필요한 리소스를 제약하는 메커니즘을 제공 recoursec property를 사용하여 제공합니다.
- requests : Pod의 최소 리소스 사용량
apiVersion: v1
kind: Pod
metadata:
name: requests
spec:
containers:
- image: nginx
name: nginx
resources:
requests: // 최소 리소스 사용량 정의
cpu: "250m" // CPU 리소스 최소 사용량 정의
memory: "500Mi" // memory 리소스 최소 사용량 정의
- limits : Pod의 최대 리소스 사용량
apiVersion: v1
kind: Pod
metadata:
name: limits
spec:
restartPolicy: Never
containers:
- image: python:3.7
name: limit
command: ["python"]
args: ["-c", "arr = []\nwhile True: arr.append(range(1000))"]
resources:
limits: // 최대 리소스 사용량 정의
cpu: "250m" // CPU 리소스 최대 사용량 정의
memory: "500Mi" // memory 리소스 최대 사용량 정의
상태 확인 (Health Check)
- livenessProbe : livenessProbe property는 컨테이너가 정상적으로 살아있는지 확인하기 위해 사용합니다
apiVersion: v1
kind: Pod
metadata:
name: lieveness
spec:
containers:
- image: nginx
name: nginx
livenessProbe: // Pod가 정상적으로 동작하고 있는지 확인하는 property
httpGet: // HTTP GET method를 이용하셔 상태 확인 작업 수행
path: /live // HTTP Path를 지정
port: 80 // HTTP Port를 지정
# liveness.yaml 실행
kubectl apply -f liveness.yaml
# watch를 사용하여 liveness 상태 확인
watch kubectl get pod leveness
# /live 호출시 404Error를 반환 받기 때문에 Pod가 정상적이지 않다고 판단하여
# Pod를 강제로 재시작(자차치유) 합니다. [RESTARTS가 계속 증가하는 이유입니다.]
# NAME READY STATUS RESTARTS AGE
# leveness 1/1 Running 5 3m16s
- readinessProbe : readinessPorbe property는 Pod 생성 직후, 트래픽을 받을 준비가 완료되었는지 확인하는 property입니다.
# readinessProbe에서 httpGet을 사용하는 방법
apiVersion: v1
kind: Pod
metadata:
name: lieveness
spec:
containers:
- image: nginx
name: nginx
readinessProbe: // Pod의 준비 완료를 확인하는 property
httpGet:
path: /ready
port: 80
# readinessProbe에서 exec을 사용하는 방법
apiVersion: v1
kind: Pod
metadata:
name: lieveness
spec:
containers:
- image: nginx
name: nginx
readinessProbe:
exec: // 명령 실행 옵션
command: // 사용자가 실행할 명령을 지정
- cat
- /tmp/ready
- startupProbe : 컨테이너 내의 애플리케이션이 시작되었는지 나타냅니다. startupProbe가 성공할 때까지 다른 probe는 비활성화 되며, 만약 startupProbe가 실패하면 쿠버네티스트는 컨테이너를 죽이고 컨테이너 재시작 정책을 처리합니다.
2개의 컨테이너를 실행하는 이유
컨테이너를 2개 이상 실행하는 경우는 여러 이유가 있지만 대표적으로 사이드카 패턴을 적용하기 위해서 입니다.
# main 컨테이너인 nginx는 본연의 임무를 수행하고 사이드 컨테이너인 curl은 loop를 돌며 5초간 대기후 localhost를 호출합니다.
apiVersion: v1
kind: Pod
metadata:
name: second
spec:
containers:
- image: nginx
name: nginx
- image curlimages/curl
name : curl
command: ["/bin/sh"]
args: ["-c", "while true; do sleep 5; curl localhost; done"]
# 2개 이상 컨테이너를 등록한 파드의 경우 -c 옵션을 통해 컨테이너를 지정해야 합니다.
kubectl logs second -c nginx
사이트가 패턴 : 오토바이의 사이드카를 비유한 것으로 메인 컨테이너가 주어진 본연의 임무를 수행하고 사이트카 컨테이너에서 메인 컨테이너를 보조하는 역할을 담달할 때 사용하는 패턴입니다.
초기화 컨테이너
기본적으로 컨테이너를 2개 이상 생성하는 Pod의 경우 실행순서를 보장하지 않습니다. 때문에 명시적으로 컨테이너가 실행되기 전에 초기화 작업(initalize)을 수행해야 하는경우 initContainers property를 사용해야합니다.
apiVersion: v1
kind: Pod
metadata:
name: init-container
spec:
restartPolicy: OnFailure
containers:
- image: busybox:1.28
name: busybox
command: ["ls"]
args: ["/tmp/moby"]
volumeMounts:
- name: workdir
mountPath: /tmp
initContainers: // 메인 컨테이너 실행에 앞에 초기화를 위해 먼저 실행되는 컨테이너
- name: git
image: alpine/git
command: ["sh"]
args:
- "-c"
- "git clone https://github.com/moby/moby.git /tmp/moby"
volumeMounts:
- name: workdir
mountPath: "/tmp"
volumes:
- name: workdir
emptyDir: {}
# Pod 생성
kubectl apply -f init-container.yaml
# init-container Pod 확인
kubectl get pod
# init-container 0/1 Completed 0 50s
initContainer property를 사용한 경우 다음과 같이 각 컨테이너의 log를 확인할 수 있습니다.
- 메인 : kubectl logs init-container
- initContainer : kubectl logs init-container -c git -f
Config 설정
쿠버네티스에서 설정값을 따로 모아 관리하는 ConfigMap을 사용해서 Pod 전달할 수 있습니다.
ConfigMap 리로스 생성
configMap은 다음과 같은 명령어를 통해서 생성할 수 있는 3가지 방법이 있습니다.
kubectl create configmap <KEY> <DATA-SOURCE>
- --frome-file 옵션을 사용하여 File을 <DATA-COURSE>로 사용할 수 있습니다.
kubectl create configmap game-config --from-file=game.properties
# game.properties
# weapon=gun
# health=3
# damage=1
- --from-literal 옵션을 사용해 사용자가 직접 설정이 가능합니다.
kubectl create configmap special-config \
--from-literal=special.power=10 \
--from-literal=special.strength=20
- ConfigMap 리소스를 YAML로 작성하여 생성할 수도 있습니다.
kubectl apply -f monster-config.yaml
# monster-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: monster-config
namespace: default
data:
monsterType: fire
monsterNum: "5"
monsterLife: "3"
위와같이 생성한 configMap을 조회하면 다음과 같이 출력됩니다.
# 생성한 configMap 조회
kubectl get cm game-config -o yaml
# game-config
apiVersion: v1
data: // 설정값
game.properties: |
weapon=gun
health=3
damage=1
kind: ConfigMap // ConfigMap 리소스
metadata:
creationTimestamp: "2021-07-25T07:16:38Z"
managedFields:
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:data:
.: {}
f:game.properties: {}
manager: kubectl
operation: Update
time: "2021-07-25T07:16:38Z"
name: game-config
namespace: default
resourceVersion: "12243"
selfLink: /api/v1/namespaces/default/configmaps/game-config
uid: 6dfc53cc-23b5-4222-bdca-4af7a3dafbcc
ConfigMap 활용
볼륨 연결
apiVersion: v1
kind: Pod
metadata:
name: game-volume
spec:
restartPolicy: OnFailure
containers:
- image: busybox:1.28
name: game-volume
command: ["/bin/sh", "-c", "cat /ect/config/game.properties"]
volumeMounts:
- name: game-volume
mountPath: /etc/config
volumes:
- name: game-volume
configMap: // configMap property를 사용하여 configMap을 사용
name: game-config // 볼륨으로 사용할configMap 이름
환경변수 - valueFrom (1개의 설정만 지정)
apiVersion: v1
kind: Pod
metadata:
name: special-env
spec:
restartPolicy: OnFailure
containers:
- image: busybox:1.28
name: special-env
command: ["printevnt"]
args: ["special_env"]
env: // 컨테이너에 환경변수 사용을 선언
- name: special_env // 환경변수 key 지정
valueFrom: // valueFrom을 사용함으로써 다른 리소스의 정보를 참조하도록 선언
configMapKeyRef: // configMap 키를 참조
name: special-config // configMap 이름을 설정
key: special.power // configMap내의 포함된 설정값 중 특정 설정값을 명시적으로 선택
환경변수 - envFrom
apiVersion: v1
kind: Pod
metadata:
name: monster-env
spec:
restartPolicy: OnFailure
containers:
- image: busybox:1.28
name: monster-env
command: ["printevnt"]
envFrom: // env 대신 evnFrom을 사용하면 ConfigMap 설정값 전체를 환경변수로 선언
- configMapRef: // configMap 전체를 사용하도록 설정
name: monster-config //사용하려는 configMap 이름을 명시적으로 지정
민감한 데이터 관리 (Secret)
Secret은 ConfigMap과 유사하지만 민감한 데이터를 저장하는데 사용할 수 있는 리소스입니다. Secret 리소스는 각 노드에서 사용될 때 디스크에 저장되지 않고 tmpfs라는 메모리 기반 파일시스템을 사용합니다. 또한 Secret 리소스 조회시 평문보다 비교적 안전한 base64로 인코딩되어 포시됩니다.
Secret 리로스 생성
- YAML을 통한 생성 (사용자가 데이터를 base64로 인코딩)
#echo -ne admin | base64
# YWRtaW4=
#echo -ne password123 | base64
# cGFzc3dvcmQxMjM=
apiVersion: v1
kind: Secret
metadata:
name: user-info
type: Qpaque // Secret 리소스 타입 설정 [Qpaque, kubernetes.io/service-account-token, kubernetes.io/tls]
data: // 저장하려는 민감한 데이터
username: YWRtaW4=
password: cGFzc3dvcmQxMjM=
- YAML을 통한 생성 (쿠버네티스가 데이터를 base64로 인코딩)
apiVersion: v1
kind: Secret
metadata:
name: user-info
type: Qpaque
sringData: // 쿠버네티스에서 base64로 인코딩 작업을 대신 수행
username: YWRtaW4=
password: cGFzc3dvcmQxMjM=
- 명령형 커맨드를 이용한 생성 [--form-env-file, --from-file, --form-literal]
kubectl create secret generic user-info-from-file \
--from-env-file=user-info.properties
# user-info.properties
# username=admin
# password=password123
--form-env-file, --from-file 차이 : --from-file은 파일 내용을 전부 설정하는 반면, --form-env-file은 내부의 key-value 값을 나누어서 저장합니다.
Secret 활용
볼륨 연결
apiVersion: v1
kind: Pod
metadata:
name: secret-volume
spec:
restartPolicy: OnFailure
containers:
- name: secret-volume
image: busybox:1.28
command: ["sh"]
args: ["-c", "ls /secret; cat /secret/username"]
volumeMounts:
- name: secret
mountPath: /secret
volumes:
- name: secret
secret:
secretName: user-info // secret 이름을 명시적으로 설정
환경변수 - env
apiVersion: v1
kind: Pod
metadata:
name: secret-env
spec:
restartPolicy: OnFailure
containers:
- name: secret-env
image: busybox:1.28
command: ["printenv"]
env:
- name: USERNAME
valueFrom:
secretKeyRef: // secret key 참조
name: user-info
key: username
- name: PASSWORD
valueFrom:
secretKeyRef: // secret key 참조
name: user-info
key: password
환경변수 - envFrom
apiVersion: v1
kind: Pod
metadata:
name: secret-envFrom
spec:
restartPolicy: OnFailure
containers:
- name: secret-envFrom
image: busybox:1.28
command: ["printenv"]
envFrom:
- secretRef: // secret 전체를 사용하도록 설정
name: user-info
메타데이터 절달
쿠버네티스에서 Pod의 메타데이터를 컨테이너에 절달할 수 있도록 Downward API를 제공합니다.
볼륨 연결
apiVersion: v1
kind: Pod
metadata:
name: downward-volume
labels:
zone: ap-north-east
cluster: cluster1
spec:
restartPolicy: OnFailure
containers:
- name: downward
image: busybox:1.28
command: ["sh", "-c"]
args: ["cat /etc/podinfo/labels"]
volumeMounts:
- name: podinfo
mountPath: /etc/podinfo
volumes:
- name: podinfo
downwardAPI: // DownwardAPI 볼륨 사용을 선언
items: // 메타데이터로 사용할 아이템 리스트를 지정
- path: "labels" // 볼륨과 연결될 컨테이너 내부 Path를 시정
fieldRef: // 참조할 필드를 선언
fieldPath: metadata.labels // Pod의 메타데이터 필드를 지정
환경병수 - env
apiVersion: v1
kind: Pod
metadata:
name: downward-env
spec:
restartPolicy: OnFailure
containers:
- name: downward
image: busybox:1.28
command: ["printenv"]
env:
- name: NODE_NAME
valueFrom:
fieldRef: // 참조할 필드를 선언
fieldPath: spec.nodeName // Pod의 메타데이터 필드를 지정
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP