헬름은 차트 개발자가 릴리스 수명주기의 특정 지점에 개입할 수 있도록 hook 매커니즘을 제공한다.
예를 들어 애플리케이션을 배포하기 전에 특정 작업을 시행하고 싶을때가 있다.
hook은 일반적인 템플릿처럼 동작하지만 다른 방식으로 처리할 수 있도록 어노테이션을 설정할 수 있다.
이번 글에서는 어노테이션과 훅/릴리스의 수명주기에 대해 정리하도록 하겠다.
- pre-install : 템플릿은 생성되었지만 리소스가 생성되기 전에 실행
- pre-upgrade : 업그레이드 요청시 리소스가 업데이트되기 전에 실행
- pre-delete : 삭제 요청시 리소스가 삭제되기 전에 실행
- pre-rollback : 롤백 요청시 리소스가 롤백되지 않은 시점에 실행
- post-install : 모든 리소스가 로드된 후에 실행
- post-upgrade : 업그레이드 요청시 모든 리소스가 업그레이드 된 후에 실행
- post-delete : 삭제 요청시 모든 리소스가 삭제된 후 실행
- post-rollback : 롤백 요청시 모든 리소스가 수정된 후에 실행
- test : 헬름 test 명령어가 호출될 때 실행
어노테이션은 pre, post, test로 나뉘어지는데 각각 실행 전, 실행 후, 명령어 호출시에 작업하도록 지정할 수가 있는 것이다.
실습을 통해 Helm Hook의 흐름과 활용 방법을 알아보자.

우선 helm install 명령어를 사용해 애플리케이션 릴리스를 사전에 배포해주자.
이때 사용되는 deployment.yaml 파일은 앱 실행 전 초기화 작업을 포함한 배포 구성을 정의한다.
deployment.yaml
apiVersion: v1
kind: Service
metadata:
name: svc
spec:
selector:
type: app
ports:
- port: 80
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment
spec:
selector:
matchLabels:
type: app
replicas: 1
template:
metadata:
labels:
type: app
annotations:
rollme: {{ randAlphaNum 5 | quote }}
spec:
initContainers:
- name: init-myservice
image: kubetm/app
command: ["sh", "-c", "echo 'start'; sleep 10; echo 'done'"]
containers:
- name: container
image: kubetm/app
이 구성에서 initContainers는 앱을 시작하기 전에 10초 동안 대기한 후 실행되는 초기화 작업을 포함한 배포 구성 으로 설정되어있다.
$ helm upgrade mychart . -n nm-1 --create-namespace --install

helm upgrade 명령어를 사용했지만 최초 배포가 되어있지 않기 때문에 'Release "mychar" does not exist. Installing it now.' 로그와 함께 새롭게 배포 것을 확인할 수 있다.

이제 Helm Hook을 활용해 릴리스의 업그레이드 과정에서 실행될 작업을 설정해보자. Hook은 애플리케이션 배포 전후 또는 특정 이벤트 시 실행되는 Pod를 정의할 수 있다.
아래는 다양한 시점에 실행될 Hook Pod 설정이다.
crd-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: crd-pod
annotations:
helm.sh/hook: pre-upgrade
spec:
restartPolicy: Never
containers:
- name: container
image: kubetm/init
command: ["sh", "-c", "echo 'start'; sleep 10; echo 'done'"]
pre-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pre-pod
annotations:
helm.sh/hook: pre-upgrade
spec:
restartPolicy: Never
containers:
- name: container
image: kubetm/init
command: ["sh", "-c", "echo 'start'; sleep 10; echo 'done'"]
post-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: post-pod
annotations:
helm.sh/hook: post-upgrade
spec:
restartPolicy: Never
containers:
- name: container
image: kubetm/init
command: ["sh", "-c", "echo 'start'; sleep 10; echo 'done'"]
test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-pod
annotations:
helm.sh/hook: test
spec:
restartPolicy: Never
containers:
- name: container
image: kubetm/init
command: ["sh", "-c", "echo 'start'; curl svc/hostname; echo 'done'"]
위에서 정의한 YAML 파일들이 릴리스의 수명주기 동안 어떻게 동작하는지 살펴보자.
$ helm upgrade mychart . -n nm-1 --create-namespace --install


pod의 생성 순서를 보면 crd-pod -> pre-pod 순서로 실행되는 것을 확인할 수 있다.
CRD와 Pre Hook은 릴리스 초기 단계에서 실행되고 있지만 각각 다른 목적과 동작 방식을 가지고 있다.
이렇게 각자 다른 역할을 수행하지만 실습에서는 추가적인 설정이나 로직이 없으므로 sh -c "echo 'start'; sleep 10; echo 'done'" 명령만 실행되고 종료된다.
pre-upgrade 훅이 실행된 후 본격적인 업그레이드는 deployment.yaml을 통해 이루어짐과 동시에 Pod의 로그를 확인할 수 있다.

업데이트 과정에서 로그를 확인하면 첫 배포와의 차이점이 드러나는데 여기서 주목할 점은 REVISION 값이 2로 변경된 부분이다.
이는 헬름 업그레이드를 성공적으로 마쳤다는 것을 의미하는데 helm upgrade 명령어를 통해 새로운 버전의 릴리스가 배포되었음을 나타낸다.
후속 작업을 처리하기 전에 업데이트 작업을 좀 더 살펴 보자면,
deployment.yaml의 annotations에 있는 rollme 설정은 헬름의 템플릿 구문을 사용하여 배포 시마다 무작위 문자열을 생성하고 이를 통해 배포가 새롭게 이루어졌음을 감지아여 롤링 업데이트를 수행하는 역할을 한다.
annotations:
rollme: {{ randAlphaNum 5 | quote }}
즉 헬름은 매번 배포 시 rollme 어노테이션의 값이 변경되기 때문에 배포가 새로 이루어졌다고 판단하고 롤링 업데이트를 수행할 것이다.
그럼 이제 배포 후 파드 상태를 살펴보자.

deployment-5c5fcf5558-nh2gq 파드는 Init:0/1 상태로 초기화 작업을 실행중이다. 이를 통해 배포가 시작되었고 롤링 업데이트가 진행 중이라는 것을 알 수 있다.
그렇다면 post-pod가 실행된 시점은 언제일까?
post-pod의 STATUS를 보면 ContainerCreating 상태로 나타난다. 이는 헬름이 롤링 업데이트와는 별개로 배포 작업이 완료되는 시점을 기준으로 post-upgrade를 실행하는 것으로 보여진다.
즉 롤링 업데이트의 완료 여부와는 관계없이 deployment.yaml의 배포 작업이 완료된 시점에 post-upgrade를 실행하는 것이다.


이로써 post-upgrade 작업과 롤링 업데이트가 완료되어 기존에 동작 중이던 파드는 종료되고 새로운 파드가 실행되어 헬름을 통한 업그레이드 작업과 후속 작업이 마무리되었다.
Helm Chart 배포 후 애플리케이션이 정상적으로 동작하는지 테스트 작업을 수행할 수 있다. helm test 명령어를 통해 지정된 테스트 파드를 실행하고 배포한 애플리케이션이 의도대로 작동하는지 검증할 수 있다.
헬름 테스트는 post-upgrade hook과는 다르게 애플리케이션의 기능적인 테스트를 수행하는 데 주로 사용된다.
$ helm test mychart -n nm-1


로그의 Phase의 값이 Succeeded를 통해 테스트가 성공적으로 완료된 상태임을 알 수 있다.
helm test 명령은 애플리케이션의 정상 동작 여부를 확인할 수 있는 유용한 도구이다. 배포 후 정상적으로 동작하는지, 기능이 예상대로 수행되는지 등에 대해 검증할 수 있다.
[참고 자료]
인프런 강의 대세는 쿠버네티스 Helm편
https://kubetm.github.io/helm/04-topic/topic1/