쿠버네티스 Config 변경을 위한 Kustomize
쿠버네티스 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 툴과 통합하여 사용이 될 수 있기 때문에, 쿠버네티스 사용자라면 알아둘 필요가 있는 도구라고 생각한다.