본문 바로가기
사이드 프로젝트

[CI/CD 프로젝트] Helm 구조와 Helm Chart 생성 방법

by 간장공장공차장 2024. 11. 20.
반응형

Helm이란?

Helm은 Kubernetes 애플리케이션을 관리하기 위한 패키지 매니저이다. Chart라는 패키지를 통해 애플리케이션 배포, 관리, 업그레이드를 효율적으로 처리할 수 있다.

  • Helm의 필요성
  • Kubernetes 리소스의 수동 관리 복잡도를 줄이고, 여러 리소스를 하나의 Chart로 관리가 가능해진다.
  • Helm의 구성 요소
    • Chart: Kubernetes 애플리케이션을 정의하는 템플릿 파일 모음. 기동되기 위해 필요한 모든 리소스들이 포함되어 있다. (Deployment, Service 등..)
    • Release: Helm Chart를 이용해 Kubernetes 클러스터에 배포된 인스턴스.
    • Repository: Helm Chart를 저장하고 공유할 수 있는 저장소.

Helm Chart 구조

  • 디렉토리 구조
    mychart/ 
    ├── Chart.yaml 
    ├── values.yaml 
    ├── charts/ 
    ├── templates/ 
    └── .helmignore

파일 형식

  • Chart.yaml

Helm Chart의 메타 데이터와 설정을 정의하는 파일이다.

따라서 이름, 버전 정보, dependency 등과 같은 정보가 포함된다.

# Chart.yaml
apiVersion: The chart API version (required)
name: The name of the chart (required)
version: A SemVer 2 version (required)
kubeVersion: A SemVer range of compatible Kubernetes versions (optional)
description: A single-sentence description of this project (optional)
type: The type of the chart (optional)
keywords:
  - A list of keywords about this project (optional)
home: The URL of this projects home page (optional)
sources:
  - A list of URLs to source code for this project (optional)
dependencies: # A list of the chart requirements (optional)
  - name: The name of the chart (nginx)
    version: The version of the chart ("1.2.3")
    repository: (optional) The repository URL ("https://example.com/charts") or alias ("@repo-name")
    condition: (optional) A yaml path that resolves to a boolean, used for enabling/disabling charts (e.g. subchart1.enabled )
    tags: # (optional)
      - Tags can be used to group charts for enabling/disabling together
    import-values: # (optional)
      - ImportValues holds the mapping of source values to parent key to be imported. Each item can be a string or pair of child/parent sublist items.
    alias: (optional) Alias to be used for the chart. Useful when you have to add the same chart multiple times
maintainers: # (optional)
  - name: The maintainers name (required for each maintainer)
    email: The maintainers email (optional for each maintainer)
    url: A URL for the maintainer (optional for each maintainer)
icon: A URL to an SVG or PNG image to be used as an icon (optional).
appVersion: The version of the app that this contains (optional). Needn't be SemVer. Quotes recommended.
deprecated: Whether this chart is deprecated (optional, boolean)
annotations:
  example: A list of annotations keyed by name (optional).

이후 repository를 추가하고자 하면, 아래와 같이 추가 하면 된다.

helm repo add fantastic-charts https://charts.helm.sh/incubator
  • template 폴더

Kubernetes 리소스 템플릿 파일들을 포함하는 디렉토리이다. Helm은 Chart를 배포할 때 이 파일들을 사용해 설정을 기반으로 실제 Kubernetes 리소스 파일을 생성한다.

여기서는 변수를 동적으로 설정한다. 말 그대로 해당 파일이 템플릿이 되고, values.yaml 파일을 통해 커스터마이징이 가능하다.

# template/ReplicationController.yaml
apiVersion: v1
kind: ReplicationController
metadata:
  name: deis-database
  namespace: deis
  labels:
    app.kubernetes.io/managed-by: deis
spec:
  replicas: 1
  selector:
    app.kubernetes.io/name: deis-database
  template:
    metadata:
      labels:
        app.kubernetes.io/name: deis-database
    spec:
      serviceAccount: deis-database
      containers:
        - name: deis-database
          image: {{ .Values.imageRegistry }}/postgres:{{ .Values.dockerTag }}
          imagePullPolicy: {{ .Values.pullPolicy }}
          ports:
            - containerPort: 5432
          env:
            - name: DATABASE_STORAGE
              value: {{ default "minio" .Values.storage }}
  • values.yaml

변수에 대한 값을 입력하는 파일이다. 공식 레파지토리/오픈소스에서 다운받은 helm파일에서 아래 값을 조정하면 내 환경에 맞는 설정으로 운영할 수 있다.

# values.yaml
imageRegistry: myregistry.io     
dockerTag: "1.0.0"              
pullPolicy: IfNotPresent       
storage: "minio"     
  • charts/

helm charts에는 다른 여러 charts에 종속될 수 있다. 따라서 charts/ 하위 폴더로 이러한 의존성을 관리할 수 있다.

dependencies:
  - name: apache
    version: 1.2.3
    repository: https://example.com/charts
  - name: mysql
    version: 3.2.1
    repository: https://another.example.com/charts

아래 명령어를 수행하면 지정된 차트를 charts 하위 폴더로 다운한다.

helm dependency update
  • _helpers.tpl

values와 유사하게 변수를 저장하는 파일이지만, 여러 telmplate하위 항목의 _helpers.tpl을 가져올 수 있어 공통된 템플릿 코드를 정의하기에 적합하다. 또한, 복잡한 로직(문자열 조작, 조건부 논리) 를 처리할 수 있어 helm의 재사용성을 높여준다.

{{/*
Generate the full name of the release.
*/}}
{{- define "hellospring.fullname" -}}
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Generate the name of the application.
*/}}
{{- define "hellospring.name" -}}
{{- .Chart.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}

Helm 과 Kustomize

앞서 살펴보았던 kustomzie와 마찬가지로, 모두 어플리케이션을 선언적으로 관리하는 도구이다. 또한 두가지 모두 patchs 와 values를 통해서 커스터마이징이 가능하다.

그렇다면 어떤 상황에서 helm을 선택할까?

  • 패키지 관리 및 재사용성: Chart를 통해서 재사용 가능한 구성으로 다양한 환경에 쉽게 배포할 수 있다.
  • 복잡한 애플리케이션 구성 지원: Helm Chart는 템플릿화를 통해 복잡한 애플리케이션 구성을 보다 쉽게 관리할 수 있도록 도와줍니다. 여러 리소스와 의존성을 가진 애플리케이션을 한 번에 구성하여 배포할 수 있습니다.
  • 커뮤니티 지원: 공식 차트 저장소뿐만 아니라 다양한 오픈소스 커뮤니티에서 유지보수하는 차트들이 많아 쉽게 활용할 수 있다. 어렵게 설치 과정을 거쳐 리소스를 생성하지 않고도 이미 제공되는 charts를 통해서 argocd와 같은 툴을 간단하게 설치할 수 있다. (가장 큼)
  • GitOps와의 호환성: Argo CD는 helm을 지원하여 용이하게 배포를 자동화할 수 있다. 참고로 ArgoCD는 kustomize도 지원한다.

Kustomize는 쿠버네티스 오브젝트의 선언적 관리를 수행할 수 있게 도와준다.

  • configmap, secret과 같은 오브젝트를 선언적으로 생성
  • patch를 통해 환경별 커스터마이징이 가능하다.

실습

💡helm을 통해서 helm charts를 생성해보고, argocd를 쉽게 패키지를 설치하고, values.yaml을 통해서 커스터마이징 해본다.

ArgoCD 설치

  • argocd cli 명령어 설치
curl -sSL https://github.com/argoproj/argo-cd/releases/download/v2.12.6/argocd-linux-amd64 -o argocd
chmod +x argocd
sudo mv argocd /usr/local/bin/

이후 아래와 같이 정상 설치가 된 것을 볼 수 있다.

  • helm 설치
curl -sSL https://get.helm.sh/helm-v3.16.2-linux-amd64.tar.gz | tar -xz
sudo mv linux-amd64/helm /usr/local/bin/helm
  • helm repo 추가
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
helm search repo argocd

아래와 같이 다운 받을 수 있는 argocd 관련 chart가 보여진다.

image.png

  • namespace 추가
kubectl create namespace argocd
  • values.yaml 생성
# argocd/values.yaml
installCRDs: false

controller:
  replicas: 1

repoServer:
  replicas: 2

server:
  replicas: 2
  service:
    type: NodePort
    nodePortHttp: 30800
  config:
    accounts:
      admin: "login"

redis:
  enabled: true

redis-ha:
  enabled: true
  • helm 설치 검증
helm -n argocd template argocd argo/argo-cd -f values.yaml

해당 명령어를 치면 install 하면 설치되게 될 argocd의 manifest가 나오게 된다.

  • 설치
helm install argocd argo/argo-cd -n argocd -f values.yaml

시간이 생각보다 오래걸린다. 기다린 후 설치가 완료된 것으로 확인하였다.

여기서는 포트프워딩을 진행하여 확인하라고 안내하지만, 이미 values.yaml을 통해서 원하는 값으로 overlay하여 nodeport:33080 포트로 지정하였기 때문에 {node ip}:33080 으로 접속한다.

아래와 같이 argocd 화면이 보인다.

  • argocd 비밀번호 확인
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
  • 설치 확인 & 접속 확인


Application Helm Chart로 생성해보기

  • helm chart 생성
helm create hellospring
  • 파일 구조
hellospring-helm/
  ├── Chart.yaml
  ├── values.yaml
  ├── charts/
  └── templates/
      ├── deployment.yaml
      ├── service.yaml
      ├── ingress.yaml
      └── _helpers.tpl
  • Chart.yaml
apiVersion: v2
name: hellospring
description: A Helm chart for deploying a Spring Boot application
type: application
version: 0.1.0
appVersion: "1.0"  # 애플리케이션의 버전
keywords:
  - spring
  - boot
  - java
sources:
  - https://github.com/suhyeonXYZ/hellospring 
dependencies: 
  - name: ingress-nginx
    version: ">=3.6.0"  
    repository: "https://kubernetes.github.io/ingress-nginx"
  • values.yaml
replicaCount: 1

image:
  repository: suhyeonsong/hellospring
  pullPolicy: Always
  tag: latest



service:
  type: ClusterIP
  port: 3000  # 컨테이너 포트를 3000으로 설정

ingress:
  enabled: true
  path: /hello 
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /  # URL 재작성 설정
  • /templates/_helpers.tpl
{{/*
Generate the full name of the release.
*/}}
{{- define "hellospring.fullname" -}}
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Generate the name of the application.
*/}}
{{- define "hellospring.name" -}}
{{- .Chart.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
  • /template/Deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "hellospring.fullname" . }}
  labels:
    app: backend
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ include "hellospring.name" . }}
  template:
    metadata:
      labels:
        app: backend
    spec:
      containers:
        - name: {{ include "hellospring.name" . }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          ports:
            - name: http
              containerPort: 3000  # 포트 3000으로 설정
          resources:
            {}
  • /template/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: {{ include "hellospring.fullname" . }}
  labels:
    app: backend
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: 3000
      targetPort: 3000
  selector:
    app: backend
  • /template/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ include "hellospring.fullname" . }}
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - http:
        paths:
          - path: {{ .Values.ingress.path }}
            pathType: Prefix
            backend:
              service:
                name: {{ include "hellospring.fullname" . }}
                port:
                  number: {{ .Values.service.port }}
  • 종속성 업데이트

ingress가 종속성으로 있기 때문에, 아래 명령어로 charts/ 하위 디렉토리에 종속성을 다운한다.

helm dependency update .

아래와 같이 nginx tgz 가 생긴 것을 볼 수 있다.

  • 문법 확인
helm lint .

  • 배포 시 생성되는 오브젝트 설정 확인
helm template .
  • Chart 패키징
helm package hellospring/

hellospring-0.1.0.tgz 로 패키징 된다.

  • index.yaml 생성(이게 없으면 chart로 인식하지 못한다.)

index.yaml은 아래 charts 정보가 있기 때문에 자동으로 생성된다.

helm repo index . --url {{github pages 주소}}

아래와 같이 파일 정보를 기반한 index가 생성된다.

  • git charts관리를 위한 repository 생성
$ git checkout -b release
$ git push --set-upstream origin release
$ git add .
$ git commit -m "helm for hellospring"
$ git push

위의 과정을 모두 진행하면, 최종 파일 구조는 아래와 같다.

➜  hellospring-helm git:(release) tree
.
├── README.md
├── hellospring-0.1.0.tgz
├── hellospring-helm
│   ├── Chart.lock
│   ├── Chart.yaml
│   ├── charts
│   │   └── ingress-nginx-4.11.3.tgz
│   ├── templates
│   │   ├── Deployment.yaml
│   │   ├── _helpers.tpl
│   │   ├── ingress.yaml
│   │   └── service.yaml
│   └── values.yaml
└── index.yaml

생성된 Chart로 hellospring 프로젝트 설치

  • helm repo를 호스팅하려면 git repository를 Pages로 호스팅한다.

아래와 같이, repository의 setting-pages에서 Branch - release 선택 후 save 버튼을 누르면, 상단 호스팅되는 페이지가 보인다.

현재는 그냥 readme 만 보이는 페이지이다.

  • Chart Repository 추가
helm repo add hellospring https://github.com/suhyeonXYZ/hellospring-helm
helm repo update

정상적으로 helm repo가 등록된 것을 알 수 있다.

  • Chart 배포
helm install hellospring hellospring/hellospring

정상적으로 설치되었다.

정상적으로 설치가 된 것을 볼 수 있다.

배포 업데이트

# Helm Chart 업그레이드
helm upgrade <release-name> ./hellospring

TroubleShooting

  • helm 삭제
helm uninstall [RELEASE_NAME] -n [NAMESPACE
  • Deployment.apps "hellospring-hellospring" is invalid: spec.template.metadata.labels: Invalid value: map[string]string{"app":"backend"}: selector does not match template labels

무조건 변수사용해야하는 것 같음

반응형