Certified Kubernetes Administrator (CKA) with Practice Tests (강의 링크, 레퍼런스 노트)
- 평소 강의 할인도 많이 하고, 연습문제도 풀어볼 수 있으니 실제 강의 수강을 추천
- 아래는 강의 내용 번역 및 정리본 (문제 시 댓글로 알려주세요)
Manual Scheduling
스케줄링 작동 방법
- pod를 생성할 때에 nodeName 필요
- 사용자가 yaml 파일에 해당 필드 작성하지 않아도 자동으로 생성됨
- nodeName의 값이 없는 pod들이 스케줄링의 대상(후보)
- 스케줄링 알고리즘을 통해 어떤 노드에 스케줄링할지 결정
- pod와 node를 연결
스케줄러가 없다면
- 직접 nodeName에 노드의 이름을 값으로 지정 (pod yaml 파일)
- pod 생성 시에만 nodeName에 값을 작성할 수 있음
- 생성된 pod 삭제 후 nodeName에 값을 지정한 파일로 재생성하는 방법도 있음
kubectl replace --force -f [파일명].yaml
- Binding 객체 생성
- pod 생성 이후 node에 할당하고 싶을 때 사용
- e.g.
curl --header "Content-Type:application/json" --request POST --data '{"apiVersion": "v1", "kind": "Biding", ...} http://$SERVER/api/v1/namespaces/default/pods/$PODNAME/binding/
- 스케줄러 있는지 여부 확인
kubectl get pods -n kube-system
Pod-bind-definition.yaml 예시
- apiVersion: v1
- kind: Binding
- metadata:
- target:
- apiVersion: v1
- kind: Node
- name: node02 [실제 노드명]
Labels and Selectors
- 그룹화 및 필터링(분류)을 도와주는 방법
- 타입 (e.g. pod, replicaset), 어플리케이션, 기능 (e.g. front-end) 등을 기준으로 분류 가능
Labels
- yaml 파일의 metadata 하위에 위치
- key, value 형태로 자유롭게 레이블 추가 가능
- 레이블 내 키를 기준으로 조회하는 명령어
kubectl get pods --selector app=App1
Selectors
- yaml 파일의 spec 하위에 위치
- selector: matchLabels와 같은 형식
- ReplicaSet에서 template 하위의 내용은 포함하는 pod의 정보
- metadata 하위의 labels가 ReplicaSet의 레이블임에 주의
- 참고로, template의 경우 매칭하려는 pod의 정보를 상세히 기입할 필요가 있을 때 사용
Annotations
- yaml 파일의 metadata 하위에 작성
- 버전, 빌드 정보, 연락처 등의 추가 정보를 작성하는 용도
명령어
- 필터링한 pod 결과 조회 (개수)
kubectl get pods --selector env=dev --no-headers | wc -l
- wordcount 옵션은 헤더까지 포함하기 때문에 --no-headers 사용
- -l은 line(행) 개수를 세기 위한 옵션
- 필터링한 모든 객체 결과 조회
kubectl get all --selector env=prod --no-headers
- 여러 개의 조회조건 사용
kubectl get all --selector env=prod,bu=finance,tier=frontend
- 쉼표로 연결
Taints and Tolerations
- 어떤 pod가 노드에 스케줄링될 수 있는지를 제한
- e.g. 특정 노드에는 특정 응용 프로그램과 관련된 pod만 배포되도록
- node에 taint 옵션을 지정, pod에 tolerance 옵션을 지정
- tolerant한 pod만 해당 taint를 가진 node에 위치됨
- pod에게 특정 node에 배정되는 것을 요구하는 것이 아니라, node로 하여금 특정 toleration을 가진 pod만 받아들이도록 지정하는 것임
- 마스터 노드의 경우 사용자가 만든 pod가 배포되지 않는 것이 유리
kubectl describe node kubemaster | grep Taint
- taint-effect가 NoSchedule로 지정됨
Taints
- 노드에 지정
- taint 지정 명령어
kubectl taint nodes [노드명] [key=value:taint-effect]
- e.g.
kubectl taint nodes node1 app=blue:NoSchedule
- untaint 명령어
kubectl taint nodes [노드명] [key=value:taint-effect]-
- 맨 마지막에 - 추가
- taint-effect
- NoSchedule
- PreferNoSchedule
- pod가 node에 스케줄되지 않을 것이나, 보장되지는 않음
- NoExecute
- 새로운 pod는 node에 스케줄되지 않음
- 만약 이미 배정된 pod 중 intolerant pod가 있다면 해당 pod는 퇴출됨(evict)
Tolerations
- pod에 지정
- yaml file에 spec 하위에 작성됨
- 위의 예시와 매칭되는 tolerations 작성법
- 값은 모두 "" 안에 작성되어야 하며, Equal은 = 연산자를 의미
- tolerations:
- -key: "app"
- operator: "Equal"
- value: "blue"
- effect: "NoSchedule"
Node Selectors
- 특정 pod가 특정 node에 위치하도록 지정하는 간편한 방법
- pod yaml 파일의 spec 하위에 nodeSelector 지정
- pod 생성 이전에 node에 관련 key, value 지정해줘야 함
kubectl label nodes [노드명] [label-key=label-value]
- e.g.
kubectl label nodes node-1 size=Large
- 한계
- 복잡한 요구사항을 수행하기에는 적절하지 않음
- e.g. Large OR Medium / Not Small
Node Affinity
- 특정 pod가 특정 node에 위치하도록 지정하는 방법
- node selector의 한계를 극복하였으나 다소 복잡
- pod yaml 파일의 spec 하위에 위치
- 만약 deployment와 같은 객체의 yaml 파일을 수정해야 한다면, template 하위의 spec에 작성해줘야 함 (pod 정보이므로)
- affinity:
- nodeAffinity:
- requiredDuringSchedulingIgnoredDuringExecution:
- nodeSelectorTerms:
- -matchExpressions:
- -key: size
- operator: In
- values: list 형태로 작성
- operator의 경우 NotIn, Exists 등 존재
- Exists의 경우 key의 존재여부만 필요로 하기 때문에 values 필요없음
Node Affinity Types
- requiredDuringSchedulingIgnoredDuringExecution
- during scheduling은 pod가 존재하지 않고 처음으로 생성되는 시기를 의미
- 매칭되는 레이블을 가진 노드가 존재해야 pod가 스케줄링됨
- 노드의 레이블이 변경되어도 스케줄링된 pod는 유지됨 (변경사항 무시)
- preferredDuringSchedulingIgnoredDuringExecution
- 매칭되는 레이블을 가진 노드가 존재하지 않아도 pod가 스케줄링됨 (있으면 해당 노드에 스케줄링)
- requiredDuringSchedulingRequiredDuringExecution
- 추가 예정
- 노드의 레이블이 변경된다면 스케줄링된 pod 중 조건에 맞지 않는 pod는 해당 노드에서 퇴출됨(evict)
Node Affinity vs. Taints and Tolerations
- 목표: 특정 pod와 특정 node를 매칭시키기
- 5개의 node, pod가 존재
- 그 중 각각 세 개에 대해서 green, red, blue로 지정되었다고 가정
- taints and tolerations
- 만약 taint되지 않은 node들이 존재한다면, toleration 옵션이 추가된 pod가 taint되지 않은 node에 위치할 수 있음
- e.g. red pod가 untainted node에 위치
- node affinity
- affinity 옵션이 적용되지 않은 pod가 추가적으로 특정 node에 위치될 수 있음
- e.g. 아무런 옵션이 없는 pod가 blue node에 위치
- 두 개를 함께 사용해서 특정 node에 특정 pod를 지정할 수 있음
Resource Requirements and Limits
- kube-scheduler는 노드의 자원(e.g. CPU, 메모리)을 고려하여 pod를 배치
- 자원 요청 및 자원 제한은 pod 내 container마다 지정 가능
자원 요청 (resource request)
- 컨테이너는 각각의 자원 요청을 가질 수 있음
- pod yaml 파일의 spec: containers 하위에 다음과 같이 작성
- CPU
- 1m (100m = 0.1) 부터 사용 가능
- 1 CPU = 1 AWS vCPU = 1 GCP Core = 1 Azure Core = 1 Hyperthread
- 메모리
- 1G (Gigabyte) = 1,000,000,000 bytes
- 1M (Megabyte) = 1,000,000 bytes
- 1K (Kilobyte) = 1,000 bytes
- 1Gi (Gibibyte) = 1,073,741,824 bytes
- 1 Mi (Mebibyte) = 1,048,576 bytes
- 1 Ki (Kibibyte) = 1,024 bytes
자원 제한 (resource limit)
- pod가 node의 자원을 모두 사용하지 않도록 제한을 가할 수 있음
- pod yaml 파일의 spec: containers 하위에 다음과 같이 작성
- 메모리의 경우 제한보다 더 많은 메모리를 사용할 수 있음
- 지속적으로 메모리를 초과할 경우 OOM (Out Of Memory) 에러 발생
기본 동작방식
- 요청과 제한 모두 없는 경우
- 하나의 pod가 모든 자원을 다 사용해 다른 pod가 자원을 사용하지 못할 수 있음
- 요청은 없지만 제한은 있는 경우
- requests = limits
- 각각의 pod가 제한만큼의 자원을 사용할 수 있음
- 요청과 제한이 모두 있는 경우
- 하나의 pod가 예상했던 것보다 많은 자원을 사용하지 않을 때, 해당 자원을 다른 pod가 사용 가능하도록 하는 것이 유리하나 이것이 불가능
- 요청만 있고 제한이 없는 경우
- 이용 가능한 자원이 있을 때 다른 pod가 해당 자원을 사용할 수 있음
- 동시에, 각각 필요한 자원은 보장받을 수 있음
- 가장 이상적인 시나리오
- 메모리의 경우, 쓰로틀링이 불가능하기 때문에 요구되는 자원을 다시금 사용하고 싶다면 해당 메모리를 더 사용하고 있던 pod를 멈춘 후 해당 메모리 회수해야 함
Limit Range (제한범위)
- 컨테이너들로 하여금 기본 자원값들을 가질 수 있게 함
- LimitRange가 생성된 다음 생성되는 pod/container에 대해서만 적용됨
- yaml file 예시
- apiVersion: v1
- kind: LimitRange
- metadata:
- name: cpu-resource-constraint
- spec:
- limits:
- -default: limit을 의미
- defaultRequest: request를 의미
- max: limit을 의미
- min: request를 의미
- type: Container
Resource Quota (자원 할당)
- namespace 별로 생성할 수 있는 자원 할당범위
- yaml file 예시
- apiVersion: v1
- kind: ResourceQuota
- metadata:
- spec:
- hard:
- requests.cpu: 4
- requests.memory: 4Gi
- limits.cpu: 10
- limits.memory: 10Gi
DaemonSets
- ReplicaSet과 유사하게 pod의 여러 개의 인스턴스를 배포하도록 도움
- ReplicaSet과 다른 점은, 노드마다 하나의 pod가 생성된다는 점임
- 클러스터의 모든 노드에 pod의 복사본 하나가 존재하는 것을 보장
- 모니터링, 로깅, 네트워킹 등에 유리
- 기본 스케줄러와 node affinity를 활용
YAML
- apiVersion: apps/v1
- kind: DaemonSet
- metadata:
- spec:
- selector: DeamonSet이 연결하고자 하는 pod 정보를 담음
- template: pod에 대한 구체적인 정보를 담음
- metadata:
- spec:
- containers:
- -name: [컨테이너명]
- image: [이미지명]
명령어
kubectl create -f [파일명].yaml
- 쉽게 yaml 파일 만드는 법: deployment 활용하기
kubectl create deployment [이름] --image=[이미지명] --dry-run=client -o yaml > [파일명].yaml
- 파일에디터로 replicas, strategy, status 필드 삭제
- 파일에디터로 Deployment를 DaemonSet으로 변경
kubectl get daemonsets(ds)
kubectl describe daemonsets [이름]
Static Pods
- master node도 없고 클러스터 구성이 없을 때는 kube-apiserver가 없기 때문에 worker node의 kubelet이 직접 pod yaml 파일을 읽도록 해야 함
- 일반적으로 /etc/kubetnetes/manifests에 pod yaml 파일 위치
- kubelet.service의 --pod-manifest-path= 에 경로 지정
- kubelet.service의 --config=kubeconfig.yaml 파일에서 staticPodPath: 로 지정도 가능
- 경로 확인은 /var/lib/kubelet/config.yaml에서 확인할 수 있음
- replicasets, deployment 등의 객체는 이런 방식으로 만들 수 없음
- kubelet에 의해 만들어진 pod = Static Pods
명령어
docker ps
- kube-apiserver가 없기 때문에 kubectl 명령어 사용 불가
kubectl get pods
- master node가 있어서 kube-apiserver가 있는 경우 해당 명령어 사용 가능
- 하지만 kubelet에 의해 생성된 pod의 경우 오직 yaml 파일을 수정하거나 삭제하는 방식만 가능
- kubectl edit, delete 명령어 사용 불가
- pod 이름 뒤에 -controlplane이 붙어있거나, pod 파일 안에 ownerReferences의 kind: Node, name: controlplane인 경우 static pod라고 볼 수 있음
- Static Pod 생성
kubectl run [이름] --image=[이미지명] --dry-run=client -o yaml --command -- [명령어: e.g. sleep 1000] > [파일명].yaml
- command 옵션은 맨 마지막에 위치해야 함
cp [파일명].yaml [staticPodPath 경로] 로 이동하면 static pod가 생성됨
- 수정 시에는 해당 파일로 들어가서 직접 수정하면 됨 (별도 명령어 필요 없음)
- 다른 노드에 생성된 Static Pod 삭제
kubectl get nodes -o wide
ssh [internal-IP]
cat /var/lib/kubelet/config.yaml
rm [pod 파일명].yaml && exit
- controlplane으로 돌아가 pod 상태 확인
kubectl get pods -A --watch
Static Pods 사용할 때
- 여러 개의 controlplane (master node) 있을 때
- 바이너리 파일을 다운로드 받을 필요도 없고, 서비스가 충돌할 염려도 없음
- e.g. apiserver.yaml, etcd.yaml, controller-manager.yaml
Static Pods vs. DaemonSets
- Static Pods
- kubelet에 의해 생성
- Control Plane 구성요소들을 static pod로 배포
- DaemonSets
- kube-apiserver에 의해 생성 (DaemonSet Controller)
- 모니터링, 로깅 에이전트들을 노드에 배포
- 둘 다 kube-scheduler에 의해 무시됨
Multiple Schedulers
- 여러 개의 스케줄러를 동시에 사용 가능
- scheduler configuration yaml file
- apiVersion: kubescheduler.config.k8s.io/v1
- kind: KubeSchedulerConfiguration
- profiles:
- -schedulerName: my-scheduler
스케줄러 배포 및 사용
- 추가적인 스케줄러 배포하는 방법
wget https://../kube-scheduler로 바이너리 파일 다운로드
- my-scheduler.service에서
ExecStart=/usr/local/bin/kube-scheduler --config=/etc/kubernetes/config/[yaml 파일명].yaml
- 추가적인 스케줄러를 Pod로 배포하는 방법
- pod yaml 파일에 spec: containers: 하위에 다음과 같이 작성 가능
- -command:
- kube-scheduler
- --address=[주소]
- --kubeconfig=/etc/kubernetes/scheduler.conf
- --config=[yaml 파일위치]
- scheduler configuration yaml 파일에 다음과 같은 내용 추가
- 동일한 스케줄러의 복사본이 여러 개의 master node에서 필요할 경우, 한 번에 하나만 활성화될 수 있음
- leaderElection:
- leaderElect: true
- resourceNamespace: kube-system
- resourceName: lock-object-my-scheduler
- pod에서 다른 스케줄러를 사용하는 방법
- yaml 파일의 spec: 하위에 다음과 같이 작성
스케줄러 사용여부 확인
kubectl get events -o wide
kubectl logs [스케줄러명] --name-space=[namespace명]
스케줄러 프로파일 설정
- 스케줄링을 기다리는 pod들은 Scheduling Queue에 위치
- 이 단계에서 정의된 우선순위에 따라 스케줄링됨
- PriorityClass (yaml file)
- apiVersion: scheduling.k8s.io/v1
- kind: PriorityClass
- metadata:
- value: 1000000
- globalDefault: false
- description: "[설명]"
- Pod (yaml file)
- spec:
- priorityClassName: high-priority
- 사용할 수 있는 노드들을 필터링 (Filtering)
- 점수 매기기 (Scoring)
- 남는 공간을 기반으로 어떤 노드가 더 유리한지 점수를 매김
- 연결 (Binding)
스케줄링 플러그인
- 각 단계마다 사용하는 플러그인이 다름
- 스케줄링 큐: PrioritySort
- 필터링: NodeResourceFit, NodeName, NodeUnschedulable
- 점수 매기기: NodeResourceFit, ImageLocality
- 연결: DefaultBinder
- Extension Points
- 플러그인이 붙을 수 있는 곳
- 이를 통해 플러그인을 새로 정의하고 사용할 수도 있음
- e.g. queueSort, preFilter, filter, postFilter, preScore, score, reserve, permit, preBind, bind, postBind, ...
스케줄러 프로파일
- 1.18 버전 이후로 하나의 yaml 파일에 여러 개의 프로파일을 관리할 수 있게 됨
- apiVersion: kubescheduler.config.k8s.io/v1
- kind: KubeSchedulerConfiguration
- profiles:
- -schedulerName: [스케줄러명]
- plugins:
- score: [Extension Points] (e.g. preScore, ..)
- disabled:
- -name: TaintToleration (e.g. '*'는 전체를 의미)
- enabled:
- -name: MyCustomPluginA
- -name: MyCustomPluginB
- -schedulerName: ...
참고사항
POD 수정하기 (edit)
- 존재하고 있는 pod의 수정할 수 있는 spec은 아래와 같음
- containers.image
- initContainers.image
- activeDeadlineSeconds
- tolerations
- 서비스 계정, 자원 제한, 환경 변수 등은 수정 불가
- 해당 부분들을 수정하고 싶다면 두 가지 방법이 있음
- 임시 파일 이용
kubectl edit pod [pod명] : 임시 파일이 저장됨
kubectl delete pod [pod명] : 기존 pod 삭제
kubectl create -f [임시파일명].yaml : 임시 파일로 새로운 pod 생성
- 혹은 delete + create 말고 replace 사용할 수 있음
kubectl replace --force -f [임시파일명].yaml
- yaml 파일 이용
kubectl get pod [pod명] -o yaml > [파일명].yaml : 새로운 파일로 저장
vi [파일명].yaml
kubectl delete pod [pod명]
kubectl create -f [파일명].yaml
Deployment 수정하기 (edit)
- Deployment에서 Pod 템플릿의 필드 및 속성값을 쉽게 수정할 수 있음
- Deployment에서 템플릿 수정 시 pod가 자동으로 삭제되고 변화를 반영한 새로운 pod가 생성됨
kubectl edit deployment [deployment명]