nayoungs
항상 끈기있게
nayoungs
  • 분류 전체보기 (274)
    • Cloud (21)
      • AWS (15)
      • Azure (3)
      • NCP (2)
      • GCP (1)
    • DevOps (68)
      • Docker (16)
      • Kubernetes (50)
      • CICD (2)
    • IaC (25)
      • Ansible (17)
      • Terraform (8)
    • Certification (4)
    • 금융 IT (5)
    • AI (3)
    • Linux (47)
    • 미들웨어 (5)
    • Programming (7)
      • GoLang (3)
      • Spring (4)
    • CS (25)
      • 네트워크 (17)
      • 운영체제 (5)
      • Web (1)
      • 개발 상식 (2)
      • 데이터베이스 (0)
    • Algorithm (59)
      • 프로그래머스 (36)
      • 백준 (18)
      • 알고리즘 정리 (5)
    • ETC (5)

블로그 메뉴

  • 홈
  • 방명록

공지사항

인기 글

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
nayoungs

항상 끈기있게

DevOps/Kubernetes

[Kubernetes] k8s Cordon과 Drain

2022. 5. 26. 23:19
728x90

📌Index

  • Cordon
  • Drain



Cordon

Cordon은 지정된 노드에 더이상 포드들이 스케쥴링 되지 않도록 한다.

 

Cordon 설정하기 : Scheduling 금지하기

$ kubectl cordon <NODENAME>

해당 노드에 이미 존재하는 것들은 관계없다.

새롭게 생성되는 파드들은 더 이상 해당 노드에 배치되지 않는다.

 

 

Cordon 해제

$ kubectl uncordon <NODENAME>

 

사용 예시

  • 패치
  • 커널 업데이트

 

💻 실습 : Cordon과 Affinity의 활용

 

현재 노드들의 상태는 다음과 같고,

$ kubectl get nodes             
NAME    STATUS   ROLES                  AGE    VERSION
node1   Ready    control-plane,master   9d     v1.22.8
node2   Ready    <none>                 9d     v1.22.8
node3   Ready    <none>                 7d1h   v1.22.8

node2를 cordon 해보자.

$ kubectl cordon node2          
node/node2 cordoned                <none>                 7d1h   v1.22.8

node2가 SchedulingDisabled 상태가 된 것을 확인할 수 있다.

$ kubectl get nodes   
NAME    STATUS                     ROLES                  AGE    VERSION
node1   Ready                      control-plane,master   9d     v1.22.8
node2   Ready,SchedulingDisabled   <none>                 9d     v1.22.8
node3   Ready

 

다음으로 아래와 같이 복제본 2개를 생성하는 ReplicaSets을 작성한다.

podAntiAffinity 설정으로, 복제본이 같은 노드에 배치될 수 없도록 구성하였다.

affinity에 대한 자세한 설명은 affinity와 anti-affinity에서 확인할 수 있다.

 

myweb-a.yaml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myweb-a
spec:
  replicas: 2
  selector:
    matchLabels:
      app: a
  template:
    metadata:
      labels:
        app: a
    spec:
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 10
              preference:
                matchExpressions:
                  - key: gpu
                    operator: Exists
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                 matchLabels:
                   app: a
              topologyKey: "kubernetes.io/hostname"
      containers:
        - name: myweb
          image: ghcr.io/c1t1d0s7/go-mywe
$ kubectl create -f myweb-a.yaml
replicaset.apps/myweb-a created

node2가 금지(Cordon)되었기 때문에 node1,3에 배치될 수 밖에 없고,

최종적으로 node1,3에 배치된 것을 확인할 수 있다.

$ kubectl get po -o wide        
NAME                                      READY   STATUS    RESTARTS        AGE   IP              NODE    NOMINATED NODE   READINESS GATES
myweb-a-7ll7d                             1/1     Running   0               12s   10.233.92.176   node3   <none>           <none>
myweb-a-kpq68                             1/1     Running   0               12s   10.233.90.241   node1   <none>           <none>

이 상태에서 스케일링을 통해 replicas를 3으로 변경해보자.

$ kubectl scale rs myweb-a --replicas=3

2번은 금지되었고, 1,3번은 안티어피니티 때문에 배치될 수 없어 Pending 상태가 지속된다.

$ kubectl get po -o wide               
NAME                                      READY   STATUS              RESTARTS        AGE     IP              NODE     NOMINATED NODE   READINESS GATES
myweb-a-7ll7d                             1/1     Running             0               2m30s   10.233.92.176   node3    <none>           <none>
myweb-a-dhdnd                             0/1     Pending             0               3s      <none>          <none>   <none>           <none>
myweb-a-kpq68                             1/1     Running             0               2m30s   10.233.90.241   node1    <none>           <none>

파드의 Events를 살펴보면 1개는 스케쥴링이 안되고,

2개는 anti-affinity 때문에 배치가 안된다는 설명을 확인할 수 있다.

Events:
  Type     Reason            Age                  From               Message
  ----     ------            ----                 ----               -------
  Warning  FailedScheduling  12m                  default-scheduler  0/3 nodes are available: 1 node(s) were unschedulable, 2 node(s) didn't match pod anti-affinity rules.

Cordon을 해제하고 다시 확인하면,

$ kubectl uncordon node2
node/node2 uncordoned

파드가 다시 생성되어, node2에 배치된 것을 확인할 수 있다.

$ kubectl get po -o wide               
NAME                                      READY   STATUS              RESTARTS        AGE     IP              NODE     NOMINATED NODE   READINESS GATES
myweb-a-7ll7d                             1/1     Running             0               2m30s   10.233.92.176   node3    <none>           <none>
myweb-a-dhdnd                             0/1     Running             0               3s      10.233.92.185   node2    <none>           <none>
myweb-a-kpq68                             1/1     Running             0               2m30s   10.233.90.241   node1    <none>           <none>



✔️ Drain

Drain은 기존 파드를 제거하는 설정으로, drain하면 자동으로 uncordon되고, 파드들을 노드에서 쫓아낸다.

복제본을 제공하는 것(RS, Deployment 등)은 삭제되어도 다른 곳에 다시 만들어지기 때문에 크게 상관없으나,

데몬셋, 파드와 같은 경우는 노드에서 쫓겨나면 갈 곳이 없는 것이기 때문에 아예 삭제된다. (없어지는 것이다)

 

다음과 같이 node2에 drain을 시도하면 에러가 발생한다.

$ kubectl drain node2
node/node2 cordoned
DEPRECATED WARNING: Aborting the drain command in a list of nodes will be deprecated in v1.23.
The new behavior will make the drain command go through all nodes even if one or more nodes failed during the drain.
For now, users can try such experience via: --ignore-errors
error: unable to drain node "node2", aborting command...

There are pending nodes to be drained:
 node2
cannot delete Pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet (use --force to override): dev/myweb, dev/myweb-label
cannot delete DaemonSet-managed Pods (use --ignore-daemonsets to ignore): ingress-nginx/ingress-nginx-controller-xbj69, kube-system/calico-node-9mxkg, kube-system/kube-proxy-cbzbn, kube-system/nodelocaldns-g74tc, metallb-system/speaker-vzw82

node2에 데몬셋에 의해 관리되는 파드들이 존재하기 때문이다.

 

에러를 무시하고 Drain하려면 --ignore-daemonsets 옵션을 사용하면 된다.

$ kubectl drain node2 --ignore-daemonsets

drain하게되면, 자동적으로 Cordon 상태가 되고,

재부팅해도 Cordon 상태 이기 때문에 drain 후 반드시 uncordon 해줘야한다.

 

728x90
저작자표시 비영리
    'DevOps/Kubernetes' 카테고리의 다른 글
    • [Kubernetes] Kubeconfig파일이란?
    • [Kubernetes] k8s Taint와 Toleration
    • [Kubernetes] k8s 어피니티(Affinity)와 안티-어피니티(Anti-Affinity)
    • [Kubernetes] Pod Scheduling : nodeName, nodeSelector
    nayoungs
    nayoungs
    안되면 될 때까지

    티스토리툴바