Pod살펴보기(쿠버네티스 스터디 2주차)
Chap 5. Pod 살펴보기
Pod 소개
Pod는 쿠버네티스의 최소 실행 단위이다. 가상머신의 Instance나 도커의 Container와 같은 포지션에 위치해 있다.
Pod 특징
Pod는 다음과 같은 특징들을 갖는다.
1개 이상의 컨테이너 실행
Pod은 1개 이상의 컨테이너를 가질 수 있다. 보통은 1개 Pod 내에 한 개 컨테이너를 실행하지만 상황에 따라서 2개, 많게는 3개까지 컨테이너를 실행한다.
💡 istio같은 서비스 메시를 사용하면, 로그 수집 등의 목적을 위해 하나의 pod안에 사이드카 패턴으로 프록시컨테이너를 넣는 경우를 볼 수 있다.
동일 노드에 할당
Pod내에 실행되는 컨테이너들은 반드시 동일한 노드에 할당되며 동일한 생명주기를 갖는다. Pod 삭제시, Pod 내의 모든 컨테이너가 전부 같이 삭제된다.
고유의 Pod IP
각 Pod는 클러스터 내에서 접근 가능한 고유의 IP를 할당받는다. 도커 컨테이너의 경우 다른 노드에 위치한 컨테이너간의 통신을 하기 위해서 일반적으로 포트포워딩을 이용하여 노드 IP와 포워딩 포트를 이용하여 접근한다.
쿠버네티스에서는 다른 노드에 위치한 Pod라 하더라도 NAT 통신 없이도 Pod 고유의 IP를 이용하여 접근할 수 있다.
IP 공유
Pod 내에 있는 컨테이너들은 서로 IP를 공유한다. 그렇기 때문에 Pod 내의 컨테이너끼리는 localhost를 통해 서로 네트워크 접근이 가능하다.
volume 공유
마찬가지로 localhost로 통신므로, 동일한 볼륨과 연결할 수 있다.
yaml 템플릿 분석
--dry-run
과 -o yaml
옵션을 통해 Pod을 실제로 생성하지 않으면서 템플릿 파일만 만들 수 있다.
kubectl run mynginx --image nginx --dry-run=client -o yaml > mynginx.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: mynginx
name: mynginx
spec:
containers:
- image: nginx
name: mynginx
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
생성된 yaml 템플릿에서 property를 분석해보면,
- apiVersion: 리소스의 이름이 동일할 경우, 이름 충돌을 피하기 위해서 리소스의 scope를 정의한다. 프로그래밍 언어의 패키지 이름과 유사하다.
- kind: 리소스의 타입을 정의한다. 위에서는 Pod으로 지정했지만, StatefulSet, Deployment등 다양한 타입이 존재한다.
- metadata: 리소스의 메타 정보를 나타낸다. 위에서의 메타 정보는 다음과 같다(실제로는 더 많은 정보가 담길 수 있다.)
- labels: 리소스의 라벨 정보
- name: 리소스의 이름
- spec: 리소스의 스펙을 정의한다.
- containers: 1개 이상의 컨테이너를 정의한다.
- name: 컨테이너의 이름
- image: 컨테이너의 이미지 주소
- containers: 1개 이상의 컨테이너를 정의한다.
Pod을 생성하면 다음과 같은 순서로 Pod가 생성된다.
- 사용자가 kubectl을 통해 쿠버네티스 API Server로 Pod 정의를 마스터에 전달한다.
- 마스터는 yaml정의의 유효성 체크 후 해당 요청을 스케줄링하여 특정 노드에 컨테이너를 실행하도록 명령을 내린다.
- 명령을 전달받은 노드의 kubelet은 요청 사항에 맞게 컨테이너를 노드에 실행한다.
라벨링 시스템
💡 라벨링 시스템은 쿠버네티스에서 정말 중요한 메커니즘 중 하나다. 특정 리소스를 참조하기 위해서 라벨링 시스템을 이용하기도 하고, Pod에 트래픽을 전달할때도 라벨링 시스템을 활용한다. 라벨은 Key-Value 형태의 문자열이다.
라벨의 역할 정리
역할 | 설명 |
---|---|
리소스 식별 | 특정 Pod, Deployment, Service 등의 리소스를 식별하는 용도로 사용된다. |
선택 및 필터링 | kubectl get pods -l key=value 와 같이 특정 라벨이 적용된 리소스를 필터링할 수 있다. |
서비스 디스커버리 | 같은 라벨을 가진 리소스들을 묶어서 Service가 특정 Pod로 트래픽을 전달할 수 있도록 한다. |
배포 전략 관리 | Deployment, ReplicaSet 등에서 특정 라벨이 있는 리소스를 대상으로 업데이트를 수행할 수 있다. |
네트워크 정책 적용 | NetworkPolicy에서 특정 라벨이 있는 Pod만 통신할 수 있도록 정책을 적용할 수 있다. |
모니터링 및 로깅 | Prometheus, Fluentd 같은 모니터링 및 로깅 시스템에서 특정 라벨이 적용된 리소스만 모니터링할 수 있도록 설정할 수 있다. |
노드 및 리소스 스케줄링 | 특정 노드에만 배포되도록 하는 NodeSelector 또는 Affinity 설정에서 라벨을 활용할 수 있다. |
보안 및 접근 제어 | RBAC(Role-Based Access Control)에서 특정 라벨을 가진 리소스에 대한 접근 권한을 부여하는 데 활용할 수 있다. |
라벨 부여 방법
kubectl label pod mynginx hello-world
라벨 확인
kubectl get pod mynginx -L hello
라벨 필터링
특정 라벨을 가진 Pod만 필터해서 보려면 -l
옵션을 사용할 수 있다.
kubectl get pod -l hello
nodeSelector를 통한 노드 선택
라벨링 시스템을 이용하여 Pod가 특정 노드에 할당되도록 스케줄링할 수 있다.
특정 노드를 명시적으로 선택해서 실행시켜야 하는 경우, 예를 들어, SSD 디스크를 사용해야하는 컨테이너가 있다면 SSD 디스크를 사용하는 노드에 라벨을 붙이고, Pod의 nodeSelector
를 이용하여 Pod를 해당 노드에 배치할 수 있다.
💡 만약 같은 라벨이 붙여져 있는 노드가 여러개라면, 쿠버네티스가 자체적으로 그 중 최적의 노드를 선택한다.
실행 명령 및 파라미터 지정
Pod 생성 시, 실행 명령과 파라미터를 전달 가능하다. 아래는 command, args를 전달한 예시이다.
apiVersion: v1
kind: Pod
metadata:
name: cmd
spec:
containers:
- image: nginx
name: mynginx
command: ["/bin/echo"]
args: ["hello"]
restartPolicy: OnFailure
status: {}
위와 같이 hello가 echo 커맨드에 의해 출력됨을 확인할 수 있다.
환경변수 설정
마찬가지로 환경변수 또한 전달할 수 있다.
apiVersion: v1
kind: Pod
metadata:
name: env
spec:
containers:
- image: nginx
name: nginx
env:
- name: hello
value: "world!"
status: {}
위와 같이 환경변수가 등록되었음을 확인 할 수 있다.
볼륨 연결
Pod 내부 스토리지의 생명주기는 Pod과 동일하다. Pod이 사라지면 내부 데이터도 전부 날아간다. Pod의 데이터를 컨테이너 제거시에도 유지하고 싶다면, Docker와 같이 볼륨을 지정해주어야 한다.
쿠버네티스는 여러가지 볼륨 타입이 존재하고, 아래에서는 가장 기본이 되는 hostVolume을 사용한다.
apiVersion: v1
kind: Pod
metadata:
name: volume
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /container-volume
name: my-volume
volumes:
- name: my-volume
hostPath:
path: /home
status: {}
리소스 관리
쿠버네티스는 컨테이너 실행에 필요한 리소스를 제약할 수 있다. resources라는 property를 활용하여 최소, 최대 Cpu, Memory 사용량 설정이 가능하다.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
위 예제에서는 최소 메모리 64Mi, 최소 cpu 250m, 최대 메모리 126Mi, 최대 cpu 500m으로 설정했다.
💡 requests, limits 설정을 하지 않는 경우, pod는 모든 리소스를 혼자 소비할 수도 있다.
requests 설정을 하지 않고 limits 설정만 하는 경우, 쿠버네티스는 자동으로 requests를 limits와 동일하게 설정한다!!! 이는 쿠버네티스가 컨테이너의 자원할당을 보다 명확하고 안정적으로 관리하기 위해서인데, 스케줄러가 컨테이너가 실제로 필요한 최소 자원량을 명확하게 인지할 수 있게하여 노드 자원의 과도한 할당이나 자원 문제를 방지하고, 최소 예약량을 보장받게 하여 자원 관리에 혼선을 줄이고자 하기 위함이다.
그러나 추천되는 옵션은 requests만 설정하거나, limits와 함께 둘다 설정하는 방식이다.
상태 확인
컨테이너가 정상적으로 살아있는지 확인하기 위해 livenessProbe
property를 제공한다. 이를 이용하여 Pod가 정상적으로 동작하는지 확인하며, 자가치유를 위한 판단 기준으로 활용한다.
apiVersion: v1
kind: Pod
metadata:
name: liveness
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
livenessProbe:
httpGet:
path: /live
port: 80
watch kubectl get pod liveness
위 명령어를 통해 각 pod의 헬스체킹을 할 수 있다.
live파일을 생성해주기 전까지는 계속해서 Crash 가 발생할 것이다.
readinessProbe
는 Pod 생성직후 해당 파드가 트래픽을 받을 준비가 되었는지 확인하는 property이다.
apiVersion: v1
kind: Pod
metadata:
name: readiness
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
readinessProbe:
httpGet:
path: /ready
port: 80
해당 Pod도 마찬가지로 ready파일을 생성해주기 전까지는 게속해서 Crash가 발생한다.
readinessProbe
는 HTTP 통신뿐만 아니라, 명령을 통해서도 정상 여부를 확인할 수 있다.
readinessProbe:
exec:
command:
- cat
- /tmp/ready
초기화 컨테이너
컨테이너 여러개를 실행하는 경우, k8s는 기본적으로 실행순서를 보장하지 않는다. 명시적으로 메인 컨테이너가 실행되기 전에 초기화 작업이 필요한 경우, initContainers property를 사용하여 초기화 작업을 수행할 수 있다.
spec:
initContainers:
- name: git
image: alpine/git
command: ["sh"]
args:
- "-c"
- "git clone https://github.com/moby/moby.git /tmp/moby"
volumeMounts:
- name: workdir
mountPah: "/tmp"
initContainers
는 메인 컨테이너 실행에 앞서 초기화를 먼저 실행하는 컨테이너를 정의한다.
Config 설정
weapon=gun
health=3
potion=5
위와 같은 파일을 먼저 만들고
kubectl create configmap game-config --from-file=game.properties
로 ConfigMap을 생성할 수 있다.
만약 파일이 없다면, --from-file
대신 --from-literal
을 사용하여 직접 설정값을 지정할 수도 있다.
물론 yaml파일을 만들어서 apply 하는 것도 가능하다.
ConfigMap 활용: 볼륨 마운트
volumes:
- name: game-volume
configMap:
name: game-config
위처럼 configMap을 불러와서 volume mount를 할 수 있다.
이러면 컨테이너 내부의 특정 디렉터리에 파일형태로 configmap이 들어간다.
ConfigMap 활용: 환경변수
env:
- name: special_env
valueFrom:
configMapKeyRef:
name: special-config
key: special.power
configMapKeyRef
를 활용하여 properties 내용을 env로 설정할 수 있다.
모든 값을 전부 env로 설정하려면, configMapKeyRef
대신 configMapRef
를 사용하면 된다.
민감 데이터 관리
ConfigMap에서 보안성을 강화한 버전이 Secret 리소스이다. Secret 리소스는 ConfigMap의 각 항목을 base64로 인코딩하여 저장한다. (디코딩이 가능하기 때문에 완벽한 보안성은 갖추지 못한다.)
Secret에 관한 내용은 상당부분 ConfigMap과 겹치므로 넘어가도록 하겠다.
메타데이터 전달
Kubernetes에서 Pod의 메타데이터(이름, 네임스페이스, 노드 정보 등)를 컨테이너에 전달하는 방법에는 여러 가지가 있다. 그중 Download API를 활용하여 전달하는 방법은 보통 컨테이너 내부에서 Kubernetes API를 호출하여 Pod의 메타데이터를 가져오는 방식이다.
이때, 컨테이너가 직접 Kubernetes API를 호출하려면:
Kubernetes API 서버의 엔드포인트를 호출해야 함. 서비스 어카운트(ServiceAccount) 및 RBAC 권한이 필요함. Pod 내부에서 실행되는 애플리케이션이 이를 요청하는 코드를 포함해야 함.
아래 방법으로 이를 구현할 수 있다.
1. 볼륨 연결(볼륨 마운트)
apiVersion: v1
kind: Pod
metadata:
name: metadata-pod
spec:
containers:
- name: my-container
image: busybox
command: [ "sh", "-c", "cat /etc/podinfo/name && sleep 3600" ]
volumeMounts:
- name: podinfo
mountPath: /etc/podinfo
volumes:
- name: podinfo
downwardAPI:
items:
- path: "name"
fieldRef:
fieldPath: metadata.name
2. 환경변수
apiVersion: v1
kind: Pod
metadata:
name: metadata-pod
spec:
containers:
- name: my-container
image: busybox
command: [ "sh", "-c", "echo My Pod Name: $POD_NAME && sleep 3600" ]
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace