이번 글에서는 Kubernetes 리소스의 Raw 파일인 YAML 파일들을 관리하는 방법을 알아보려고 합니다. 사용자에 따라 YAML 파일을 관리하는 방법은 다양합니다. 리소스 별로 생성한 YAML 파일을 작업서버 내에 Application 별로 나눠놓거나, 배포 환경 별로 나눠놓는 등 기준을 가지고 분류하고 서버내의 스토리지에 저장하거나 원격 스토리지(git, cloud, external/internal NAS 등)에 저장합니다. 때로는 YAML파일들을 Application별로 Template화 하여 관리하기도하며, 한개의 YAML 파일에 여러개의 리소스를 정의하거나 Helm이나 자체적인 Template을 만들어서 사용하기도 합니다.
지금부터 다룰 Kustomize는 이런 YAML파일을 Customize하여 Template화 할 수 있는 편리한 도구입니다. 지금부터 Kustomize가 무엇이고, 어떻게 사용할 수 있는지 알아보도록 하겠습니다.
Kustomize 공식문서에 따르면 아래와 같이 소개하고 있습니다.
- Kustomize는 템플릿이 없는 방식으로 구성 파일을 커스터마이징 하는 데 도움이 됩니다.
- Kustomize는 커스터마이징을 더 쉽게 하기 위해 생성기(Generator)와 같은 여러 편리한 방법을 제공합니다.
- Kustomize는 패치(Patch)를 사용하여 기존 표준 구성 파일을 방해하지 않고 환경별 변경 사항을 도입합니다.
Kustomize는 템플릿 및 DSL(Domain Specific Language)이 없는 Kubernetes 리소스 구성을 커스터마이징할 수 있습니다. 위에서 이야기한 대로 템플릿이 없는 리소스 파일들의 일종의 템플릿화(실제로 템플릿이 존재하는 것은 아닙니다🧐)를 도와주는 도구라고 볼 수 있습니다. Kustomize는 템플릿이 없는 RAW YAML 파일을 여러 목적으로 커스터마이징할 수 있고, 이 과정에서 원본 YAML을 그대로 유지하고 사용할 수 있으며(약간의 수정이 필요한 부분이 있습니다) 이는 Kubernetes를 대상으로 합니다. 파일에 선언된다는 점에서 make
와 비슷하고 편집된 텍스트를 내보내는 점에서 sed
와 비슷합니다.
Application의 설정 내용을 수정하려면 sed 명령어(그 외 텍스트 수정을 할 수 있는 명령어)를 사용해서 변경해야 합니다. 구성되어 있는 내용이 간단한 Application이라면 이와 같은 방법으로 수정할 수 있지만, 구성 데이터가 더 많은, 더 큰 Application의 경우에는 수정/관리 하는 것이 매우 복잡해 질 수 있습니다. Test 프로젝트, Prod 프로젝트, 다른 클러스터의 다른 Prod 프로젝트 등 프로젝트별로 별도의 추가적인 Repository에 YAML manifest를 저장해서 관리할 수는 있지만, 관리하기가 복잡하고 손이 많이 가기 때문에 곧 관리 불가능해진다는 것을 알게 될 것입니다. Kustomize는 배포할 환경(프로젝트/클러스터/환경)을 기반으로 YAML manifest를 커스터마이징 하는데 효율적으로 사용할 수 있습니다.
Kustomize를 설치하는 방법은 간단합니다. 아래의 설치 command를 입력하면 됩니다.
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
sudo mv kustomize /usr/local/bin
Kubernetes 1.14버전부터는 kubectl에 built-in 기능으로 포함되어 있습니다.
위의 방법은 binary 설치방법이며, 그 외의 설치방법을 알고싶다면 이곳을 클릭하세요.
추가적으로 위의 방법은 ARM 아키텍처에서는 동작하지 않으니, 자세한 내용은 릴리즈 페이지를 참고하세요.
Kustomize는 기존 Application의 근원이 되는 부분인 base
와 base에 변경되는 사항을 정의하는 overlays
로 나뉘어 있습니다. 아래는 Kustomize의 디렉터리 트리구조입니다.
~/someApp
├── base
│ ├── deployment.yaml
│ ├── kustomization.yaml
│ └── service.yaml
└── overlays
├── development
│ ├── cpu_count.yaml
│ ├── kustomization.yaml
│ └── replica_count.yaml
└── production
├── cpu_count.yaml
├── kustomization.yaml
└── replica_count.yaml
base
디렉터리에는 YAML 리소스 파일(deployment, service, configmap 등)을 포함하고 있으며, 이 디렉터리에서 kustomization.yaml 파일을 생성하여 참조하는 리소스와 여기에 적용할 모든 사용자 정의내용(ex. 공통으로 적용할 Label 추가)를 선언해야 합니다.
overlay
디렉터리에는 base를 참조하고 수정하는 내용들을 패치(patch)라는 항목으로 정의한 kustomization.yaml 파일과, 패치에 적용할 실제 내용의 파일들이 포함되어 있습니다. overlays 하위에는 development, staging, production과 같은 구성(구성은 마음대로 정의할 수 있음)으로 디렉터리를 생성하여 관리할 수 있습니다.
기존의 Kubernetes Resource 파일을 Kustomize 형식으로 변경하는 예시와 함께 확인해 봅시다.
이 Application은 Red Hat Openshift Container Platform에서 구성하였습니다. 따라서 Kubernetes에 없는 리소스(ex. buildconfig.yaml, route.yaml 등)가 있을 수 있지만, kustomize를 설명하는데 큰 문제가 없으니 신경쓰지 않으셔도 됩니다.😀
~/coffee-shop
├── deployment.yaml
├── configmap.yaml
├── buildconfig.yaml
├── service.yaml
├── route.yaml
├── imagestream.yaml
└── sealed_secret.yaml
# ~/coffee-shop/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
app.openshift.io/connects-to: '["coffee-shop-database",{"apiVersion":"apps/v1","kind":"Deployment","name":"coffee-shop-database"},{"apiVersion":"serving.knative.dev/v1","kind":"Service","name":"barista"}]'
labels:
app.kubernetes.io/part-of: coffee-shop
app.openshift.io/runtime: quarkus
name: coffee-shop
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: coffee-shop
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
app: coffee-shop
spec:
containers:
- env:
- name: QUARKUS_DATASOURCE_USERNAME
valueFrom:
secretKeyRef:
key: quarkus.datasource.username
name: coffee-shop
- name: QUARKUS_DATASOURCE_DB_KIND
valueFrom:
secretKeyRef:
key: quarkus.datasource.db-kind
name: coffee-shop
- name: QUARKUS_DATASOURCE_JDBC_URL
valueFrom:
secretKeyRef:
key: quarkus.datasource.jdbc.url
name: coffee-shop
- name: QUARKUS_DATASOURCE_PASSWORD
valueFrom:
secretKeyRef:
key: quarkus.datasource.password
name: coffee-shop
- name: BARISTA_URL
valueFrom:
configMapKeyRef:
key: BARISTA_URL
name: coffee-shop
image: nexus-registry.apps.cluster.example.com/coffee-shop:prod-2021-11-16-07-26-46
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
httpGet:
path: /
port: 8080
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
name: coffee-shop
ports:
- containerPort: 8080
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /
port: 8080
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
requests:
cpu: 100m
memory: 512Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
terminationGracePeriodSeconds: 30
위의 Application을 develpment 환경과 production 환경으로 배포하기 위해 아래의 내용처럼 디렉터리를 구성하고 리소스 파일을 각 디렉터리에 옮깁니다.
- coffee-shop 하위에 base, overlays 디렉터리를 생성하고, overlay 하위에 development, production 디렉터리 생성
- base 디렉터리에 deployment.yaml, service.yaml, route.yaml, sealed_secret.yaml 파일을 이동.
- development 디렉터리에 buildconfig.yaml, imagestream.yaml, comfigmap.yaml 파일을 이동.
- production 디렉터리에 development 디렉터리에 이동한 configmap.yaml 파일을 복사.
완료하면 아래와 같습니다.
~/coffee-shop
├── base
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── route.yaml
│ └── sealed_secret.yaml
└── overlays
├── development
│ ├── buildconfig.yaml
│ ├── imagestream.yaml
│ └── configmap.yaml
└── production
└── configmap.yaml
kustomize.yaml 파일에서 관리할 수 있도록 기존 리소스 파일을 아래의 내용으로 수정합니다.
- kustomize.yaml에서 공통 label을 정의하기 위해 기존 base/deployment.yaml, base/service.yaml, base/route.yaml 파일 내 label
app: coffee-shop
을 제거합니다.- base/deployment.yaml 파일의
.spec.template.metadata
영역을 제거합니다.- base/deployment.yaml 파일의 image 부분을
<PATCH_ME>
로 변경합니다.- base/deployment.yaml 파일의 container env 부분을
envFrom
을 사용하여 configmap과 secret을 지정합니다.
완료하면 아래와 같습니다.(service.yaml과 route.yaml 파일은 app: coffee-shop 부분만 제거하면 되기 때문에 첨부하지 않았습니다.)
# ~/coffee-shop/base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
app.openshift.io/connects-to: '["coffee-shop-database",{"apiVersion":"apps/v1","kind":"Deployment","name":"coffee-shop-
database"},{"apiVersion":"serving.knative.dev/v1","kind":"Service","name":"bar
ista"}]'
labels:
app.kubernetes.io/component: coffee-shop
app.kubernetes.io/instance: coffee-shop
app.kubernetes.io/part-of: coffee-shop
app.openshift.io/runtime: quarkus
name: coffee-shop
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
spec:
containers:
- envFrom:
- configMapRef:
name: coffee-shop
- secretRef:
name: coffee-shop
image: <PATCH_ME>
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 3
httpGet:
path: /health
port: 8080
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
name: coffee-shop
ports:
- containerPort: 8778
protocol: TCP
- containerPort: 8080
protocol: TCP
- containerPort: 8443
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /health
port: 8080
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
requests:
cpu: 100m
memory: 384Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
terminationGracePeriodSeconds: 30
공통 Label을 적용하기 위한 base/kustomize.yaml 파일을 작성합니다.
- base 디렉터리 내 리소스를 참조하고
app: coffee-shop
을 공통 Label로 지정하는 kustomize.yaml 파일을 작성합니다.
완료하면 아래와 같습니다.
# ~/coffee-shop/base/kustomize.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./sealed_secret.yaml
- ./deployment.yaml
- ./service.yaml
- ./route.yaml
commonLabels:
app: coffee-shop
개발환경에 배포하기 위해 수정해야 하는 내용을 담는 리소스 파일 및 kustomize.yaml 파일을 overlays/development 디렉터리에 작성합니다.
- 개발환경에 적용해야 할 수정내용을
overlays/development/deployment-patches.yaml
파일에 정의합니다.
이 예제에서는 이미지를 개발용 이미지로 변경합니다.- configMapGenerator를 사용하기 위해 configmap.yaml 내의 내용을
configmap.env
파일을 생성하여 key=value 형식으로 작성하고, 기존 configmap.yaml 파일을 삭제합니다.
configmap은 kustomize로부터 생성됩니다.- overlays/development 디렉터리 내 리소스파일 및 deployment-patches 및 configmap.env 파일을 참조하는 kustomize.yaml 파일을 생성합니다.
완료하면 아래와 같습니다.
# deployment-patches.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: coffee-shop
spec:
template:
spec:
containers:
- name: coffee-shop
image: image-registry.openshift-image-registry.svc:5000/dev-coffeeshop/coffee-shop:dev-2021-11-16-07-26-46
# configmap.env
BARISTA_URL=http://barista.dev-coffeeshop.svc.cluster.local/processes
# overlays/development/kustomize.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- ../../base
resources:
- ./imagestream.yaml
- ./buildconfig.yaml
namespace: dev-coffeeshop
patches:
- ./deployment-patches.yaml
configMapGenerator:
- name: coffee-shop
envs:
- ./configmap.env
운영환경에 배포하기 위해 수정해야 하는 내용의 리소스 및 kustomize.yaml 파일도 개발환경과 같이 overlays/production 디렉터리에 작성합니다.
- 운영환경에 적용해야 할 수정내용을
overlays/production/deployment-patches.yaml
파일에 정의합니다.
이 예제에서는 이미지를 운영용 이미지로 변경합니다.- configMapGenerator를 사용하기 위해 configmap.yaml 내의 내용을
configmap.env
파일을 생성하여 key=value 형식으로 작성하고, 기존 configmap.yaml 파일을 삭제합니다.
configmap은 kustomize로부터 생성됩니다.- overlays/development 디렉터리 내 리소스파일 및 deployment-patches 및 configmap.env 파일을 참조하는 kustomize.yaml 파일을 생성합니다.
완료하면 아래와 같습니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: coffee-shop
spec:
template:
spec:
containers:
- name: coffee-shop
image: nexus-registry.apps.cluster.example.com/coffee-shop:prod-2021-11-16-07-26-46
# configmap.env
BARISTA_URL=http://barista.prod-coffeeshop.svc.cluster.local/processes
# overlays/production/kustomize.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- ../../base
namespace: prod-coffeeshop
patches:
- ./deployment-patches.yaml
configMapGenerator:
- name: coffee-shop
envs:
- ./configmap.env
위의 과정을 마치고 나면 아래와 같은 상태가 됩니다.
~/coffee-shop
├── base
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── route.yaml
│ ├── kustomize.yaml
│ └── sealed_secret.yaml
└── overlays
├── development
│ ├── buildconfig.yaml
│ ├── imagestream.yaml
│ ├── deployment-patches.yaml
│ ├── kustomize.yaml
│ └── configmap.env
└── production
├── deployment-patches.yaml
├── kustomize.yaml
└── configmap.env
Kustomize 파일을 작성하고 난 후, 확인 및 적용하려면 kustomize build
명령어를 사용합니다.
# Kustomize 파일 확인
# 배포할 환경의 디렉터리로 이동
$ cd ~/coffee-shop/overlays/development
$ kustomize build .
# Kustomize 파일 적용
# 배포할 환경의 디렉터리로 이동
$ cd ~/coffee-shop/overlays/development
$ kustomize build . | kubectl apply -f -
# Kustomize 파일로 적용된 리소스 제거
# 배포할 환경의 디렉터리로 이동
$ cd ~/coffee-shop/overlays/development
$ kustomize build . | kubectl delete -f -
Kustomize는 효율적인 도구임에는 분명하지만 Kubernetes 리소스를 관리하는 최고의 방법은 아닙니다. 언제나 그렇듯이 적용하려는 대상의 성격과 규모등을 파악 후 Kustomize로 관리하기 적절한지 판단해야 합니다. 소규모의 간단한 Application은 Kustomize 적용이 오히려 복잡할 수 있고, 개발한 application의 정식 출시로 인한 배포판을 만들 때에는 helm 같은 도구를 사용하는게 더 적합할 수 있기 때문입니다.
이 글은 Kustomize에 대한 대략적인 설명을 담았습니다. 추가적인 기능과 보다 더 자세한 내용을 필요로 하신다면 공식가이드 문서를 참고하시면 좋을 듯 합니다.
참고로 아래 링크에서는 Red Hat Openshift 상에서 Kustomize를 사용한 Gitops hands-on을 진행해보실 수 있습니다.
https://developers.redhat.com/courses/gitops/working-kustomize
작성하신 글 잘 봤습니다 감사합니다!
혹시 위에 진행하신 프로젝트 따로 깃허브로 볼 수 있을까요??