티스토리 뷰
Manual Scheduling
how to work?
스케쥴러는 백엔드에서 어떻게 작동할까?
예시로 다음의 간단한 yaml 파일을 보자
apiVersion: v1
kind: Pod
metatdata:
name: nginx
labels:
name: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 8080
nodeName: # 기본적으로 설정되지 않은 필드
- 일반적으로는
nodeName
필드를 쿠버네티스가 자동으로 추가한다. - 스케쥴러는 모든 pods를 보면서
nodeName
필드가 설정되어있지 않은 pod를 탐색한다. 이 pod들이 스케쥴링 예약을 해야하는 pod들이다. - 그런 다음 스케쥴링 알고리즘을 실행하여 POD에 적합한 노드를 식별한다.
- 식별되면
nodeName
을 해당 노드의 이름으로 설정하여 노드에서 POD를 스케쥴에 예약한다.
스케쥴러가 없다면?
pod는 계속해서
pending
상태가 된다.스케쥴러 없이 매뉴얼하게 직접 파드를 노드에 할당할 수 있다.
- 가장 쉬운 방법은 해당 pod의 매니페스트 파일에서 상기와 같이
nodeName
필드에서 노드를 직접 지정해주는 것이다.
- 가장 쉬운 방법은 해당 pod의 매니페스트 파일에서 상기와 같이
생성할 때에만 노드 네임을 직접 지정할 수 있다.
pod가 이미 생성되어있다면?
쿠버네티스는 이미 pod가 생성되었다면 pod의
nodeName
property를 수정하는것을 허용하지 않는다.따라서 다른 방법은 binding 객체를 생성하고 request를 보내서 이미 존재하는 pod에 노드를 assign 하는 것이다.
apiVersion: v1 kind: Binding metadata: name: nginx target: apiVersion: v1 kind: Node name: # target Node name
이때 yaml file을 이에 상응하는 Json 포맷으로 변경해야한다.
이는 스케쥴러가 하는 일을 매뉴얼하게 따라하는 것과 비슷하다.
스케쥴러 상태 확인
kubectl get pods --namespace kube-system
Labels and Selector
labels와 selector는 함께 그룹화하는 표준 방법이다.
어떻게 사용될까?
우리는 쿠버네티스에서 pods, service, deployments, 등 다양한 다른 타입의 객체(리소스)를 생성할 수 있다. 시간이 지나면서 클러스터에는 아주 많은 다양한 객체가 생성되어 있을 것이다. 효율적으로 원하는 객체를 선택하기 위해서는 여러 카테고리에 따라 그룹화를 한다.
이때 labels and selector를 사용하여 각기 다른 그룹화되어 있는 객체를 필요에 따라서 구분지어 찾을 수 있다.
어떻게 사용할까?
- 매니페스트 파일에서 key:value 쌍으로 값을 지정해주면 된다.
- 커맨드로 간단하게 어떤 selector를 찾고자한다면 다음과 같이 할 수 있다.
kubectl get pods --selector app=App1
어떻게 작동할까?
- labels와 selector는 내부적으로 다른 객체를 함께 연결한다.
주의
metadata
field의 label과template
하위 field의 label을 혼동하지 말자.- metadata - label: 매니페스트 구성 즉, kind 요소 자체의 label
- template - label: pod의 label
selector
는 pod의label
과 동일하게 연결시켜주자.- 이는
service
를pod
와 연결할때도 사용됨.
- 이는
Annotation
labels and selector는 그룹화하는데 사용되지만 annotation은 그 외 세부사항을 기록하는데 사용된다.
주로 사용하는 command
- kubectl get pods —selector key=value
- kubectl get all —selector key=value
- kubectl get all —selector key=value,key2=value2,key3=value3
Taints And Tolerations
- 사람은 nods, 벌레는 pods
- tains and toleration은 노드에서 스케쥴링 될 수 있는 pod를 제한할 때 사용한다.
- node와 pod가 어떠한 오염이나 제한이 있지 않은 경우 밸런싱되어 pod는 node에 스케쥴링되어 위치한다.
- 이때 하나의 node가 taint=blue라는 오염을 주었을 때, pod는 이 오염된 노드에 위치하고 싶지 않다.
- 이 때 하나의 pod에 blue라는 tolerance를 주게 되면 이 pod는 taint=bule node와의 접근을 할 수 있게 된다.
- 이것이 pod가 스케쥴링 되는 방법이다.
how to use
kubectl taint nodes node-name key=value:taint-effect
taint-effect 종류: NoSchedule, PreferNoSchedule, NoExecute
kubectl taint nodes node1 app=blue:NoSchedule
- NoSchedule: taint가 허용되지 않는 pod는 Scheduling 하지 않는다. 이미 실행중인 POD는 관여하지 않는다.
- PreferNoSchedule: taint가 허용되지 않는 pod는 scheduling 하지 않으려고 한다. 하지만 cluster 리소스가 부족한 상황 등에 대해서는 toleration을 만족하지 않아도 node에 scheduling 된다.
- NoExecute: taint가 허용되지 않는 pod는 Scheduling 하지 않는다. 이미 실행중인 POD도 퇴출시킨다.
in yaml file - 위의 예시를 yaml file에 적용시켜보자
spec:
containers:
- name: nginx-container
image: nginx
tolerations:
- key: "app"
operator: "Equal"
value: "blue"
effect: "NoSchedule"
- 모든 tolerations와 관련된 value는 큰따옴표로 묶어주어야 함에 주의하자.
- pod가 새로운 toleration으로 생성되거나 업데이트되면 노드에서 스케쥴되지 않는다.
taint 확인하기
kubectl describe node [nodename] | grep Taint
Node Selector
node selector는 node selector에 설정된 label을 가지고 있는 node 중에 하나를 선택하여 스케쥴링 할 수 있도록 하는 기능.
- pod의 yaml file에서 node selector를 사용하여 key=value로 값을 저장할 수 있다. 그런데 pod은 키값 쌍을 가진 노드를 어떻게 구분할까?
- 노드에도 해당 키값에 해당하는 label을 지정해주어야 한다. 방법은 다음과 같다.
kubectl label nodes <node-name> <label-key>=<label-value>
하지만 node selector는 다음과 같은 한계를 가지고 있다.
label = small, medium, large 값을 가진 노드가 있다고 가정하자.
- medium, large 값을 가진 노드만 선택하고 싶으면 어떡할까?
- 같은 의미로, small이 아닌 노드만 선택하고 싶으면 어떡할까?
이러한 한계를 보완하기 위해 나온 것이 node affinity
기능이다.
Node Affinity
node affinity의 주된 기능은 특정 node에 pod를 확실하게 호스팅하기 위한 기능이다.
사용 방법은 다음과 같다.
# kind: Pod
spec:
containers:
- name:
image:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: size
operator: In
values:
- Large
- Medium
requiredDuringSchedulingIgnoredDuringExecution
이 용어가 되게 생소하게 보일 수 있다. 이는 공식문서에서 찾을 수 있었다.
- requiredDuringSchedulingIgnoredDuringExecution: 규칙이 만족되지 않으면 스케줄러가 파드를 스케줄링할 수 없다. 이 기능은
nodeSelector
와 유사하지만, 좀 더 표현적인 문법을 제공한다. - preferredDuringSchedulingIgnoredDuringExecution: 스케줄러는 조건을 만족하는 노드를 찾으려고 노력한다. 해당되는 노드가 없더라도, 스케줄러는 여전히 파드를 스케줄링한다.
- 참고) IgnoredDuringExecution: 쿠버네티스가 파드를 스케쥴링 한 뒤에 노드 레이블이 변경되어도 파드는 계속 해당 노드에서 실행됨을 의미.
taint and toleration and node affinity
taint and toleration으로 물리적으로 완전히 노드를 분리 할 수는 없다. 예를 들어 blue, red, green으로 taint한 노드가 세개 있고, taint가 없는 노드가 두개 있고 pod 또한 각각의 blue, red, green의 toleration을 추가한 pod도 있다고 가정하자.
이때 blue toleration pod는 blue taint node에만 스케줄링 된다고 보장할 수 있는가? 그렇지 않다. taint가 존재하지 않는 노드에도 스케줄링 될 수 있다.
두번째 상황으로, blue, red, green의 node affinity를 추가한 노드가 있으며 각각의 pod에도 node affinity를 사용하여 node가 스케줄링되도록 적용한 상황이다. 이 상황에서의 문제는 어떠한 node affinity도 추가하지 않은 pod가 blue or red or green label의 node에 스케줄링 될 수 있다는 문제가 있다.
따라서 taint and toleration과 node affinity를 조합해서 사용해야 완전한 물리적 노드 분리가 가능해진다.
Resource and Limits
Resource
각 노드마다 할당된 자원이 있다. CPU, Memory, disk, etc…
그리고 쿠버네티스 스케줄러에 의해서 각 노드의 자원 상황에 맞게 pod가 할당된다. 그런데 어떠한 노드도 추가적인 pod를 감당할 자원이 부족한 상황이 발생하면? 쿠버네티스는 해당 pod를 스케줄링하는 것을 보류한다. 그리고 해당 pod는
pending
status가 된다.쿠버네티스는 디폴트로 pod에 0.5CPU, 256 Mi memory를 할당한다. 이것이 node에 pod를 할당할 때 컨테이너에 의해서 요청된 가장 최소의 cpu 또는 memory의 양이다. 이 숫자로 pod를 할당할 충분한 자원의 여유가 있는지를 판단한다. 그리고 이 숫자는 yaml file에서 튜닝이 가능하다.
resources:
requests:
memory: "1Gi"
cpu: 1
Limit
- 한정된 자원을 설정할 수 있다.
limits: # requests와 같은 들여쓰기 수준
memory: "2Gi"
cpu: 2
초과하려고 하면?
만약 제한된 자원을 실행중에 초과하려고 하면 어떻게 할까?
- CPU의 경우 쿠버네티스는 CPU가 지정된 제한을 초과하지 않도록 조절한다.
- 컨테이너는 제한된 CPU보다 많은 자원을 사용할 수 없기 때문에
- memory의 경우는 다르다. 지정된 제한을 초과할 수 있다.
- 컨테이너가 지정된 메모리보다 더 많은 메모리 자원을 사용할 수 있기 때문에
- 하지만 pod가 지속적으로 제한된 자원보다 많은 메모리를 사용하려고 하면 pod는 종료된다.
참고) 디폴트로 정해진 자원을 선택하기 위해서는 해당 네임스페이스에서 LimitRange
라는 리소스를 사전에 정의해놓아야 한다.
apiVersion: v1
kind: LimitRange
metadata:
name: mem-limit-range
spec:
limits:
- default:
memory: 512Mi
defaultRequest:
memory: 256Mi
type: Container
---
apiVersion: v1
kind: LimitRange
metadata:
name: cpu-limit-range
spec:
limits:
- default:
cpu: 1
defaultRequest:
cpu: 0.5
type: Container
Daemonset
- daemonset은 여러 pod를 배포하는데 도움을 주기 때문에 replica set와 비슷하다.
- 하지만 daemonset은 각 pods가 배포되어 있는 node 하나당 하나만 복사한다.
- 즉, daemonset은 클러스터의 모든 node에 항상 하나의 pod 복사본이 존재하도록 한다.
- daemonset은 solution, log monitoring에 아주 적합하다.
- replicaset과 kind를 제외하고는 아주 똑같은 양식으로 생성할 수 있다.
- pod template의 label을 통해 선택할 수 있다.
- node가 새로 생성되거나 삭제될 때 daemonset의 pod 역시 생성 또는 삭제된다.
- taint and toleration 과 node affinity가 daemonset에도 적용된다.
Static Pods
master node의 kube api-server와 worker node의 kubelet이 통신을 한다는 것을 알고 있다. 그렇다면 master node의 모든 리소스가 없는 상태라면 worker node는 스스로 작동을 할 수 없을까? kubelet
만 있다면 할 수 있다. 이것이 static pods
다.
- 하지만 manifest file과 통신할 api server도 없는데 kubelet 혼자서 어떻게 생성할까?
- 서버의 디렉토리(
/etc/kubernetes/manifests
)에서 pod 정의 파일을 읽도록 kubet을 구성할 수 있다.
- 서버의 디렉토리(
- kubelet은 주기적으로 이 디렉토리에 있는 파일을 읽으며 호스트에 pod를 생성한다.
- 생성 뿐만 아니라 활성 상태로 만든다. pod 충돌이 발생하면 kubelet은 충돌한 pod을 다시 시작할 수도 있다.
- 이 디렉토리의 파일에 변경사항이 발생하면 kubelet은 이 변경사항을 적용하여 pod를 재생성한다.
- 이 디렉토리의 파일이 삭제되면 pod도 자동으로 삭제된다.
- 오직 pod만 생성이 가능하다는 것에 주의하자.
어디서 쓰는데?
- Master Node에서 Control plane 역할을 하는 pod를 static pod를 이용해 생성할 수 있다.
'Infrastructure > Kubernetes' 카테고리의 다른 글
[CKA] Security (0) | 2022.08.03 |
---|---|
[CKA] Cluster Maintenance (0) | 2022.07.30 |
[CKA] Application Lifecycle Management (0) | 2022.07.28 |
[CKA] Logging & Monitoring (0) | 2022.07.28 |
[CKA] Kubernetes Core Concepts (0) | 2022.07.27 |
- Total
- Today
- Yesterday
- mahout
- elasticsaerch
- 파이썬
- logstash
- Hadoop
- 백준
- kafka
- BOJ
- DFS
- HDFS
- Espher
- sqoop
- 이코테
- Elasticsearch
- 빅데이터
- Flutter
- GROK
- 프로그래머스
- cka
- oozie
- kubernetes
- DP
- 네트워크
- CSAPP
- 빅데이터를지탱하는기술
- OS
- CS
- Python
- Algorithm
- heapq
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |