Kubbernetes Custom Controller를 만들었습니다.

18458 단어 Kubernetestech
이 글은 Kubernetes Advent Calendar 2020 22일째 되는 글이다.

개시하다


Kubbernetes에는 Pod를 수평으로 축소Horizontal Pod Autoscaler(이하 HPA)하는 자원이 있습니다.HPA는 매우 편리하며 노드의 규모Cluster Autoscaler와 조합해 사용하는 곳이 많죠.
하지만 이 HPA도 만능은 아니에요.팟과 노드 규모에 시간이 얼마나 걸리느냐에 따라 이른바 스파이크 방문 등 돌발적인 방문에 대응하기가 쉽지 않기 때문이다.이 경우 어떻게 해야 하는지, 특정 시간에 스파이크 방문이 발생할 수 있다는 것을 알았다면 평소보다 자원을 더 많이 준비했을 것이다.HPA로서는 스매시minReplicas가 안정적일 때보다 커지는 것을 막기 위한 것이라는 인상을 준다.다음은 이 대응을 Scheduled Scoling이라고 합니다.
그러나 상술minReplicas의 대응을 미리 늘리는 것도 문제다.그것은 원가적인 문제 때문에 스파이크가 발생하기 전에 Cluster에 적용하고 싶지만, 이를 위해 반드시 어떤 구조와 이런 점을 만들어야 한다.실현된 메커니즘 자체는 HDAminReplicas를 간단하게 업데이트하는 메커니즘만 있으면 된다.대충 설치하면 CronJob이 API를 직접 두드려 업데이트하는 구조를 생각해 낼 수 있다.
실제로 비슷한 일을 이루는 Kubbernetes의 Custom Controller가 이미 존재합니다.
  • amelbakry/kube-schedule-scaler: Kubernetes Controller which provides schedule scaling to Kubernetes deployments and other custom resources in the cluster
  • https://github.com/amelbakry/kube-schedule-scaler
  • lilic/kube-start-stop: Schedule Scaling of Kubernetes Resources
  • https://github.com/LiliC/kube-start-stop
  • 기다리면 같은 일이 이루어질 거야.
    그러나 GitOps를 실천하는 경우 Git에 놓인 manifest를 업데이트해야 하며, Cluster에서 API를 사용하여 업데이트하는 것만으로는 부족하다.이 동기에 대응할 수 있는 Custom Controller(당시)는 관측 범위를 찾지 못했다.이에 따라 자체 커스텀 컨트롤러를 제작해 깃옵스도 사용할 수 있는 스cheduled Scoling을 구현했다.

    scheduled-pod-autoscaler


    https://github.com/d-kuro/scheduled-pod-autoscaler
    두 개의 Custom Resource로 구성됩니다.
    친자 관계는 다음과 같다.
    $ kubectl tree scheduledpodautoscaler nginx
    NAMESPACE  NAME                             READY  REASON  AGE
    default    ScheduledPodAutoscaler/nginx     -              6m5s
    default    ├─HorizontalPodAutoscaler/nginx  -              6m5s
    default    ├─Schedule/test-1                -              6m4s
    default    ├─Schedule/test-2                -              6m4s
    default    └─Schedule/test-3                -              6m4s
    

    ScheduledPodAutoscaler

    ScheduledPodAutoscaler는 HPA로 싸인 커스텀 리소스다.ScheduledPodAutoscaler Controller는 리소스에서 일반 HPA를 사용합니다.
    여기에 정의된 HPA의 스펙은 Scheduled Sccalling을 실행하지 않을 때 사용됩니다.
    왜 HPA에 신선도를 유지해야 하는지를 말하자면 schedule-pod-autooscaller는 특정한 시간 안에 HPAmaxReplicas/minReplicas를 바꾸는 방법으로 Scheduled Scoling을 실현했다.Giit에서 HPA를 관리하는 manifest의 경우 Controller에서 Kubernetes API로만 HPA의 스펙을 변경했다면 Giit의 manifest는 변경되지 않았기 때문에 GitOps가 불편할 수 있습니다.HPA를 둘러싼 자원을 사용했기 때문에 HPA의 manifest 자체는 Git에서 관리되지 않고 API를 통해 HPA의 스펙을 변경하는 것도 문제없다.
    랩 HPA의 스펙v2beta2의 API을 사용할 수 있습니다.
    apiVersion: autoscaling.d-kuro.github.io/v1
    kind: ScheduledPodAutoscaler
    metadata:
      name: nginx
    spec:
      horizontalPodAutoscalerSpec:
        scaleTargetRef:
          apiVersion: apps/v1
          kind: Deployment
          name: nginx
        minReplicas: 3
        maxReplicas: 10
        metrics:
        - type: Resource
          resource:
            name: cpu
            target:
              type: Utilization
              averageUtilization: 70
    
    $ kubectl get spa # You can use spa as a short name of scheduledpodautoscaler.
    NAME    MINPODS   MAXPODS   STATUS      AGE
    nginx   3         10        Available   6m52s
    

    Schedule

    Schedule는 Scheduled Scoling을 정의하는 데 사용되는 Custom Resouce입니다.부모ScheduledPodAutoscaler에 대해 여러 개Schedule를 정의할 수 있다.ScheduledPodAutoscaler의 Controller 참조Schedule는 Scheduled Scoling의 시간이 되었을 때maxReplicas의 스펙트럼에 따라generate가 만든 HPA의minReplicas/Schedule를 고쳤다.이때 주의해야 할 것은 HPA의 replicas가 변경된 후 Pod가 실제로 시작되기 전에 시간이 걸린다는 것이다.따라서 스파이크가 발생하는 시간에 스cheduled Sccalling을 하지 말고 스파이크가 조금 여유를 가지도록 미리 스cheduled Scoling을 하는 것이 좋다.
    여러 개Schedule의 시간 범위가 충돌하는 경우 각각의 Schedule가 정의한 maxReplicas/minReplicas의 최대치를 사용한다.
    $ kubectl get schedule -o wide
    NAME     REFERENCE   TYPE      STARTTIME          ENDTIME            STARTDAYOFWEEK   ENDDAYOFWEEK   MINPODS   MAXPODS   STATUS      AGE
    test-1   nginx       Weekly    20:10              20:15              Saturday         Saturday       1         1         Available   4m49s
    test-2   nginx       Daily     20:20              20:25                                              2         2         Available   4m49s
    test-3   nginx       OneShot   2020-10-31T20:30   2020-10-31T20:35          
    
    Schedule는 3개의 Schedule Type을 지원합니다.

    type: Weekly


    시간을 HH:mm 형식으로 설명하고 요일을 지정합니다.
    apiVersion: autoscaling.d-kuro.github.io/v1
    kind: Schedule
    metadata:
      name: nginx-push-notification
    spec:
      scaleTargetRef:
        apiVersion: autoscaling.d-kuro.github.io/v1
        kind: ScheduledPodAutoscaler
        name: nginx
      minReplicas: 10
      maxReplicas: 20
      type: Weekly
      startDayOfWeek: Monday
      startTime: "11:50"
      endDayOfWeek: Wednesday
      endTime: "13:00"
      timeZone: Asia/Tokyo
    

    type: Daily

    HH:mm의 형식으로 시간을 기술하다.
    apiVersion: autoscaling.d-kuro.github.io/v1
    kind: Schedule
    metadata:
      name: nginx-push-notification
    spec:
      scaleTargetRef:
        apiVersion: autoscaling.d-kuro.github.io/v1
        kind: ScheduledPodAutoscaler
        name: nginx
      minReplicas: 10
      maxReplicas: 20
      type: Daily
      startTime: "11:50"
      endTime: "13:00"
      timeZone: Asia/Tokyo
    

    type: OneShot

    yyyy-MM-ddTHH:mm의 형식으로 시간을 기술하다.
    apiVersion: autoscaling.d-kuro.github.io/v1
    kind: Schedule
    metadata:
      name: nginx-push-notification
    spec:
      scaleTargetRef:
        apiVersion: autoscaling.d-kuro.github.io/v1
        kind: ScheduledPodAutoscaler
        name: nginx
      minReplicas: 10
      maxReplicas: 20
      type: OneShot
      startTime: "2020-09-01T10:00"
      endTime: "2020-09-10T19:00"
      timeZone: Asia/Tokyo
    

    Install


    다음 명령을 사용하여 설치할 수 있습니다.
    # Kubernetes v1.16+
    $ kubectl apply -f https://raw.githubusercontent.com/d-kuro/scheduled-pod-autoscaler/v0.0.3/manifests/install/install.yaml
    
    # Kubernetes < v1.16
    $ kubectl apply -f https://raw.githubusercontent.com/d-kuro/scheduled-pod-autoscaler/v0.0.3/manifests/install/legacy/install.yaml
    
    기타 상세한 API 스펙과 export의metrics 등은 README를 참조하십시오.

    조금 안쪽이면...


    schedule-pod-autooscaller는 kubebuilder로 제작되었습니다.
    kubebuilder를 사용하여 Custom Controller를 만드는 방법@zoetrope창조하고 배우는 Kubilder 아주 좋아요. 꼭 참고하세요.
    https://zoetrope.github.io/kubebuilder-training/

    Controller


    schedule-pod-autooscaller에서 이동하는 Controller는 ScheduledPodAutoscaler의 Controller와 Schedule의 Controller 두 개가 있다.기본적으로 주 논리는 ScheduledPodAutoscaler의 Controller 측면쓰여 있다에 있다.
    그렇다면Schedule의 Controller는 무엇을 하고 있을까요?.spec.scaleTargetRef는 지정된 부모ScheduledPodAutoscaler와의 친자관계owner Reference 부여를 표현하기 위해서입니다.여기 주어진 ownerReference색인 추가, ScheduledPodAutoscaler의 Controller에서 아이Schedule를 모을 때 사용합니다.나는 개인적으로 이곳의 처리가 매우 마음에 든다. 분명히 일반 자원ownerReference이 아닌데 나중에 지불하면 어떻고, 게다가 ownerReference하면 부모를 없앨 때ScheduledPodAutoscaler일 때 아이Schedule도 소장되기 때문에 별로 좋지 않다.만약 누가 이렇게 하는 것이 비교적 좋다는 것을 알았다면 나는 매우 기뻤을 것이다.

    CRD용 API Version


    설치의 예를 보면 Kubbernetes의version은 두 가지 설치 방법을 따로 제공했다.
    # Kubernetes v1.16+
    $ kubectl apply -f https://raw.githubusercontent.com/d-kuro/scheduled-pod-autoscaler/v0.0.3/manifests/install/install.yaml
    
    # Kubernetes < v1.16
    $ kubectl apply -f https://raw.githubusercontent.com/d-kuro/scheduled-pod-autoscaler/v0.0.3/manifests/install/legacy/install.yaml
    
    왜 두 가지를 제공했을까.16 CRD에서 GA가 진행돼 API version이 달라졌기 때문이다.
    # Kubernetes v1.16+
    apiVersion: apiextensions.k8s.io/v1
    kind: CustomResourceDefinition
    ...
    
    # Kubernetes < v1.16
    apiVersion: apiextensions.k8s.io/v1beta1
    kind: CustomResourceDefinition
    ...
    
    CRD 등 manifest는 List 도구를 사용하여generate를 진행하는데, 이 버전에 따라generate의 manifest의 API version이 달라진다.그래서 controller-gen 저는generate manifest에 있어요.
    Kubbernetes에 업로드된 버젼도 약 3개월에 한 번씩 업데이트되고 각종 클라우드 공급자가 지원하는 버젼도 편차가 있기 때문에 Custom Controller를 쓸 때 어느 버젼을 지원하는지 주의해야 한다. 정말 쉽지 않다.그렇습니다.(v1.16 이하 버전의 지원을 끊고 싶습니다)

    향후


    기본적으로 하고 싶었던 일이 이뤄졌기 때문에 잦은 추가 기능을 한다는 점은 별로 고려하지 않았지만, 굳이 말하자면 스틸 투 제로를 지원해주면 좋겠다고 생각했다.Sciele to Zero가 지원되면 야간 등 특정 시간에 리플릭스를 0으로 설정해 비용 절감 등을 할 수 있다.
    Scale to Zero를 할 수 있다면 좋겠지만 왜 움츠러들었을까
    schedule-pod-autooscaller의 구조는generate의 HPAmaxReplicas/minReplicas를 제어하여ScheduledScoling을 실현하는 것이다.사실 HPA 자체 Sciele to Zero의 지원이 알파에서 피처 게이트를 사용하지 않으면 사용할 수 없기 때문이다.
    HPA의 Sciele to Zero의 KEP:
    두 가지 버전 사용
    따라서 현재는 HPA를 사용한 상태에서 리플릭스를 0으로 설정할 수 없다.그렇다면 어떻게 해야 할까. Scalle to Zero Scheduled Scarling의 경우 일반 HPA를 삭제하고 직접 Scare API를 사용해 0으로 만들고, Scheduled Scaring이 끝나면 HPA를 다시 일반 반환하는 등의 실현은 쉽게 생각할 수 있지만, 복잡화도 그다지 예쁘지 않다.좋은 생각이 있는 사람이 나에게 알려주면 나는 매우 기쁠 것이다.(이 블로그는 이것을 말하고 싶다.)
    기타 기능 추가 요구사항과 버그의 보고 등이 지아이허브 이슈에 보고되면 반응할 것으로 보인다.

    좋은 웹페이지 즐겨찾기