반응형

 

  • cordon

cordon은 특정 노드를 선택하여 스케줄 대상에서 제외 시킵니다. 간단한 deployment nginx 이미지를 생성해주는 매니페스트 파일을 작성 후 아래와 같이 cordon 명령을 실행하면 선택한 특정 노드가 SchedulingDisabled 상태가 되는것을 확인할 수 있습니다.

  • kubectl get nodes : 기존 노드 STATUS 확인
  • kubectl get pod -o custom-columns=Pod:metadata.name,Node:spec.nodeName : Pod가 배치된 노드 확인
  • kubectl cordon [노드네임] : 해당 노드에 cordon 적용
  • kubectl get nodes : 기존 노드 STATUS에 SchedulingDisabled가 추가된 내용 확인

 

이후 scale를 이용하여 deployment nginx의 replicas 개수를 늘려주면 아래 이미지와 같이 cordon 했던 노드에는 pod가 증가하지 않고, 다른 노드에서 증가하는것을 확인할 수 있습니다.

저는 aks-nodepool1-14067510-vmss000000 이라는 이름을 가진 노드를 cordon 했으므로 000001 노드에 Pod가 생성 되었습니다.

 

위의 과정을 그림으로 표현한다면 아래 이미지와 같이 됩니다.

 

SchedulingDisabled를 해제하고 싶다면 uncordon을 사용하시면 됩니다. (아래 drain에서도 마찬가지 입니다)

 

  • drain

drain은 cordon이랑 똑같이 동작 하지만, SchedulingDisabled 된 노드에 남아있는 Pod를 모두 삭제하고 재생성 하는 등의 기능이 추가된거라고 보시면 됩니다.

kubectl drain [노드네임] --ignore-daemonsets 을 입력하면 아래와 이미지와 같이 실행이 됩니다. 참고로 선택하는 노드는 SchedulingDisabled가 될 노드 입니다.

좌 : drain 전  /  우 : drain 후

 

* 참고로 --ignore-daemonsets 옵션을 추가해주지 않고 drain을 사용하게 되면 아래와 같이 에러가 발생 합니다. daemonsets은 각 노드들에 하나씩 실행되기 때문에 다른 노드로 옮기수가 없어 발생하는 에러 입니다. 

 

마찬가지로 그림으로 보면 아래 이미지처럼 됩니다.

 

  • PodDisruptionBudget (PDB)

PodDisruptionBudget 오브젝트는 drain을 사용할 때 한번에 많은양의 Pod가 옮겨지고, 일시적으로 리플리카 수가 커질 가능성을 없애기 위한 오브젝트 입니다. 

  • max-unavaliable : 사용할 수 없는 Pod를 허용하는 최대 수 or 비율
  • max-available : 최소한 유지할 Pod 갯수 or 비율

max-unavaliable을 2로 설정할 경우 최대 2개까지 사용할 수 없는 Pod를 허용(Pod를 이동하는 과정에서 사용할 수 없게 되므로) Pod가 2개씩 노드를 옮겨갈 것이고, max-available을 2로 설정할 경우 최소한 Pod가 2개 되는것까지를 허용하여 나머지 Pod들이 다른 노드로 옮겨갈 것 입니다.

현재 000000 이라는 노드에 8개의 pod가 동작중이며 kubectl create poddisruptionbudget [pdb이름] --selector=app=nginx --max-unavailable=2 명령을 실행 하였습니다.

pdb 네임은 임의로 아무렇게나 지으셔도 되고, selector는 매니페스트 파일에 설정한 labels에 맞춰 작성 하시고, 저의 경우 --max-unavailable=2 를 입력하여 2개씩 이동시킬 겁니다. drain을 진행하기전에 콘솔창을 하나 더 띄워서 kubectl get deployment [deployment 이름] -w 을 사용하시면 실시간으로 최대 2개씩 옮겨가는것을 확인할 수 있습니다.  

drain 명령을 실행할 땐 --ignore-daemonsets --delete-local-data 옵션을 사용해야 합니다.

 

Pod가 2개씩 이동하여 최종적으로 000001 노드에 모든 Pod가 이동되었습니다.

 

아래 이미지와 같이 되지만, 좀더 정확히는 Pod가 노드를 옮겨가기 전에 잠깐 사라지는 구간이 있습니다. (node1 pod 종료 → node2 pod 시작 이기때문 입니다.) pdb를 생성할 때 --max-unavailable=2 를 설정 했으므로 Pod가 다른 노드에 옮겨가는 과정에서 최대 2개까지 사라지는게(?) 허용 됩니다.

 

PodDisruptionBudget은 다른것들과 마찬가지로 kubectl get, kubectl delete 등으로 조회/삭제가 가능 합니다.

 

반응형
반응형

 

  • 쿠버네티스 HPA 이란?

HPA(HorizontalPodAutoscaler)는 CPU, Memory 등 리소스가 정해둔 임계치를 초과할 경우 자동으로 스케일 아웃(Pod의 리소스를 증가 시키지 않고, Pod 개수 자체를 늘려줌) 해주는 기능을 갖추고 있습니다. HPA 컨트롤러가 리소스를 체크하며 정해둔 replicas 수에 맞춰 Pod를 줄이거나 늘려줍니다.

아래 리소스들을 이용하여 HPA를 구성할 수 있습니다.

  • Deployment
  • Replicaset
  • StatefulSet
  • Recplication Controller

,

  • 쿠버네티스 HPA 구조

위와 같은 과정을 통해 replicaset을 배포하고, 모든 Pod의 사용률 총합을 구한 뒤 HPA 매니페스트 파일에 지정한 사용률을 나눠 배포할 replicas 개수를 구합니다.

 

  • 쿠버네티스 HPA 구성 및 동작 확인

아래와 같은 HPA 매니페스트 파일을 이용하여 확인할 수 있습니다.

apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
  name: hpa-test
spec:
  minReplicas: 1  # 최소 replicas 개수
  maxReplicas: 5  # 최대 replicas 개수
  metrics:
  - resource:
      name: cpu  # HPA를 구성할 리소스(CPU, MEM 등)
      targetAverageUtilization: 30  # CPU 사용률이 30% 이상일 경우 생성
    type: Resource  # 리소스 타입 선언
  scaleTargetRef:  # 스케일 아웃할 타겟 설정
    apiVersion: apps/v1
    kind: Deployment  #  스케일 아웃할 타겟의 종류 (deployment, replicaset 등)
    name: deployment-hpa  #  스케일 아웃할 타겟의 네임

저의 경우 기존에 부하를 유발시키는 deployment-hpa 라는 이름을 가진 Deployment가 있었습니다. 위의 코드를 작성한 후 apply 하면 리소스에 따라 자동으로 스케일 아웃해주는 것을 확인할 수 있습니다.

 

deployment-hpa는 replicas를 2로 지정해둔 상태 입니다.

 

deployment-hpa에서 CPU 사용률 부하가 발생하며 아래와 같이 HPA로 인해 자동으로 스케일 아웃된것을 확인할 수 있었습니다. HPA 매니페스트 파일에 maxReplicas: 5를 설정 했으므로 최대 5개까지 증가 되었습니다.

 

반응형
반응형

 

  • kubespray "assertion: groups.etcd | length is not divvisibleby 2" 에러

kubespray 설치 후 ansible-playbook 명령어로 k8s 설치 진행 시 "assertion: groups.etcd | length is not divisibleby 2" 에러가 발생할 수 있습니다.

해당 에러는 아래 이미지와 같이 inventory.ini 파일에 지정한 etcd가 짝수인 경우에 발생할 수 있습니다.

kubespray/inventory/cluster/inventory.ini
에러를 유발 시키던 코드 : kubespray/roles/kubernetes/preinstall/tasks/0020-verify-settings.yml

 

이 에러를 해결하기 위해선 etcd를 홀수로 늘리기 위해 노드를 추가하거나, -e ignore_assert_errors=yes 옵션을 추가하여 해결할 수 있습니다. 저같은 경우 테스트용이기도 하고 노드를 더이상 추가 하기가 힘들어서 -e ignore_assert_errors=yes 옵션을 이용하여 해결 후 설치까지 확인 했습니다.

# ex
ansible-playbook -i kubespray/inventory/cluster/inventory.ini \
-v --become --become-user=root kubespray/cluster.yml -e ignore_assert_errors=yes

 

  • etcd는 홀수로 사용하는것을 권장 합니다.

짝수로 사용할 경우 스플릿 브레인(Split Brain) 현상이 발생하여 네트워크 단절로 인한 통신 장애 등 문제가 발생할 여지가 존재 합니다. 이러한 이유로 실제 서비스 환경에서는 etcd 클러스터를 홀수로 사용하는것이 좋습니다.

 

참고 사이트 : https://github.com/etcd-io/etcd/blob/master/Documentation/faq.md#what-is-failure-tolerance

 

반응형
반응형

 

쿠버네티스 볼륨 개념 1편 (emptyDir, hostPath) : https://nirsa.tistory.com/156?category=871751

 

  • 쿠버네티스 PV (Persistent Volume)와 PVC (persistent Volume Claim) 이란?

PV는 관리자에 의해 생성된 볼륨을 뜻하고, PVC는 사용자가 볼륨을 사용하기 위해 PV에 요청을 하게 됩니다. 컨테이너의 /var/log/test.log 디렉토리를 워커노드의 /tmp/log_backup 경로에 PVC와 PV 설정을 하면 아래와 같은 형태가 될 수 있습니다.

 

  • PV와 PVC의 Lifecycle

PV와 PVC는 크게 4가지 정도의 Lifecycle을 가집니다.

 

  • 1. 프로비저닝 (provisioning)

정적(static) 또는 동적(dynamic)의 pv를 생성하는 단계 이며 적어도 지금 작성하는 lifecycle인 프로비저닝에서는 pv 생성이라는 단어를 프로비저닝이라고 불러도 모두 같은 의미가 됩니다. pv 생성(프로비저닝)이 정상적으로 성공하면 Available 상태가 됩니다.

정적 프로비저닝은 매니페스트 파일 등을 통해 특정 용량을 가진 PV를 미리 생성해두고, 요청이 있을 시 미리 생성한 PV을 할당하여 사용하게 됩니다. 

동적 프로비저닝은 정적과는 다르게 사용자가 요청할 때 pv를 생성하여 할당하고, 사용자는 원하는 만큼의 용량을 생성해서 자유롭게 사용할 수 있습니다.

 

  • 2. 바인딩 (binding)

PV를 PVC에 연결시키는 단계 입니다. PVC는 사용자가 요청하는 볼륨을 PV에 요청하고 PV는 그에 맞는 볼륨이 있으면 할당해주게 되됩니다. 만약 PVC가 요청하는 볼륨이 PV에 없다면 해당 요청은 무한정 남아있게 되고, PVC가 요청하는 볼륨이 PV에 생성되면 그 요청은 받아들여져 할당해주게 됩니다.

PVC와 PV는 ClaimRef를 사용하는 1:1 관계 이며 바인딩이 정상적으로 완료될 경우 bound 상태가 됩니다.

 

  • 3. 사용 (using)

Pod는 PVC를 볼륨으로 사용 합니다. 클러스터는 PVC를 확인하여 바인딩된 PV를 찾고 해당 볼륨을 Pod에서 사용할 수 있도록 해줍니다.

만약 Pod가 사용중인 PVC를 삭제하려고 하면 Storage Object in Use Protection에 의해 삭제되지 않습니다. 만약 삭제 요청을 하였다면 Pod가 PVC를 사용하지 않을때까지 삭제 요청은 연기 됩니다.

 

  • 4. 회수 (Reclamiming)

PV는 기존에 사용했던 PVC가 아니더라도 다른 PVC로 재활용이 가능 합니다. 때문에 사용이 종료된 PVC를 삭제할 때, 사용했던 PV의 데이터를 어떻게 처리할지에 대한 설정을 하게 됩니다.

  1. Retain : PV의 데이터를 그대로 보존 합니다.
  2. Recycle : 재사용하게될 경우 기존의 PV 데이터들을 모두 삭제 후 재사용 합니다.
  3. Delete : 사용이 종료되면 해당 볼륨을 삭제 합니다.

 

  • 1. pv 생성
apiVersion: v1
kind: PersistentVolume
metadata:
  name: dev-pv
spec:
  capacity:
    storage: 2Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  storageClassName: manual
  persistentVolumeReclaimPolicy: Delete
  hostPath:
    path: /tmp/log_backup
  • spec.capacity.storage → 사용할 용량을 2GB로 설정 합니다.
  • spec.volumeMode → 볼륨을 Filesystem으로 사용 합니다.
  • spec.accessModes → 특정 접근 모드 선택 
    • ReadWriteOnce : 하나의 Pod 노드에서만 읽고 쓸 수 있습니다.
    • ReadOnlyMany : 여러개의 Pod 노드에서 읽을 수 있습니다.
    • ReadWriteMany : 여러개의 Pod 노드에서 읽고 쓸 수 있습니다.
  • spec.storageClassName → 스토리지 클래스를 지정하고 해당 클래스에 맞는 PVC와 연결 할 수 있습니다.
  • spec.persistentVolumeReclaimPolicy → Delete는 볼륨의 사용이 종료되면 볼륨을 삭제 합니다. 위의 회수 단계에서 설명한 필드 입니다.
  • hostPath → 노드에 저장되는 디렉토리를 설정 합니다.

 

생성후 kubectl get pv로 확인하면 Available 상태인것을 확인할 수 있습니다.

 

  • 2. PVC 생성
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: dev-pvc
spec:
  accessModes:
  - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 2Gi
  storageClassName: manual

 

PVC를 생성하고 kubectl get pv,pvc로 조회하면 PV와 PVC가 연결(binding) 되었으므로 상태가 Available 상태에서 Bound으로 변경 된것을 확인할 수 있습니다.

 

  • 3. PVC를 사용할 디플로이먼트 생성
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-deployment
  labels:
    app: test-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test-deployment
  template:
    metadata:
      labels:
        app: test-deployment
    spec:
      containers:
      - name: test-deployment
        image: nginx
        ports:
        - containerPort: 8080
        volumeMounts:
        - mountPath: "/var/log/test.log"
          name: dev-volume
      volumes:
      - name: dev-volume
        persistentVolumeClaim:
          claimName: dev-pvc
  • spec.template.spec.containers.volumeMounts → 볼륨 마운트할 컨테이너 안의 경로를 작성하고, 이 경로를 저장한 볼륨 마운트 정보를 dev-volume 이라는 이름으로 지정 합니다.
  • spec.template.spec.volumes → 위에 작성한 컨테이너에서 사용할 볼륨 마운트 이름(dev-volume)을 가져오고, 이 정보와 연결 요청을 보낼 pvc를 2번에서 생성한 dev-pvc로 지정 합니다.

 

 kubectl exec -it [pod name] bash을 입력하여 확인하면 정상적으로 test.log 디렉토리가 생성 되었으며 touch test1 파일을 생성하거나 app.log에 아무 데이터를 넣어 줍니다. Pod가 실행중인 노드로 이동하여 /tmp/log_backup 디렉토리 안에 정상적으로 test1 파일이 생성 된것을 확인할 수 있으며, app.log에 데이터가 입력되었을 경우 입력된 데이터도 확인될 것 입니다.

 

반응형

+ Recent posts