클라우드 컴퓨팅 & NoSQL/도커 & 쿠버네티스

쿠버네티스 Config 변경을 위한 Kustomize

Terry Cho 2022. 12. 29. 07:04

쿠버네티스 Config 변경을 위한 Kustomize

조대협 (http://bcho.tistory.com)

 

 

쿠버네티스 환경을 운영하면, 같은 설정을 다른 클러스터에 배포해야 하는 시나리오가 있다. 예를 들어서 애플리케이션을 개발/테스트/운영 (dev/stage/production)환경에 배포해야 하는데, 이 경우에 세부 설정이 조금씩 다를 수 있다. 이때 각 환경별로 파일을 만들면 관리가 어렵고 비효율적이기 때문에, 다른 세부 설정만 

이러한 문제를 해결하기 위한 도구들이 Kubernetes 배포 도구이다. 대표적인 도구로 Kustomize, Helm, Ksonnet

 

예를 들어 아래 그림과 같이 deployment를 정의한 YAML 파일이 있을때 전체 설정을 수정하지 않고 replica 수만 개발/테스트/운영 환경에 따라서 변경하고 싶을 경우 전체 파일을 환경별로 만드는 것 보다는 일부 설정만 변경할 수 있는 방법이 있는 것이 좋다.

템플릿 방식 (Helm)

첫번째 방식으로는 템플릿 방식이 있다.

Deployment YAML 파일을 만들때, 환경에 따라 변경되는 부분을 변수로 처리한 템플릿을 만든 후에, 환경별로 변수 값을 채워 넣는 방식이다.

이런 템플릿 방식을 사용하는 도구가 Helm이다. Helm에 대한 자세한 설명은 이글 https://bcho.tistory.com/1335 을 참고하기 바란다.

Helm은 템플릿을 사용하는 것 이외에도 패키지 매니저 (Linux의 RPM이나, node js npm 패키지)와 같은 기능이다. 템플릿내에서 if 문등을 이용하여 분기등 복잡한 처리가 가능하지만 상대적으로 러닝 커브가 높고, 디렉토리 구조가 복잡하다는 단점을 가지고 있어서 간단한 설정 변경에는 사용이 상대적으로 어렵다.

상속 방식(Kustomize)

다른 방식으로 객체지향형 프로그래밍 (OOP)에서 사용하는 상속(Inherit)의 개념을 사용하는 방식이 있다. 상속은 베이스 클래스에서 상속을 받아서 다른 부분만 상속받은 클래스에서 구현하는 개념을 YAML에 적용해보면 base YAML을 정의한 후에, 다른 변경할 부분만 상속받은 YAML에서 구현하는 방식이다. 

Kustomize가 이 방식을 사용한다. 

 

그러면 Kustomize가 어떻게 작동하는지 아래 그림을 보자 base로 deployment yaml을 만든 후에, base에서는 replica수가 5인데, 이를 상속 받아서 replica 수를 2개로 변경한다. Replica 2를 patch에 적용해서 이 patch와 base 파일을 merge하게 되면, replica 수만 변경할 수 있게 되는 것이다. 이때 patch에는 변경할 부분과, 그리고 변경할 리소스를 식별하기 위한 리소스 이름과 리소스 이름 (name)을 정의해야 한다. 

Kustomize

Kustomize를 사용하려면 먼저 디렉토리 구조를 이해해야 한다. 

보통 디렉토리 구조는 아래와 같은 구조를 취한다. 

오리지널 파일이 있는 디렉토리 (base)를 만든 후에, 각 환경별로 다른 디렉토리(dev)를 만들고 환경별 디렉토리마다 변경할 내용이 정의된 patch 파일을 작성한다. 

예를 들어 base/hpa.yaml을 다음과 같이 구현했다고 하자

 

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
   name: frontend-deployment-hpa
spec:
   scaleTargetRef:
     apiVersion: apps/v1
     kind: Deployment
     name: frontend-deployment
   minReplicas: 1
   maxReplicas: 5
   metrics:
   - type: Resource
   resource:
     name: cpu
     target:
       type: Utilization
       averageUtilization: 50



<코드 : ./base/hpa.yaml>

 

원본 HPA 파일에서 오토스케일의 minReplicas를 1, maxReplicas를 5로 했을때, dev 환경에서 이 값을 1,99 변경하고 싶으면 이 hpa 파일에 대한 patch를 아래와 같이 정의한다. 

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
 name: frontend-deployment-hpa
spec:
 minReplicas: 1
 maxReplicas: 99

<코드 : ./dev/hpa.yaml>

 

앞서 설명한대로 resource의 종류 “kind: HorizontalPodAutoscaler”와 이름 “name: frontend-deployment-hpa“을 정의한 후에, 변경할 부분 “minReplicas: 1 maxReplicas: 99 “ 만을 patch 파일에 적용한다.

 

다음 ./dev/kustomization.yaml 을 작성한다. 이 파일에는 parent 설정 (상속을 받을 오리지널 파일)의 디렉토리와, 내가 생성할 파일들의 목록을 정의한다.  



apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
 - ../base
patchesStrategicMerge:
#patches:
 - hpa.yaml
 - deployment.yaml

<코드 : ./dev/kustomization.yaml >

 

위의 파일은 ../base 디렉토리의 설정을 상속할것이고, ../base에 있는 파일들 중에서 hpa.yaml , deployment.yaml 파일만을 변경하겠다는 정의이다.

 

파일을 생성한 후에 ./dev 디렉토리에서

%kustomize build ./

명령을 실행하면, 다음과 같이 Patch를 적용하여 생성된 YAML을 화면에 출력해준다.

apiVersion: v1
kind: Service
metadata:
  name: frontend-service
spec:
  ports:
  - name: http
    port: 8080
  selector:
    app: frontend-deployment
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: frontend-deployment
  name: frontend-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: frontend-deployment
  template:
    metadata:
      labels:
        app: frontend-deployment
    spec:
      containers:
      - image: foo/bar:latest
        name: app
        ports:
        - containerPort: 8080
---
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: frontend-deployment-hpa
spec:
  maxReplicas: 99
  metrics:
  - type: Resource
  minReplicas: 1
  resource:
    name: cpu
    target:
      averageUtilization: 50
      type: Utilization
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: frontend-deployment

 

만약에 화면으로 출력하지 않고 바로 Kubernetes에 반영하고 싶으면

%kustomize build ./ | kubectl apply -f

 

아니면 kustomize가 kubectl 1.14부터 포함이 되었기 때문에, 아래와 같이 kubectl 명령을 바로 사용해도 된다. 

%kubectl apply -f ./

 

Kustomize는 상속의 개념을 이용한 Patch를 제공함으로써 template 방식보다 비교적 간편하다는 장점이 있다.  그러나 모호성도 존재한다.

예제 코드 출처 : https://github.com/kubernetes-sigs/kustomize/issues/173

예를 들어 아래와 같은 Service가 있다고 하자

 

# base/frontend.yaml
apiVersion: v1
kind: Service
metadata:
  name: frontend
spec:
  ports:
  - name: http 
    port: 80
  selector:
    app: frontend
  type: NodePort

 

다음과 같이 포트를 80에서 90으로 변경하는 오버레이(Overlay) 패치를 작성하여 적용하면

# overlay/port.yaml
apiVersion: v1
kind: Service
metadata:
  name: frontend
spec:
  ports:
  - name: http 
    port: 90

 

포트가 변경이 되는 것이 아니라 아래와 같이 90번 포트가 추가되어 버린다. 이유는 Service는 여러개의 Port 를 가질 수 있기 때문에, Overlay가 아니라 추가가되는 merge가 발생하게 된것이다. 

apiVersion: v1
kind: Service
metadata:
  name: frontend
spec:
  ports:
  - name: http
    port: 90
  - name: http
    port: 80
  selector:
    app: frontend
  type: NodePort

 

이런 경우에는 Patch에서 기존 포트를 아래와 같이 삭제하고 새 포트를 추가하도록 해주어야 한다. 

apiVersion: v1
kind: Service
metadata:
  name: frontend
spec:
  ports:
  - port: 80
    $patch: delete
  - name: http
    port: 90

 

이러한 모호성에도 불구하고 Kustomize는 Kubectl에 포함되면서 널리 사용되고 있으며 특히 argocd, skaffold, helm과 같은 다른 CI/CD 툴과 통합하여 사용이 될 수 있기 때문에, 쿠버네티스 사용자라면 알아둘 필요가 있는 도구라고 생각한다.