Ssoon

Helm : 5.7 Triggering a Rolling Update Automatically 본문

CICD Study [1기]

Helm : 5.7 Triggering a Rolling Update Automatically

구구달스 2025. 10. 19. 14:46

 

🚀 Helm으로 ConfigMap 변경 시 Rolling Update 자동 트리거하기

  • Kubernetes에서 ConfigMap은 애플리케이션의 환경 설정을 외부에서 관리할 수 있게 해주는 매우 유용한 리소스입니다.
    하지만 ConfigMap이 변경되어도 Deployment가 자동으로 업데이트되지 않는 문제가 있습니다.
    Helm을 사용해 ConfigMap 변경 시 자동으로 Rolling Update가 일어나도록 설정하는 방법

📘 문제 상황

  • Kubernetes에서 Deployment는 기본적으로 Pod의 스펙이 변경될 때만 새로운 Pod를 생성합니다.
    즉, ConfigMap이 수정되어도 Deployment 자체가 변하지 않으면 Rolling Update는 발생하지 않습니다.
    그 결과, 새로운 설정값이 반영되지 않은 채 기존 Pod가 그대로 실행되는 문제가 생깁니다.

"ConfigMap이 변경되어도 Deployment가 변경되지 않으면 Pod는 재시작되지 않는다."


⚙️ Kustomize의 방식

  • Kustomize에는 ConfigMapGenerator라는 기능이 있습니다.
    이 기능은 ConfigMap이 변경될 때마다 자동으로 이름 뒤에 해시(Hash)를 붙여 새로운 ConfigMap 이름을 생성합니다.
    이로 인해 Deployment 파일의 참조가 변경되고, Kubernetes는 이를 감지해 자동으로 Rolling Update를 수행합니다.
# Kustomize 예시
configMapGenerator:
  - name: app-config
    files:
      - config.yaml
  • 이름이 자동으로 생성되며, ConfigMap 내용이 바뀌면 해시 값이 변경되어 자동 업데이트가 일어납니다.

"Kustomize는 ConfigMap 변경 시 자동으로 이름에 해시를 붙여 Rolling Update를 트리거한다."


🧩 Helm에서는 어떻게 할까?

  • Helm에는 Kustomize처럼 자동으로 해시를 붙여주는 기능은 없습니다.
    하지만 Helm 템플릿 내에서 sha256sum 함수를 사용하면 유사한 효과를 낼 수 있습니다.
    이 함수를 통해 ConfigMap 파일의 내용을 해시화하고, 그 해시 값을 Deployment의 annotation에 추가하면 됩니다.
  • annotation 값이 변경되면 Deployment 템플릿이 달라졌다고 인식되어 Pod가 자동으로 재배포됩니다.

"Helm에서는 sha256sum 함수를 이용해 ConfigMap 내용의 해시값을 annotation에 추가해 Rolling Update를 유도한다."


🌐 예제: Greetings 애플리케이션

이제 실제 예시를 통해 과정을 살펴보겠습니다.
간단한 Node.js 애플리케이션이 있고, 이 앱은 ConfigMap에서 환경 변수(GREETING) 값을 가져와 인사 메시지를 반환합니다.

(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ mkdir greetings
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ mkdir greetings/templates
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ cd greetings/
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$

🧱 1. Deployment 템플릿 작성

  • Deployment 템플릿에서 ConfigMap을 환경 변수로 주입합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$ cat << EOF > templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Chart.Name }}
  labels:
    app.kubernetes.io/name: {{ .Chart.Name }}
    {{- if .Chart.AppVersion }}
    app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
    {{- end }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ .Chart.Name }}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: {{ .Chart.Name }}
    spec:
      containers:
      - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        name: {{ .Chart.Name }}
        ports:
        - containerPort: {{ .Values.image.containerPort }}
        env:
        - name: GREETING
          valueFrom:
            configMapKeyRef:
              name: {{ .Values.configmap.name }}
              key: greeting
EOF

"Deployment는 ConfigMap의 key-value를 환경 변수로 주입받는다."


🧾 2. ConfigMap 생성

(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$ cat << EOF > templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: greeting-config
data:
  greeting: Aloha
EOF

"ConfigMap은 greeting이라는 key에 인사 메시지를 저장한다."


🌉 3. Service 생성

(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$ cat << EOF > templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: {{ .Chart.Name }}
  name: {{ .Chart.Name }}
spec:
  ports:
  - name: http
    port: {{ .Values.image.containerPort }}
    targetPort: {{ .Values.image.containerPort }}
  selector:
    app.kubernetes.io/name: {{ .Chart.Name }}
EOF

"Service는 Deployment의 Pod에 접근할 수 있도록 포트를 노출한다."


⚙️ 4. values.yaml 설정

(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$  cat << EOF > values.yaml
image:
  repository: quay.io/gitops-cookbook/greetings
  tag: "1.0.0"
  pullPolicy: Always
  containerPort: 8080

replicaCount: 1

configmap:
  name: greeting-config
EOF

"values.yaml은 이미지 정보와 ConfigMap 이름을 지정한다."


🧩 5. Chart 설치 및 테스트

(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$ cat << EOF > Chart.yaml
apiVersion: v2
name: greeting
description: A Helm chart for greeting
type: application
version: 0.1.0        # 차트 버전, 차트 정의가 바뀌면 업데이트한다
appVersion: "1.0.0"   # 애플리케이션 버전
EOF


(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$ tree
.
├── Chart.yaml
├── templates
│   ├── configmap.yaml
│   ├── deployment.yaml
│   └── service.yaml
└── values.yaml

2 directories, 5 files
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$ helm install greetings .
NAME: greetings
LAST DEPLOYED: Sat Oct 25 16:17:50 2025
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None


(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$ kubectl port-forward service/greetings 8080:8080
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080

C:\Users\kscho>curl localhost:8080
Aloha Ada

 

"처음 배포된 앱은 ConfigMap의 greeting 값(Aloha)을 정상적으로 사용한다."


⚠️ 문제 발생: ConfigMap 변경 후에도 반영되지 않음

  • ConfigMap을 아래처럼 수정해봅시다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$ sed -i 's/Aloha/Hola/' templates/configmap.yaml
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$ cat templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: greeting-config
data:
  greeting: Hola
  • 이후 Helm 차트의 버전을 올려 재배포합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$ helm upgrade greetings .
Release "greetings" has been upgraded. Happy Helming!
NAME: greetings
LAST DEPLOYED: Sat Oct 25 16:34:22 2025
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None

다시 curl로 테스트하면?

(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$ kubectl port-forward service/greetings 8080:8080
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080

C:\Users\kscho>curl localhost:8080
Aloha Alexandra
  • 여전히 이전 값이 출력됩니다.
    ConfigMap은 업데이트되었지만 Deployment에는 아무런 변화가 없기 때문입니다.
    즉, Pod 재시작이 발생하지 않아 새로운 값이 반영되지 않은 것입니다.

"ConfigMap이 변경되어도 Deployment가 갱신되지 않으면 Pod가 재시작되지 않는다."


🔐 해결 방법: sha256sum으로 체크섬 추가

이 문제를 해결하기 위해 Deployment 템플릿에 아래 코드를 추가합니다.

(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$ sed -i '/    spec:/i \      annotations:\
        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}' templates/deployment.yaml
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$ cat templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Chart.Name }}
  labels:
    app.kubernetes.io/name: {{ .Chart.Name }}
    {{- if .Chart.AppVersion }}
    app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
    {{- end }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ .Chart.Name }}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: {{ .Chart.Name }}
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
    spec:
      containers:
      - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        name: {{ .Chart.Name }}
        ports:
        - containerPort: {{ .Values.image.containerPort }}
        env:
        - name: GREETING
          valueFrom:
            configMapKeyRef:
              name: {{ .Values.configmap.name }}
              key: greeting

이 코드는 다음을 수행합니다.

  1. configmap.yaml 파일의 내용을 읽습니다.
  2. 그 내용을 SHA-256 해시로 변환합니다.
  3. 해당 해시 값을 Deployment의 annotation(checksum/config)에 추가합니다.

ConfigMap 내용이 바뀌면 해시값도 바뀌기 때문에, Deployment 템플릿이 변경된 것으로 인식되어 Rolling Update가 자동으로 발생합니다.

"ConfigMap의 해시값을 annotation으로 추가하면 내용 변경 시 자동으로 Pod가 재배포된다."


🔁 6. 다시 ConfigMap 수정 및 배포

(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$ sed -i 's/Hola/Namaste/' templates/configmap.yaml
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$ cat templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: greeting-config
data:
  greeting: Namaste
  • Helm 차트를 다시 업그레이드합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$ helm upgrade greetings .
Release "greetings" has been upgraded. Happy Helming!
NAME: greetings
LAST DEPLOYED: Sat Oct 25 16:40:15 2025
NAMESPACE: default
STATUS: deployed
REVISION: 3
TEST SUITE: None
  • 이제 다시 curl로 테스트해봅시다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$ kubectl port-forward service/greetings 8080:8080
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080

C:\Users\kscho>curl localhost:8080
Namaste Ada
  • 새로운 설정이 반영되었음을 확인할 수 있습니다.

"sha256sum annotation을 추가하면 ConfigMap 변경 시 Rolling Update가 자동으로 트리거된다."


📸 Figure: Pod annotation 예시

  • Pod Annotation 출력 예시
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~/greetings$ k describe pod greetings-67cc7d89c7-5cq65
Name:             greetings-67cc7d89c7-5cq65
Namespace:        default
Priority:         0
Service Account:  default
Node:             myk8s-control-plane/172.19.0.2
Start Time:       Sat, 25 Oct 2025 16:40:15 +0900
Labels:           app.kubernetes.io/name=greetings
                  pod-template-hash=67cc7d89c7
Annotations:      checksum/config: 38f96b801b3a9f43e67bf729e33729fd0576ebc15332a6fcbea5c05c679238de
Status:           Running
IP:               10.244.0.45
...
checksum/config: 38f96b801b3a9f43e67bf729e33729fd0576ebc15332a6fcbea5c05c679238de

📌 핵심 요약

  • 문제: ConfigMap이 변경되어도 Deployment가 갱신되지 않으면 Pod는 재시작되지 않는다.
  • Kustomize: ConfigMap 이름에 해시를 자동 추가해 Rolling Update를 유도한다.
  • Helm: sha256sum 함수를 활용해 ConfigMap의 해시값을 annotation에 추가하여 동일한 효과를 낼 수 있다.
  • 결과: ConfigMap 변경 시 자동으로 Deployment가 업데이트되어 Pod가 재배포된다.
  • 핵심 코드:
  • annotations: checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}

"Helm 차트에서 sha256sum을 활용하면 ConfigMap 변경 시 자동 Rolling Update를 구현할 수 있다."

 

Comments