✅ Taint & Toleration
taint : 노드마다 설정가능. 설정한 노드에는 pod이 스케줄되지 않음
toleration : taint를 무시할수있음
주로 노드를 지정된 역할만 하게할때 사용한다.
예를들어 gpu잇는 노드에는 다른 pod들은 올라가지않고 gpu쓰는 pod들만 올라가게 하는등의 상황에 사용할 수 있습니다.
taint에는 사용할 수 있는 3가지 옵션이 있다.
- NoSchedule : toleration이 없으면 pod이 스케쥴되지 않음, 기존 실행되던 pod에는 적용 안됨
- PreferNoSchedule : toleration이 없으면 pod을 스케줄링안하려고 하지만 필수는 아님, 클러스터내에 자원이 부족하거나 하면 taint가 걸려있는 노드에서도 pod이 스케줄링될 수 있음
- NoExecute : toleration이 없으면 pod이 스케줄되지 않으며 기존에 실행되던 pod도 toleration이 없으면 종료시킴
worker1과 worker2에 taint를 준다.
[root@master1 schedule]# kubectl describe nodes worker1 | grep -i Taints
Taints: <none>
[root@master1 schedule]# kubectl taint node worker1 tier=gpu:NoSchedule
node/worker1 tainted
[root@master1 schedule]# kubectl taint node worker2 tier=dev:NoSchedule
node/worker2 tainted
어떤 배치전략도 적용되지 않은 노멀한 Deployment에 tolerations을 정의한다.
key가 role이고 value는 system, effect는 NoSchedule인 Node에 대해서, 이 yml이 생성할 Pod의 배치를 용인해준다.
[root@master1 schedule]# vi deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 4
selector:
matchLabels:
app: nginx-deployment
template:
metadata:
name: nginx-deployment
labels:
app: nginx-deployment
spec:
containers:
- name: nginx-deployment-container
image: halilinux/web-site:aws
ports:
- containerPort: 80
tolerations:
- key: "tier"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"
pod를 확인해보면 지정 노드를 targeting 해서 배치시킨 것을 볼 수 있다.
[root@master1 schedule]# vi deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment2
spec:
replicas: 1
selector:
matchLabels:
app: nginx-deployment2
template:
metadata:
name: nginx-deployment2
labels:
app: nginx-deployment2
spec:
containers:
- name: nginx-deployment-container2
image: 192.168.149:5000/nginx:latest
ports:
- containerPort: 80
tolerations:
- key: "tier"
operator: "Equal"
value: "dev"
effect: "NoSchedule"
✔ 원복시키기
# kubectl taint node worker1 tier=dev:NoSchedule-
node/worker1 untainted
# kubectl taint node worker1 tier=gpu:NoSchedule
node/worker2 untainted
✔ 수동 배포
[root@master1 schedule]# vi pod-nodename.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-nodename-metadata
labels:
app: pod-nodename-labels
spec:
containers:
- name: pod-nodename-containers
image: 192.168.1.149:5000/nginx:latest
ports:
- containerPort: 80
nodeName: master1
---
apiVersion: v1
kind: Service
metadata:
name: pod-nodename-service
spec:
type: NodePort
selector:
app: pod-nodename-labels
ports:
- protocol: TCP
port: 80
targetPort: 80
taint를 수동으로 설정하면 자동으로 뚫고 들어간다.
master1에 taint를 걸어주었지만 할당되는 모습이다.
[root@master1 schedule]# kubectl describe nodes master1 | grep -i Taints
Taints: node-role.kubernetes.io/master:NoSchedule
[root@master1 schedule]# kubectl taint node master1 node-role.io/master:NoSchedule
node/master1 tainted
[root@master1 schedule]# vi deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment3
spec:
replicas: 3
selector:
matchLabels:
app: nginx-deployment3
template:
metadata:
name: nginx-deploymen3
labels:
app: nginx-deployment3
spec:
containers:
- name: nginx-deployment-container3
image: halilinux/web-site:aws
ports:
- containerPort: 80
지표의 상태에 따라 할당되는 노드들이 달라진다.
✅ 로컬 클러스터에 메트릭스 서버 추가하기
메트릭스 서버는 쿠버네티스에서 리소스 메트릭 파이프라인을 구성하는 가장 기본적인 방법이다.
그러나 쿠버네티스를 설치한다고해서 메트릭 서버가 자동으로 설치되지는 않으므로 직접 설치하는 과정이 필요하다.
다음 두 명령을 실행해 공개된 yaml 파일을 사용하여 metrics-server 사용할 수 있도록 yaml 파일을 적용한다.
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.3.7/components.yaml
여기까지 실행하면 metrics 서버는 돌지만 kubelet 에 접근해 포드와 노드의 정보를 얻어오지 못하는 현상이 일어난다.
이 현상은 tls 통신이 제대로 이뤄지지 않기 때문이므로 다음과 같이 metrics 서버의 내용을 수정하여 서버 통신이 원활하게 할 수 있도록 옵션을 바꾼다.
메트릭스 디플로이의 설정을 변경하기 위해 다음 명령어를 실행한다.
kubectl edit deployments.apps -n kube-system metrics-server
--kubelet-insecure-tls
✅ Cordon & Drain
✔ Cordon
$ kubectl cordon <node-name>
kubectl은 노드의 pod-scheduling 정책을 변경할 수 있는 drain, cordon, uncordon 등의 명령어를 제공한다. 이러한 명령어들은 worker 노드의 OS나 kubelet 버전 업데이트 등을 위해 활용된다.
kubectl cordon은 현재 노드에 배포된 Pod은 그대로 유지하면서, 추가적인 Pod의 배포를 제한하는 명령어이다. 따라서, drain 과정에 cordon이 포함되어 있다고 볼 수 있다.
# vi pod-nodename.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-nodename-metadata1
labels:
app: pod-nodename-labels1
spec:
containers:
- name: pod-nodename-containers1
image: 192.168.1.149:5000/nginx:latest
ports:
- containerPort: 80
nodeName: worker2
---
apiVersion: v1
kind: Service
metadata:
name: pod-nodename-service1
spec:
type: NodePort
selector:
app: pod-nodename-labels1
ports:
- protocol: TCP
port: 80
targetPort: 80
cordon 처리한 worker2에 배치된 모습이다.
Scheduling은 자동을 의미하는 것이고 수동이 더 우선시 된다.
즉슨, cordon 명령은 지정된 노드에 추가로 파드를 "자동" 스케줄하지 않는다.
✔ 상태 원복하기
[root@master1 schedule]# kubectl uncordon worker2
node/worker2 uncordoned
[root@master1 schedule]# kubectl get no
NAME STATUS ROLES AGE VERSION
master1 Ready master 7d18h v1.19.16
worker1 Ready <none> 7d18h v1.19.16
worker2 Ready <none> 7d18h v1.19.16
✅ 데몬셋 (Daemonset)
데몬셋은 디플로이먼트와 유사하게 파드를 생성하고 관리한다.
디플로이먼트는 롤링 업데이트나 배포 일시 중지, 재개 등 배포 작업을 좀 더 세분화하여 조작하였다면, 데몬셋은 특정 노드 또는 모든 노드에 항상 실행되어야 할 특정 파드를 관리 하며 쉽게 지울 수 없도록 lock이 걸린다.
하나의 예를 들자면 모니터링 시스템 구축을 위해 모든 노드에 특정 파드(로그 수집용)를 관리해야 할 때 사용할 수 있다. 모니터링 시스템을 원활히 사용하기 위해선 모든 노드에 항상 로그 수집할 무언가가 필요하기 때문이다.
특정 노드를 지정하여 사용할수도 있다.
[root@master1 schedule]# kubectl get daemonsets.apps -n kube-system
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
kube-proxy 3 3 3 3 3 kubernetes.io/os=linux 7d18h
✔ Drain
$ kubectl drain <node-name>
Drain은 직역하면 배수구, 물 빠짐 등의 의미로 번역된다. 이름에서 알 수 있듯, kubectl drain은 노드에 존재하는 모든 Pod을 제거하여 노드를 비우고, Pod들을 다른 노드에 새롭게 스케쥴링하는 명령어이다.
또한, kubectl drain이 적용된 노드는 SchedulingDisabled 상태가 되며, 이후 새롭게 생성되는 어떤 Pod도 해당 노드에 생성되지 않는다.
✔ drain통해 worker1 배제하기
[root@master1 schedule]# kubectl drain worker1 --ignore-daemonsets --force --delete-local-data
cordon은 이미 갖고있는 파드를 유지시키면서 새롭게 파드를 추가시키지 않는다는 의미고
drain은 갖고있는 파드를 다른 곳에서 새롭게 만들어진다는 의미이다.
✅ 오토스케일링 실습(HPA: Horizontal Pod Autoscaler)
[root@master1 schedule]# kubectl taint node master1 node-role.kubernetes.io/master:NoSchedule
deployment는 자가치유기능이 있기에 pod가 지워지면 다시 만들어진다
master1 노드의 파드가 지워지면 다시 만들어 질 것이다.
[root@master1 schedule]# vi php-apache.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache
spec:
selector:
matchLabels:
run: php-apache
replicas: 2 # Desired capacity, 시작 갯수
template:
metadata:
labels:
run: php-apache
spec:
containers:
- name: php-apache
image: k8s.gcr.io/hpa-example
ports:
- containerPort: 80
resources:
limits:
cpu: 500m
requests:
cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
name: php-apache
labels:
run: php-apache
spec:
ports:
- port: 80
selector:
run: php-apache
[root@master1 schedule]# kubectl apply -f php-apache.yaml
deployment.apps/php-apache created
service/php-apache created
[root@master1 schedule]# kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
php-apache-d4cf67d68-4h9sv 1/1 Running 0 15m 10.244.1.118 worker1 <none> <none>
php-apache-d4cf67d68-s25d9 1/1 Running 0 15m 10.244.1.117 worker1 <none> <none>
# vi hpa.yaml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
spec:
maxReplicas: 4
minReplicas: 2
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
targetCPUUtilizationPercentage: 50
status:
currentCPUUtilizationPercentage: 0
currentReplicas: 2
desiredReplicas: 2
# kubectl apply -f hpa.yaml
실습을 위해 busybox 이미지를 다운받는다
(yaml 파일에 busybox:1.28 로 정의할 수 있지만 이미지를 pull 받는 과정에서 에러가 발생하여 다음과 같은 추가 과정을 거쳤다)
[root@master1 schedule]# docker pull busybox:1.28
[root@master1 schedule]# docker tag busybox:1.28 192.168.1.149:5000/busybox:1.28
[root@master1 schedule]# docker push 192.168.1.149:5000/busybox:1.28
[root@master1 schedule]# kubectl run -i --tty load-generator --rm --image=192.168.1.149:5000/busybox:1.28 --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"
pod들이 생성되는 모습을 볼 수 있다.
참고
https://velog.io/@koo8624/Kubernetes-Drain-Cordon-and-Uncordon
'DEVELOP > AWS' 카테고리의 다른 글
AWS | EKS, ECR (0) | 2023.06.16 |
---|---|
KUBERNETES | GCP에서 쿠버네티스 사용해보기 (0) | 2023.06.08 |
KUBERNETES | 프로메테우스, 그라파나 실습 (1) | 2023.06.07 |
AWS | NAT 인스턴스, S3, CloudFront, Lambda, MediaConvert구축 (0) | 2023.05.09 |
AWS | 다이어그램 따라 망 구축하기 (0) | 2023.05.03 |