Kustomize로 K8S 리소스 관리하기

hojlee·2021년 12월 21일
5

시작하기 전에

이번 글에서는 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 공식문서에 따르면 아래와 같이 소개하고 있습니다.

  • 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 설치

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 구조

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 : kustomization + resources

base 디렉터리에는 YAML 리소스 파일(deployment, service, configmap 등)을 포함하고 있으며, 이 디렉터리에서 kustomization.yaml 파일을 생성하여 참조하는 리소스와 여기에 적용할 모든 사용자 정의내용(ex. 공통으로 적용할 Label 추가)를 선언해야 합니다.

👉🏻 overlays : kustomization + patches + 기타 resources

overlay 디렉터리에는 base를 참조하고 수정하는 내용들을 패치(patch)라는 항목으로 정의한 kustomization.yaml 파일과, 패치에 적용할 실제 내용의 파일들이 포함되어 있습니다. overlays 하위에는 development, staging, production과 같은 구성(구성은 마음대로 정의할 수 있음)으로 디렉터리를 생성하여 관리할 수 있습니다.

Kustomize 적용해보자!

기존의 Kubernetes Resource 파일을 Kustomize 형식으로 변경하는 예시와 함께 확인해 봅시다.

기존 Application

이 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

Kustomize를 위한 디렉터리 구성 및 리소스 파일 이동

위의 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

Kustomization 파일 작성 - base

공통 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

Kustomization 파일 작성 - overlays/development

개발환경에 배포하기 위해 수정해야 하는 내용을 담는 리소스 파일 및 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

Kustomization 파일 작성 - overlays/production

운영환경에 배포하기 위해 수정해야 하는 내용의 리소스 및 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

Kustomize 구성으로 변경 후의 Application

위의 과정을 마치고 나면 아래와 같은 상태가 됩니다.

~/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 파일을 작성하고 난 후, 확인 및 적용하려면 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

참고한 문서들

profile
홎리몰리 과카몰리

2개의 댓글

작성하신 글 잘 봤습니다 감사합니다!
혹시 위에 진행하신 프로젝트 따로 깃허브로 볼 수 있을까요??

1개의 답글