본문 바로가기
Kubernetes

Cluster Overprovisioning

by freesunny 2019. 11. 13.

현재 운영 중인 사이트는 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