Freesunny

간단하게 nginx 배포하기

Kubernetes

클러스터 내에 파드의 통신을 확인할때 명세 없이 커맨드 만으로 nginx 를 배포하는 방법이다.

os가 debian 이라서 배포후 필요한 패키지는 apt 로 설치해서 사용하면 된다.

 

$ kubectl create deployment nginx --image=nginx -n namespace

Cluster Overprovisioning

Kubernetes

현재 운영 중인 사이트는 HPA(Horizontal Pod Autoscaler) 통해서 파드를 오토스케일링 하는데,

파드가 스케일 아웃을 할 때, 필요한 자원이 없을 경우에는 CA(Cluster Autoscaler)를 통해서, 노드를 추가 하게 된다.

 

그런데, CA를 통해서 노드가 추가 될때, 노드가 바로 추가되지 않기 때문에,

노드가 추가되고 파드가 생성될 때 까지는 사이트 속도가 떨어지는 문제가 발생하였다.

HPA의 기준(CPU사용율)을 변경하거나, 파드나 노드의 갯수를 매우 넉넉하게 설정을 해 놓으면 문제는 없겠지만

좀 더 스마트 한 방법을 찾아 보기로 했다.

 

처음에는 상시적으로 여유 노드를 한 개 정도 더 확보하고 있는 방법을 생각하였으나, 

자원을 낭비 되는 감이도 있고, 관련 문서도 찾을 수가 없었는데, Overprovioning 이라는것을 발견하여 적용해 보기로 하였다.

 

 

 

개요

출처 : https://medium.com/scout24-engineering

  • 일정 자원을 가진 pod(더미 파드)를 일정 개수 상시적으로 띄워 놓는다.
  • pod 의 scale out 이 우선적으로 더미 파드를 사용하여, scale out 을 완료한다. (pod 의 priority = 0, dumy_pod = -1)
  • pod 의 scale out 으로 자원을 뺏기게 되면, dumy_pod 를 지정된 수량을 맞추기 위해서 생성한다. (이 과정에서 노드가 필요할 경우 CA를 통해 노드가 추가됨)  

참고 사이트 #1 : https://medium.com/scout24-engineering/cluster-overprovisiong-in-kubernetes-79433cb3ed0e

참고 사이트 #2 : https://kurtmadel.com/posts/cicd-with-kubernetes/just-in-time-autoscaling-for-jenkins-agents-with-kubernetes/

FAQ : https://medium.com/scout24-engineering/cluster-overprovisiong-in-kubernetes-79433cb3ed0e

 

 

 

설치 (EKS 환경에 셋팅하였음)

 

<RBAC-configs.yaml>

---
kind: ServiceAccount
apiVersion: v1
metadata:
  name: cluster-proportional-autoscaler
  namespace: kube-system
---
kind: ClusterRole
metadata:
  name: cluster-proportional-autoscaler
rules:
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["list", "watch"]
  - apiGroups: [""]
    resources: ["replicationcontrollers/scale"]
    verbs: ["get", "update"]
  - apiGroups: ["extensions","apps"]
    resources: ["deployments/scale", "replicasets/scale"]
    verbs: ["get", "update"]
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["get", "create"]
---
kind: ClusterRoleBinding
metadata:
  name: cluster-proportional-autoscaler
subjects:
  - kind: ServiceAccount
    name: cluster-proportional-autoscaler
    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: cluster-proportional-autoscaler

 

<cluster-proportional-autoscaler.yaml>

---
kind: ConfigMap
apiVersion: v1
metadata:
  name: overprovisioning
  namespace: kube-system
data:
  linear: |-
    { 
      "coresPerReplica"12
    }
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: overprovisioning-autoscaler
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: overprovisioning-autoscaler
  template:
    metadata:
      labels:
        app: overprovisioning-autoscaler
    spec:
      containers:
        - image: k8s.gcr.io/cluster-proportional-autoscaler-amd64:1.1.2
          name: autoscaler
          command:
            - /cluster-proportional-autoscaler
            - --namespace=kube-system
            - --configmap=overprovisioning
            - --target=deployment/overprovisioning
            - --logtostderr=true
            - --v=2
      serviceAccountName: cluster-proportional-autoscaler
 
 
  • 더미 파드(deployment/overprovisioning) 의 수량을 조절하는 autocaler 설정
  • coresPerReplica : 12 > Core 12당 한 개씩 더미 파드를 생성 (사용사 설정에 맞게 수정이 필요함)

<k8s-overprovisioning.yaml>

---
apiVersion: scheduling.k8s.io/v1beta1
kind: PriorityClass
metadata:
  name: overprovisioning
value: -1
globalDefault: false
description: "Priority class used by overprovisioning."
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: overprovisioning
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      run: overprovisioning
  template:
    metadata:
      labels:
        run: overprovisioning
    spec:
      priorityClassName: overprovisioning
      containers:
      - name: reserve-resources
        image: k8s.gcr.io/pause
        resources:
          requests:
            cpu: 2500m
            memory: 2560Mi

더미 파드의 리소스 설정 : CPU 2.5 Core, Memory 2.5GB

 

<CA 설정> 

CA 아래의 설정을 추가한다.

  • Priority -1 인 파드의 요청에도 노드 증설을 처리시키는 옵션 (기본값: 0)
  • 현재 노드그룹은 2개로 standard-workers(Ondemand 2 대) 와 sport-workers(Spot 2 대)를 사용 이다.
  • Ondemand  는 Max 가 2대 이기 때문에 자원이 부족할 경우에는 sport-workers (Spot 인스턴스)만 스케일 아웃 된다.

 

동작 확인

<overprovisioning 작동 상태>

  • 노드 가 증가되면 합산되는 코어도 늘어나므로, overprovisioning pod 갯수도 증가할수 있으므로, 사용자 환경에 맞도록 설정이 필요함

 

 

Inter-Pod Affinity 설정 추가

윗 단계까지 적용하고, 반나절 동안 모니터링 해 보았는데, 문제를 발견하였다.

  • overprovisioning pod 가 여러 노드 분산되어 있어, 필요한 노드 수보다 더 많이 사용하게 되는 것을 발견하였다.
  • 노드는 8 Core 이고, overprovisioning pod 의 CPU 요구량은 2.5 이다.
  • overprovisioning pod 가 5개 실행되고 있는데, 3개의 노드를 사용하고 있다. (3개 모두 overprovisioning pod 만 실행 중)
  • 2 개의 노드만 사용하면 되는 상황인데, 3 대를 사용하고 있으니, 아무리 Spot Instance 이지만 그대로 둘 수 없다.

아래의 설정을 deployment/overprovisioing 에 추가한다.

Inter-Pod Affintiy 설정

  • pod 라벨이 run=overprovisioning 이면 가급적 같은 호스트네임에 배치해라.

최종적인 k8s-overprovisiong.yaml

<k8s-overprovisioning.yaml>

---
apiVersion: scheduling.k8s.io/v1beta1
kind: PriorityClass
metadata:
  name: overprovisioning
value: -1
globalDefault: false
description: "Priority class used by overprovisioning."
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: overprovisioning
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      run: overprovisioning
  template:
    metadata:
      labels:
        run: overprovisioning
    spec:
      affinity:
        podAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: run
                  operator: In
                  values:
                  - overprovisioning
              topologyKey: kubernetes.io/hostname
            weight: 100
      priorityClassName: overprovisioning
      containers:
      - name: reserve-resources
        image: k8s.gcr.io/pause
        resources:
          requests:
            cpu: 2500m
            memory: 2560Mi
 

 

kubectl 자동 완성

Kubernetes

# bash

source <(kubectl completion bash) # bash-completion 패키지를 먼저 설치한 후, bash의 자동 완성을 현재 셸에 설정한다
echo "source <(kubectl completion bash)" >> ~/.bashrc # 자동 완성을 bash 셸에 영구적으로 추가한다

 

# zsh

source <(kubectl completion zsh)  # 현재 셸에 zsh의 자동 완성 설정
echo "if [ $commands[kubectl] ]; then source <(kubectl completion zsh); fi" >> ~/.zshrc # 자동 완성을 zsh 셸에 영구적으로 추가한다.

 

 

참고 링크 : https://kubernetes.io/ko/docs/reference/kubectl/cheatsheet/

 

kubectl 치트 시트

 

kubernetes.io

실행되고 있는 pod 를 node 기준으로 sort 하여 보고 싶을 때

Kubernetes

실행되고 있는 pod 를 node 기준으로 sort 하여 보고 싶을 때

 $ kubectl get pods -n <namespace> -o wide --sort-by=.spec.nodeName

 

kubernetes 노드 변경

Kubernetes

한대의 노드가 정상적이지 않은 것 같아서 새로운 노드를 추가하고 문제있는 노드를 제거 하였다.

 

AWS를 사용하고 있고, 오토스케일링 그룹에 속해있는 노드라서, 

오토스케일링 그룹에 신규 인스턴스가 추가 되도록 Desired Capacity 를 추가한다.

 

<추가된 인스턴스 상태 >

$ kubectl get nodes
ip-172-31-16-133.ap-northeast-2.compute.internal   Ready    <none>   16m   v1.12.7
ip-172-31-24-205.ap-northeast-2.compute.internal   Ready    <none>   82d   v1.12.7
ip-172-31-33-98.ap-northeast-2.compute.internal    Ready    <none>   27s   v1.12.7
ip-172-31-42-90.ap-northeast-2.compute.internal    Ready    <none>   82d   v1.12.7
ip-172-31-47-233.ap-northeast-2.compute.internal   Ready    <none>   16m   v1.12.7

 

 

문제 있는 노드(ip-172-31-42-90.ap-northeast-2.compute.internal)가 스케쥴링 되지 않도록 설정

$ kubectl cordon ip-172-31-42-90.ap-northeast-2.compute.internal
node/ip-172-31-42-90.ap-northeast-2.compute.internal cordoned

$ kubcectl get nodes                                           
NAME                                               STATUS                     ROLES    AGE     VERSION
ip-172-31-16-133.ap-northeast-2.compute.internal   Ready                      <none>   24m     v1.12.7
ip-172-31-24-205.ap-northeast-2.compute.internal   Ready                      <none>   82d     v1.12.7
ip-172-31-33-98.ap-northeast-2.compute.internal    Ready                      <none>   8m24s   v1.12.7
ip-172-31-42-90.ap-northeast-2.compute.internal    Ready,SchedulingDisabled   <none>   82d     v1.12.7
ip-172-31-47-233.ap-northeast-2.compute.internal   Ready                      <none>   24m     v1.12.7

 

 

문제 있는 노드 제거

$ kubectl drain ip-172-31-42-90.ap-northeast-2.compute.internal --ignore-daemonsets --delete-local-data
node/ip-172-31-42-90.ap-northeast-2.compute.internal already cordoned
WARNING: Ignoring DaemonSet-managed pods: aws-node-bjrrv, kube-proxy-stgz4, prometheus-node-exporter-lt9ls; 
Deleting pods with local storage: metrics-server-7fbd9b8589-qjkvg, monitoring-influxdb-5c5bf4949d-fshbn

 

오토스케링링 그룹에서 문제 있는 노드(인스턴스)를 제거 (인스턴스가 제거 되고, 새로운 인스턴스가 추가됨)

 

인스턴스 삭제

 

오토 스케일링 Desired Capacity 원래대로 축소

nodeAffinity 를 이용하여 pod 를 원하는 노드에 배포하기

Kubernetes

노드에 설정된 label 을 이용하여, 원하는 노드에 pod를 배포할 수 있다.

아래의 예제는 kube-system 네임스페이스 안에 cluster-autoscaler 를 (반드시) Spot 노드가 아닌 OnDemand 노드에 배포하는 설정이다.

(Spot, OnDemand 노드의 구분은 Spot : lifecycle=EC2Spot, OnDemand : lifecycle=OnDemand) 

## spec.template.spec ##
affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: lifecycle
          operator: In
          values:
          - OnDemand

Service 재시작 하기

Kubernetes

아래의 명령으로 Service 를 재시작할 수 있다.

# kubectl get svc <service_name> -n <namespace> -o yaml | kubectl replace --force -f-

Pod 재시작 하기

Kubernetes

아래의 명령으로 pod 를 재시작할 수 있다.

# kubectl get pod <pod_name> -n <namespace> -o yaml | kubectl replace --force -f-

# 예)
# kubectl get pod heapster-c84bf57d9-j5p5q -n kube-system -o yaml | kubectl replace --force -f-