1.Manual Scheduling
스케쥴러가 없을 시에 파드를 직접 노드에 수동으로 할당해야한다.
nodeName
nodeName은 어피니티 또는 nodeSelector보다 더 직접적인 형태의 노드 선택 방법이다
pod 파일에 nodeName을 설정 해주면 파드를 생성하는 동안 파드가 지정된 노드에 할당된다.
또다른 방법 > 이미 배포한 pod를 직접 스케줄링하려면 Binding 리소스를 만들고 직접 api 요청을 해야 한다
nodeName 을 사용해서 노드를 선택할 때의 제한 사항 몇가지
- nodeName에 해당하는 node가 없다면, 파드가 실행되지 않고 따라서 자동으로 삭제될 수 있다.
- nodeName에 해당하는 node에 파드를 수용할 수 있는 리소스가 없는 경우 파드가 실패하고, 그 이유는 다음과 같이 표시된다.
예: OutOfmemory 또는 OutOfcpu. - 클라우드 환경의 노드 이름은 항상 예측 가능하거나 안정적인 것은 아니다.
nodeSelector
#노드에 레이블 추가
kubectl get nodes --show-labels
kubectl label nodes <your-node-name> disktype=ssd #<your-node-name>는 선택한 노드의 이름이다.
kubectl get nodes --show-labels # disktype=ssd 레이블 가지고 있는지 확인
# worker0 노드에 disktype=ssd 레이블이 있는걸 확인할 수 있음
NAME STATUS ROLES AGE VERSION LABELS
worker0 Ready <none> 1d v1.13.0 ...,disktype=ssd,kubernetes.io/hostname=worker0
worker1 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker1
worker2 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker2
선택한 노드에 스케줄되도록 파드 생성하기
disktype: ssd라는 노드 셀렉터를 가진 파드가 disktype=ssd 레이블이 있는 노드에 스케줄 될 것이라는 걸 의미함.
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd
kubectl apply -f https://k8s.io/examples/pods/pod-nginx.yaml
kubectl get pods --output=wide
#결과
NAME READY STATUS RESTARTS AGE IP NODE
nginx 1/1 Running 0 13s 10.200.0.4 worker0
2. Labels & Selectors & Annotations
label은 selector와 함께 특정 레이블이 있는 자원을 선택할 때 사용되고, annotation은 메타데이터를 기록하는데 사용된다.
- label : 사용자가 오브젝트를 생성할 때 해당 오브젝트 구분하는 용도
- annotation : 사용자가 원하는 값을 설정하기 보다, 시스템에서 필요한 정보를 표시하는데 사용하는 용도
label
레이블은 key-value 쌍으로 구성되어 있으며, 클러스터 안에 오브젝트를 만들 때 메타데이터로 설정할 수 있다.
쿠버네티스는 레이블의 키로 관리 대상을 구분하기 때문에, 특정 컨트롤러가 만든 파드더라도 레이블을 변경하면 인식할 수 없게 된다.
laebl의 활용
- 유연한 파드 관리 : 컨트롤러와 파드를 느슨하게 결합하는 특징 때문에, 실제 서비스에서 운영 중인 파드 중 임의의 1개를 따로 분리해서 파드 상태를 확인 할 수 있다.
- 디버깅용 : 서비스 운영 중 디버깅이 필요할 때는 디버깅용으로 별도의 컨테이너를 실행해서 확인할 수 있다. 서비스 이슈가 발생한 파드만을 따로 분리해 확인 할 수 있다.
- 노드 자원 할당 : 노드에도 레이블 설정이 가능하므로 클러스터 안 노드 중 특정 레이블이 있는 노드에만 자원을 할당하여 실행할 수 있다. 예) SSD를 사용하는 노드에만 자원 할당 하기. GPU사용하는 노드에만 자원 할당하기
레이블 키값 설정 시 지켜야하는 규칙
- 63글자를 넘으면 안됨
- 시작과 끝 문자는 알파벳 대소문자 및 숫자여야 한다.
- 중간에는 - (대시) _(밑줄) .(점) 26 (숫자) 등이 올 수 있다.
- (참고) 레이블의 키 앞에는 / 구분해 접두어(DNS 하위 도메인 형식) 사용 가능함. 점으로 구분 가능하며 253자 초과 안됨.
사용자가 직접 레이블 키를 설정할 때는 접두어 사용을 잘 하지 않기 때문에, 접두어가 존재하는 레이블의 키는 쿠버네티스 시스템에서 사용하는 레이블이라고 볼 수 있다. ("kubernetes.io/")
selector
사용자가 설정한 특정 레이블에만 자원을 할당하여 관리할 수 있다. 이렇게 특정 레이블을 선택할 때는 레이블 셀렉터를 이용하게 된다.
설정 방식
- 등호 기반(equality-based): 같냐 =,== 다르냐 !=
- 예) enviroment=develop, release=stable 의 의미는 두 조건을 모두 만족한 레이블을 선택해라다. 쉼표(AND연산)
- 집합 기반(set-based): 여러 값을 조건으로 설정한 뒤 해당 키가 있는 레이블 값이 조건에 속하는지(In), 아닌지(not in), 특정 레이블 키가 존재(exists)하는지 확인
enviroment in (develop, stage) #enviroment가 develop이거나 stage레이블 선택
release notin(lastest, canary) #release가 없거나 lastest와 canary가 아닌 레이블 선택
gpu #gpu라는 레이블 키가 있는 모든 레이블, 이때 값 확인은 하지 않음.
!gpu #gpu라는 레이블 키가 없는 모든 레이블
동일하게 이 조건 모두 만족시키는 AND연산은 쉼표(,) 이다.
🍓 레이블 사용 예시 추후
애너테이션(annotation)
애너테이션은 클라이언트나 라이브러리 자원을 관리하는데 사용된다. 레이블과 마찬가지로 키-값 쌍이며, 사용자가 설정할 수 있다.
annotation의 키는 쿠버네티스 시스템이 인식할 수 있는 값을 사용하게 된다.
예)
- 디플로이먼트 앱 배포 시 변경 사유 적는 CHANGE-CAUSE
- ingress-nginx같은 인그레스 컨트롤러에 annotation으로 사용자가 직접 nginx에 필요한 설정을 정의함.
- 사용자에게 필요한 정보 메모 용도 ( 릴리즈 정보, 모니터링에 필요한 정보, 오브젝트의 담당자 정보나 비상 연락처 등등)
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: simple-webapp
labels:
app: App1
function: Front-end
annotations:
buildversion: 1.34
spec:
replicas: 3
selector:
matchLabels:
app: App1
template:
metadata:
labels:
app: App1
function: Front-end
spec:
containers:
- name: simple-webapp
image: simple-webapp
-----------------------------파드 스케쥴링-----------------------------
3. Taints and Tolerations
테인트를 설정한 노드에는 파드들을 스케줄링하지 않는다. 즉 테인트를 설정한 노드에 파드를 스케쥴링하려면 톨러레이션을 설정해야한다.
뒤에서 언급할 잘노드 셀럭터나 어피니티는 포드를 끌어당겨서 실행하게 하지만 테인트와 톨러레이션은 그반대이다. 노드가 특정 역할만 수행하게 하기 위해서 원하지 않는 포드는 실행되지 않게 한다.
예) 데이터베이스용 파드를 실행한 후 노드 전체의 CPU나 RAM 자원을 독점해서 사용
taint ⇒ nodes 에 설정하는 것
tolerations ⇒ pods 에 설정하는 것
k describe nodes 노드이름 # 노드에 테인트가 설정되어있는지 확인
중간은 생략 $ Taints: key01=value-1:NoSchedule #테인트 확인
#테인트가 있으므로 톨러레이션 설정을 해줘야 테인트가 설정된 노드에 파드를 실행 시킬 수 있음
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
tolerations:
- key: "key01" #테인트에 설정되었던 값
operator: "Equal"
value: "value-1" #테인트에 설정되었던 값
effect: "NoSchedule"
# 클러스터에 적용하면 새로운 파드를 스케줄해 실행 됨.
k apply -f deployment-toleraion.yaml
#테인트 설정 삭제
k taint nodes 노드이름 키:효과
4. nodeSelector
가장 간단한 스케쥴링 옵션이다. Node에 설정된 Label을 기반으로 하여 Label Selector 기반 Pod 배치 가능하다.
이미 띄워져있는 Node들에 대해선, kubectl을 통해 Node의 label 관리가 가능하다.
- 노드에 추가
$ kubectl get nodes --show-labels # 현재 node들의 label 정보확인
$ kubectl label nodes [노드명] [키]=[값]
- 노드에 제거
$ kubectl label node [노드명] [key]-
- node에 label이 disktype=ssd로 추가되었고, pod에 spec.nodeSelector.disktype: hdd 설정되있다고 가정했을 시
nodeSelector와 key, value를 지정하면 해당 label을 갖고 있는 node에만 배포가 진행된다. 만일 필드 값이 다를 시 동일하게 변경 후 적용하여 파드를 실행 시키면 된다.
따라서 k delete pods 파드명 을 실행시켜 파드를 삭제한 후 다시 파드.yaml 파일에 spec.nodeSelector.disktype 값 수정 후 적용하면 됨.
5. affinity
노드 어피니티(Node Affinity): 파드를 함께 묶어 같은 노드에서 실행하도록 설정, 친밀감 (=rapport)
노드 안티 어피니티(Node anti-Affinity): 파드를 다른 노드에 나누어서 실행하도록 설정
노드 어피니티(Node Affinity)는 노드 셀렉터와 비슷하게 노드의 레이블을 기반으로 파드를 스케쥴링한다. 노드 어피니티와 노드셀렉터를 함께 설정할 수도 있으며, 이 때는 노드 어피니티와 노드셀렉터의 조건을 모두 만족하는 노드에 파드를 스케쥴링한다.
노드 어피니티에는 두 가지 필드가 있다.
(두 필드는 실행 중에 조건이 바뀌어도 무시한다 : 파드가 이미 스케줄링 되어 특정 노드에서 실행 중 이라면 중간에 해당 노드의 조건이 변경되더라도 이미 실행 중인 파드는 그대로 실행된다.)
- requiredDuringSchedulingIgnoredDuringExecution : '스케쥴링하는 동안 꼭 필요한' 조건
- preferredDuringSchedulingIgnoredDuringExecution : '스케쥴링하는 동안 만족하면 좋은' 조건.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: beta.kubernettes.io/os
operator: In
values:
-linux
-window
- key: disktype
operator: Exists
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 10
preference:
matchExpressions:
- key: kubernettes.io/hostname
operator: In
values:
- worker-node01
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
.spec.affinity의 하위 필드보면 두 필드가 모두 설정된 것을 알 수 있음
requiredDuringSchedulingIgnoredDuringExecution의 하위 필드
- 노드 어피니티 유형과 연관된 노드 셀렉터 설정을 연결하는 nodeSelectorTerms[], matchExpressions[]
preferredDuringSchedulingIgnoredDuringExecution의 하위필드
- nodeSelectorTerms[] 필드 대신 preference 필드를 사용, matchExpressions[], weight
- preference는 말 그대로 조건에 맞는 노드를 우선해서 선택한다는 뜻.
- weight 필드는 1부터 100까지의 값을 설정할 수 있다. 여러 개 matchExpressions[] 필드 안 설정 각각이 노드의 설정과 맞을 때 마다 weight 필드 값을 더하게 된다. 이때 모든 노드 중에서 weight필드 값의 합계가 가장 큰 노드를 선택함.
matchExpressions[]의 하위 필드
- key, operator, values[]
key 필드 값 | 설명 |
In | values[] 필드에 설정한 값 중 레이블에 있는 값과 일치하는 것이 하나라도 있는지 확인 |
NotIn | In과 반대로 values[]에 있는 값 모두와 맞지 않는 지 확인 |
Exists | key 필드에 설정한 값이 레이블에 있는지만 확인. (values[] 필드가 필요 없다.) |
DoseNotExist | Exists와 반대로 노드의 레이블에 key 필드 값이 없는지만 확인. |
Gt | Greater than의 약자로 values[] 필드에 설정된 값이 설정된 값 보다 더 큰 숫자형 데이터 인지 확인. 이 때 values[] 필드에는 값이 하나만 있어야 한다. |
Lt | Lower than의 약자로 values[] 필드에 설정된 값이 설정된 값 보다 더 작은 숫자형 데이터 인지 확인. 이 때 values[] 필드에는 값이 하나만 있어야 한다 |
6. Resource Limit
Resource Request와 Limit은 컨테이너에 할당되는 cpu와 memory 자원량을 의미한다.
- CPU : Milicore단위(1,000 Milicore = 1Core)
- Memory : Mbytee단위
pod의 spec.containers[].resources 에 아래와 같은 4개 정보를 설정해야 한다.
requests와 limits 이라는 항목이 있으며, 각각 cpu, memory 값을 설정할수 있다.
container당 default request 0.5vcpu와 256Mi, limit는 container당 1vcpu와 512Mi로 생성된다.
- limits.cpu
- limits.memory
- requests.cpu
- requests.memory
# 리소스 확인
kubectl get po -o yaml [pod]
# 모든 파드의 값을 한번에 출력
kubectl get po -o custom-columns="Name:metadata.name,\
CPU-Requet:spec.containers[*].resources.requests.cpu,CPU-limit:spec.containers[*].\
resources.limits.cpu,MEM-Request:spec.containers[*].resources.requests.memory,MEM-limit:spec.containers[*].resources.limits.memory"
7. Daemonset
클러스터 전체 노드에 특정 파드를 실행할 때 사용하는 컨트롤러이다. 예) kube-proxy
클러스터 안에 새롭게 노드가 추가되었을 때 데몬셋이 자동으로 해당 노드에 파드를 실행시키며, 반대로 노드가 클러스터에서 빠졌을 때는 해당 노드에 있던 파드는 그대로 사라질 뿐 다른 곳으로 옮겨가서 실행되지는 않는다. 따라서 보통 로그 수집기를 실행하거나 노드를 모니터링하는 데몬 등 클러스터 전체에 항상 실행해두어야 하는 파드에 사용한다. 예) 모니터링이나 로그 컬렉터, 네트워킹
kubectl get daemonset -n kube-system # 데몬셋 조회
8. Static PODs
스태틱 파드는 API 서버 없이 특정 노드에 있는 kubelet 데몬에 의해 직접 관리된다. etcd, api-server 등이 대표적인 스태틱 파드이다.
- 기본 경로 : /etc/kubernetes/manifests/
조회는 가능하나 edit은 불가능하며, k delete pod로 지우면 재생성되기에 ,kubelet의 config 파일에 있는 staticPodPath(staticPodPath: /etc/kubernetes/manifests) 를 찾아서 path위치에 있는 yaml파일을 지워야한다.
kubectl get pods --all-namespaces -o wide #특정 스태틱 파드가 어느 노드에서 실행 중인지 확인
9. Multiple Schedulers
쿠버네티스 스케줄러는 할당되지 않은 파드를 확인하고 어떤 노드에 할당할지를 결정하면 API를 통해 노드를 지정하는 구조로 되어 있다.
따라서 정기적으로 쿠버네티스 마스터 API를 통해 확인하고 할당하는 커스텀 스케줄러 프로그램을 구현하면 기존 스케줄러를 대체 할 수 있다.
기본적인 스케출러만으로도 충분하나, 기능적으로 부족한 경우에 커스텀 스케줄러를 활용하여 사용자가 배치하고 싶은 노드를 쉽게 관리할 수 있다.
커스텀 스케줄러
# kubelet에 설정되어있는 config.yaml경로 찾기
ps -ef | grep -i kubelet | grep -i config
>> /var/lib/kubelet/config.yaml
# config.yaml에 설정되어있는 staticPodPath찾기
grep -i static /var/lib/kubelet/config.yaml
>>/etc/kubernetes/manifests
# 해당 경로에 static pod를 실행시키는 yaml파일들이 있음
cd /etc/kubernetes/manifests
## 여기에 kube-scheduler.yaml파일을 /root로 복사
cp /etc/kubernetes/manifests/kube-scheduler.yaml /root/my-scheduler.yaml
vi /root/my-scheduler.yaml
## 1.command 부분 아래와 같이 수정
- --leader-elect=false #커스텀 스케줄러를 메인으로 사용하지 않을거라 false
- --port=10282 #기존에 사용하는 포트랑 다른걸 선택하기 위해 10282
- --scheduler-name=my-scheduler #설정안해주면 디폴트 이름으로 정해진다.
- --secure-port=0 # http는 사용안하겠다.
## 2. livenessProbe, startppProbe의 health체크 하는 부분 포트 변경 10282, HTTPS를 HTTP로 변경
httpGet:
host: 127.0.0.1
path: /healthz
port: 10282
scheme: HTTP
custom scheduler를 사용하고 싶은 pod의 spec 아래에 schedulerName을 넣어준다.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
schedulerName: my-scheduler ## 기존 스케줄러에 할당되지 않도록 파드에 지정해야 함.
containers:
- image: nginx
name: nginx
특정노드 지정 스케줄러
노드를 지정하여 파드를 가동시킬 수도 있다.
하지만 이방법은 추천하지 않으므로, 레이블 등을 사용해 간접적으로 스케줄링 하는 것을 권장함.
View Events (다중 스케줄러 적용 확인하기)
$ kubectl get events -o wide
$ kubectl logs my-custom-scheduler -n kube-system
참고
'STUDY > Data Engineering' 카테고리의 다른 글
11. CKA udemy 강의 정리 - Section 5 [Application Lifecycle Management] (0) | 2023.01.12 |
---|---|
10. CKA udemy 강의 정리 - Section 4 [Logging&Monitoring] (0) | 2023.01.11 |
8. CKA udemy 강의 정리 - Section 2 [명령형 접근법/선언형 접근법] (0) | 2023.01.06 |
7. CKA udemy 강의 정리 - Section 2 [Namespace] (1) | 2023.01.06 |
6. CKA udemy 강의 정리 - Section 2 [Services & kodekloud] (0) | 2023.01.05 |