본문 바로가기
프로젝트 일지/BoWS

Helm으로 애플리케이션 배포 한 방에 해보기

by 데브겸 2024. 7. 22.

Helm Chart 만들기

helm create 명령어로 기본적인 틀 생성하기

helm create sampleApp

 

 

위 명령어로 아래와 같은 구조의 폴더가 만들어진다(이외에 여러 파일들이 있는데 optional한 경우가 많다)

sampleApp
    ├── Chart.yaml
    ├── templates
    └── values.yaml

 

 

아래와 같이 샘플을 구성

sampleApp
    ├── Chart.yaml
    ├── templates
    │   ├── frontend-deployment.yaml
    │   ├── backend-deployment.yaml
    │   ├── db-deployment.yaml
    │   └── ingress.yaml
    └── values.yaml

 

 

values.yaml

namespace: my-app

projectName: sampleApp
domain: bows.co.kr

app:
  backend:
    image:
      name: bogyumkim/backend
      tag: latest
    port: 8080
    protocol: TCP
    database: mysql
  frontend:
    image:
      name: bogyumkim/frontend
      tag: latest
    port: 80
    protocol: TCP
  db:
    image: 
      name: mysql
      tag: latest
    port: 3306
    protocol: TCP
    env:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: sampleapp
      MYSQL_USER: sampleApp
      MYSQL_PASSWORD: qwer1234

 

 

frontend-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: {{ .Values.namespace }}
  name: {{ .Values.projectName | lower }}-frontend-deployment
  labels:
    projectName: {{ .Values.projectName | lower }}
    tier: frontend
spec:
  replicas: 1
  selector:
    matchLabels:
      projectName: {{ .Values.projectName | lower }}
      tier: frontend
  template:
    metadata:
      labels:
        projectName: {{ .Values.projectName | lower }}
        tier: frontend
    spec:
      containers:
      - name: {{ .Values.projectName | lower }}-frontend
        image: {{ .Values.app.frontend.image.name }}:{{ .Values.app.frontend.image.tag }}
        ports:
        - containerPort: {{ .Values.app.frontend.port }}
---
apiVersion: v1
kind: Service
metadata:
  namespace: {{ .Values.namespace }}
  name: {{ .Values.projectName | lower }}-frontend-service
spec:
  selector:
    projectName: {{ .Values.projectName | lower }}
    tier: frontend
  ports:
    - protocol: {{ .Values.app.frontend.protocol }}
      port: {{ .Values.app.frontend.port }}
      targetPort: {{ .Values.app.frontend.port }}

 

 

backend-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: {{ .Values.namespace }}
  name: {{ .Values.projectName | lower }}-backend-deployment
  labels:
    projectName: {{ .Values.projectName | lower }}
    tier: backend
spec:
  replicas: 1
  selector:
    matchLabels:
      projectName: {{ .Values.projectName | lower }}
      tier: backend
  template:
    metadata:
      labels:
        projectName: {{ .Values.projectName | lower }}
        tier: backend
    spec:
      containers:
        - name: {{ .Values.projectName | lower }}-backend-server
          image: {{ .Values.app.backend.image.name }}:{{ .Values.app.backend.image.tag }}
          ports:
          - containerPort: {{ .Values.app.backend.port }} 
          env:
            - name: MYSQL_HOST
              value: {{ printf "%s-db-service" (.Values.projectName | lower) | quote }}

---

apiVersion: v1
kind: Service
metadata:
  namespace: {{ .Values.namespace }}
  name: {{ .Values.projectName | lower }}-backend-service
  labels:
    projectName: {{ .Values.projectName | lower }}
    tier: backend

spec:
  selector:
      projectName: {{ .Values.projectName | lower }}
      tier: backend 
  ports:
    - protocol: {{ .Values.app.backend.protocol }} 
      port: {{ .Values.app.backend.port }} 
      targetPort: {{ .Values.app.backend.port }} 

 

 

db-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Values.projectName | lower }}-db
  namespace: {{ .Values.namespace }}
  labels:
    projectName: {{ .Values.projectName | lower }}
    tier: db
spec:
  replicas: 1
  selector:
    matchLabels:
      projectName: {{ .Values.projectName | lower }}
      tier: db
  template:
    metadata:
      labels:
        projectName: {{ .Values.projectName | lower }}
        tier: db
    spec:
      containers:
      - name: {{ .Values.projectName | lower }}-db
        image: {{ .Values.app.db.image.name }}:{{ .Values.app.db.image.tag }}
        ports:
        - containerPort: {{ .Values.app.db.port }}
        env:
          {{- range $name, $value := .Values.app.db.env }}
          - name: {{ $name }}
            value: {{ $value }}
          {{- end }}
        volumeMounts:
          - name:  {{ .Values.projectName | lower }}-storage
            mountPath: /var/lib/{{ .Values.projectName | lower }}/storage
      volumes:
      - name: {{ .Values.projectName | lower }}-storage
        emptyDir: {}
          
---

apiVersion: v1
kind: Service
metadata:
  namespace: {{ .Values.namespace }}
  name: {{ .Values.projectName | lower }}-db-service
spec:
  selector:
    projectName: {{ .Values.projectName | lower }}
    tier: db
  ports:
    - protocol: {{ .Values.app.db.protocol }}
      port: {{ .Values.app.db.port }}
      targetPort: {{ .Values.app.db.port }}

 

 

helm chart linting

중간중간 helm lint 명령어를 통해 chart 작성 중 올바르지 않은 내용이 있는지 확인할 수 있다

helm lint 헬름차트 # ex. helm lint ./sampleApp/

 

 

helm template 명령어를 사용하면 values.yaml과 template의 내용을 합쳐서 최종적으로 어떤 yaml 파일로 렌더링되는지 보여준다. 개별 파일 지정은 해보니 에러가 발생했었고 헬름 차트 전체를 보는 것은 가능한 것 같았다.

helm template 헬름차트 # helm template ./sampleApp/

 

 

Helm Chart Repository 만들기

위 과정은 모두 차트를 로컬로 만들고, 로컬에서 배포하는 과정이었다. 만약 원격에 있는 차트를 가져와 배포를 하고 싶다면, helm chart 또한 원격으로 가져갈 수 있도록 서빙해주어야 한다. Helm은 이러한 원격 배포를 위해 Repository라는 개념을 도입하였다. Helm Repository는 index.yaml 파일과 패키지화된 tgz 형태의 차트를 저장하는 HTTP 서버이다. ‘Http 서버’ 정도로 느슨하게 정의하였기 때문에 GitHub Pages와 같은 형태로도 Chart Repository를 구축할 수 있다.

 

우선 만들어진 chart를 배포하기 위해선 패키징을 하여 tgz 파일로 만들어야 한다. 아래 명령어를 통해 tgz 파일 생성이 가능하다.

helm package sampleApp/

 

 

다음은 chart의 정보를 알려주는 index.yaml을 생성한다. 아래 명령어로 간단하게 생성할 수 있다. 이때 생성되는 index.yaml은 현재 디렉토리 기준 tgz 파일을 참조하여 생성된다.

helm repo index .

 

 

위에서 생성된 패키지와 index.yaml을 GitHub Pages 등에 올려 http 통신으로 가져올 수 있도록 한다. 배포하고자 하는 서버가 있는 곳에서 아래 명령어를 통해 repo를 추가할 수 있다(chart를 땡겨올 수 있다)

helm repo add ${CHART_NAME} https://${레포 엔드포인트}

 

 

차트 배포를 할 때는 아래 명령으로 가능하다. 커스텀한 values.yaml을 만들어 오버라이딩하여 배포하자

helm install ${앱 이름} ${레포 이름}/${차트 이름} -n ${ns 이름} -f ${values.yaml 경로}

helm install deployEx sampleapp/sampleapp -n my-app -f custom-values.yaml 

 

 

만약 배포한 애플리케이션을 삭제하고 싶다면

helm uninstall ${앱 이름} -n ${ns이름}

helm uninstall deployEx -n my-app

 

 

Chart 수정후 재배포하기

만약 chart를 수정한다면 반드시 tgz와 index.yaml까지 업데이트를 하여 repository를 업데이트 해야 한다. helm repo add, helm install은 결국 tgz 파일을 받아 압축을 풀고 그것을 바탕으로 배포하는 것이기 때문. templates 폴더 안에 있는 yaml 파일을 수정한다고 해서 바로 반영되는 것이 아니다. 따라서 아래와 같은 절차를 밟는다

// 원하는 부분 수정

// package, index.yaml 수정
helm package sampleApp/

helm rep index .

// Helm Repo 업데이트

// 배포하고자 하는 곳에서 repo update로 chart 최신화
helm repo update 

helm install ~~~