helm-v2-deprecated-announce-at-kubecon

Helm 릴리즈 매니저는 쿠버네티스에 애플리케이션을 배포할 때 더할나위 없이 편리하고 표준적인 방법으로 많은 유저들에게 사랑받고 있다. 현재 가장 대중적으로 쓰이는 버전은 v2 인데, 한달 전 미국 샌디에고에서 진행한 Kubecon에 참가했을 때, 이 v2 버전이 앞으로 약 1년에 걸쳐 서서히 지원 중단되고, 최신 버전인 v3로 세대 교체를 한다는 발표를 보았다.

helm-v2-lifecycle

Helm v3 출시가 처음 공표된 것이 필자가 참가한 11월 Kubecon의 약 일주일 전이였고, 1년의 사후 지원 기간이 있어 그리 서두를 필요는 없지만, 미리 Helm v2와 v3의 차이점을 이해하고, 어떻게 하면 서비스 영향을 최소화하며 안전히 마이그레이션 할 수 있을지 알아보는 과정이 필요할 것 같아 시간이 남는 크리스마스 (…) 에 글을 끄적여본다. 내년 크리스마스는 시간이 남지 않길

Helm v2와 v3의 차이점

Helm이 버전의 앞자리까지 바꿀 정도의 업그레이드를 거치며 기존 버전과 몇가지 큰 차이점들이 생겨났는데, 다행히 주로 Helm v2에서 사람들이 문제점으로 지적하는 것들, 불편한 것들이 수정된 “개선점” 이다.

아래 내용 작성에는 Helm 공식 문서를 참고했습니다. 원문을 보고 싶으신 분, 혹은 자잘한 변경점까지 모두 확인하고 싶으신 분은 이 링크를 확인해주세요.

Tiller의 완전한 삭제

Helm v2에서는 클러스터에서 Helm Chart들의 통합 관리와 설치를 위해 Tiller라는 특별한 Pod를 사용했다. Tiller가 설치된 Chart를 통합 관리해주는 덕에, 누가 그 쿠버네티스 클러스터에 접속하더라도 같은 버전의 Helm Chart를 볼 수 있었다.

그래, 다 좋아 보이지만 언제나 문제는 보안이다. 쿠버네티스의 RBAC가 기본으로 활성화되고부터, Helm은 Tiller Pod에 cluster-admin 권한을 부여했다. 시스템 관리자가 자잘한 보안 문제에 직면하지 않고 애플리케이션 배포에 집중할 수 있게 해준 배려였겠지만, 프로덕션 환경까지 생각할 경우 이는 큰 보안 구멍이 될 수 있다.

대표적으로, 사용자의 PC에 설치된 Helm 클라이언트와 쿠버네티스의 Tiller는 gRPC를 사용해서 통신을 하게 되는데, 기본 설정으로는 이 gRPC 포트가 보안 없이 열려있게 된다! 물론 이 포트가 직접적으로 외부에 열려있지는 않지만, 만약 공격자가 작정하고 쿠버네티스에 악성 프로그램을 구동하는데 성공했다면, 내부 네트워크를 타고 이 gRPC 포트에 요청을 보내 아무런 인증 과정 없이 cluster-admin 권한을 사용할 수 있게 되는 거다.

이런 잠재적인 문제를 방지하기 위해, Helm v3부터는 Tiller가 아닌 쿠버네티스 API를 사용해 설치된 Helm Chart들을 쿠버네티스 그 자체에 저장하게 된다. 그 Chart를 설치하는 RBAC 권한은 사용자가 사용한 kubeconfig 파일을 따라가게 된다.

이처럼 Helm 작동 구조가 조금 더 직관적으로 변하면서, 프로덕션 환경에서도 조금 더 안심하고 Helm을 사용할 수 있게 되었다.

Helm으로 설치된 릴리즈의 수정 감지와 반영

제목만 보고 이게 무슨 소린가 할 거다. 필자가 공돌이랑 문돌이 그 사이 어딘가에 있는 어중간한 성향의 사람이라 그럴 수도 있다. 각설하고, 이제 Helm으로 설치된 릴리즈가 (Chart 등) kubectl 등의 외부 도구를 사용해 수정되어도 Helm이 감지하고 rollback이나 upgrade 등에 자연스럽게 반영한다는 말이다.

예를 들어보자, 만약 Helm v2에서 1개의 Nginx를 실행하는 Chart를 설치했을 때, 이후 kubectl을 사용해 replicas를 1개에서 0개로 만든다면 Helm은 이를 감지하지 못한다. 만약 이 상태에서 helm rollback을 실행했을 때, Helm 입장에서는 자신을 통해 수정된 부분이 없으니 모든 설정이 최신이라고 생각해 아무런 일이 벌어지지 않는다. Nginx Pod의 갯수는 계속 0개로 남아있을 거다. Helm 공식 문서의 말 맞다나 “Panic ensues” 다.

Helm v3는 이런 외부 도구를 사용해 수정된 리소스의 차이도 감지할 수 있게 된다. 같은 상황에서 helm rollback을 실행하면, Helm v3는 최초 설치된 Helm Chart의 정보와, 현재의 수정된 정보를 비교해 최초의 Chart 정보로 덮어씌운다. Pod의 갯수도 당연히 1개로 돌아간다. 진정한 의미의 Rollback이 가능해진 것이다.

또 다른 에시로, Helm v2를 통해 설치한 Deployment에 이후 kubectl edit등을 사용해 Sidecar 컨테이너를 하나 추가했다고 생각해 보자. 이후 helm upgrade로 해당 릴리즈를 업그레이드 할 경우, Helm Chart에는 당연히 아무런 Sidecar 설정이 되어있지 않으니 업그레이드 된 릴리즈에는 Sidecar는 흔적도 없이 사라져 있을꺼다. 물론 정석적인 방법은 Sidecar를 Helm Chart 단계에서 추가해, upgrade를 돌리는 거지만, 만약 급하게 Helm을 통하지 않고 Sidecar를 추가한 후, upgrade를 실행해 버렸다면 또다시 패닉이겠다.

Helm v3에서는 이 같은 차이도 감지해서 upgrade에 반영하게 된다. 즉, Chart에 Sidecar가 설정되어 있지 않다고 해도 upgrade를 돌렸을 때 Sidecar가 남아있다는 말씀. 오오. 이 얼마나 편리한가.

Release Name의 중복 허용

Helm Chart를 설치할 때는 Release Name을 필수적으로 정해야 하는데, Helm v2에서는 이 이름은 Unique Name이 되었다. 한번 사용한 이름은 다른 Chart를 설치할 때 다시 사용할 수 없었다는 뜻이다.

지금까지는 Tiller가 모든 설치된 Chart들을 관리하면서 Tiller가 위치한 Namespace에 모든 설치 정보도 저장되었다. 그래서 같은 Release Name을 사용하면 충돌이 발생했는데, 이제 각 Chart의 설치 정보는 그 Chart가 설치된 Namespace에 개별적으로 저장되게 되면서, 다른 Namespace에 무언가를 설치하며 동일한 Release Name을 사용한다고 해도 충돌이 벌어질 건덕지가 없어졌다.

이제 같은 이름 여러번 써도 된다! 개발자의 가장 큰 직무, 이름 짓기의 부담이 티끌만큼 덜어지는 순간이다.

자잘한 명령어 변경

설치된 릴리즈를 지울 때 흔히 사용되는 helm delete 명령어가 helm uninstall 로 대체되었다. 정획하 밀하면 helm deletehelm uninstall의 대체 명령어로 남아있어 둘 중 아무거나 사용해도 되지만, helm uninstall이라는 명령어를 새로 만든 만큼 나중에는 helm delete라는 명령어 자체가 사라질 수도 있을 것 같으니 미리미리 helm uninstall을 사용하는 습관을 길러보자.

추가적으로, helm delete--purge 라는 플래그를 추가적으로 사용해야 설치된 릴리즈 정보를 완전히 삭제할 수 있었는데, helm uninstall을 사용하면 이제 기본적으로 --purge까지 같이 수행된다. 만약 --purge 기능을 사용하고 싶지 않다면, helm uninstall--keep-history 플래그를 같이 사용하면 된다.

그 외

  • helm inspect -> helm show
  • helm fetch -> helm pull

Helm v2에서 v3로의 마이그레이션

테스트 환경 구성

우선, Helm v2가 설치된 쿠버네티스 환경을 준비하자. 필자는 Helm v2를 사용하는 프로덕션 쿠버네티스를 여러대 운용하고 있지만, 안전한 테스트를 위해 로컬 환경에 새로운 쿠버네티스를 기동했다. macOS 환경을 사용한다면 Docker for Mac에서 원클릭 쿠버네티스 구축 기능을 지원하니 간편하고 안전한 테스트를 원하는 분들은 참고하시길.

helm-v2-setup-on-local

helm init --service-account=tiller

위 명령어로 Helm v2의 Tiller Pod를 initialize 시킬 수 있다. 위의 tiller Service Account는 아래를 참고해 본인이 원하는 이름으로 생성하면 된다.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: tiller
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: tiller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: tiller
    namespace: kube-system

helm version 명령어를 통해 정상적으로 Tiller Pod가 사용 준비가 되었는지 체크하자. 아래와 같이 클라이언트, 서버 버전이 잘 출력된다면 사용 준비 끝.

kycfeel-MBP:~ kycfeel$ helm version
Client: &version.Version{SemVer:"v2.9.1", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.9.1", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}

Helm v3로 마이그레이션 하기 전, Helm v2인 상태로 Helm Chart 하나를 설치해보자. 이전에 설치된 릴리즈가 신 버전에서도 정상적으로 동작해야 마이그레이션의 의미가 있다. 이미 Helm v2를 사용중이고, Helm으로 설치한 릴리즈가 존재한다면 다음 단게로 넘어가도 무방하다.

만약 없다면, 아래 명령어를 통해 간단히 Redis 서버를 설치해 보자.

간단한 테스트 애플리케이션 구성을 위해 Persistet Volume Claim 생성은 비활성화 했다.

helm install --name test-redis stable/redis -set master.persistence.enabled=false --set slave.persistence.enabled=flase stable/redis

이후 kubectl get pods 명령어로 정상적으로 Redis가 설치되어 구동되는지 꼭 확인하자.

Helm v3와 2to3 플러그인 설치하기

아래의 메뉴얼은 Helm 공식 블로그를 참고해 작성되었습니다.

우선, 최신 버전의 Helm v3를 Helm 공식 GitHub에서 다운로드하자. 우리의 목적은 Helm v3로의 클린 재설치가 아닌, 부드러운 마이그레이션이므로 기존 설치된 Helm을 생각없이 덮어쓸 수는 없다. 일단, 다운로드 받은 바이너리의 이름을 helm에서 helm3로 바꿔, 시스템의 /usr/local/bin 폴더에 넣어주자. 사용하는 OS에 따라 경로가 약간 다를 수는 있지만, 비슷한 역할을 하는 곳에 넣어주면 된다.

이제, helm3 plugin install https://github.com/helm/helm-2to3 명령어로 Helm v2를 v3로 마이그레이션 할 수 있게 도와주는 2to3 플러그인을 설치하자. 아래처럼 helm 2to3 명령어를 입력했을 때, 사용 방법이 출력되면 정상적으로 설치된 것이다.

kycfeel-MBP:darwin-amd64 kycfeel$ helm3 2to3
Migrate and Cleanup Helm v2 configuration and releases in-place to Helm v3

Usage:
  2to3 [command]

Available Commands:
  cleanup     cleanup Helm v2 configuration, release data and Tiller deployment
  convert     migrate Helm v2 release in-place to Helm v3
  help        Help about any command
  move        migrate Helm v2 configuration in-place to Helm v3

Flags:
  -h, --help   help for 2to3

Use "2to3 [command] --help" for more information about a command.

Helm v2의 설정 마이그레이션

helm3 2to3 move config 명령어로 기존 Helm v2를 통해 설치한 Chart들의 Repository, 플러그인 등을 Helm v3로 안전하게 옮길 수 있다.

잠깐 진행하기 전, helm repo list 명령어를 통해 기존 Helm v2의 Repository list와, helm3 repo list 명령어로 Helm v3의 Repository list를 비교해 보자. Helm v2는 stable을 위시한 local 등의 list들의 보일 것인데, Helm v3는 기본 설정이라면 아무런 Repo도 보이지 않을 것이다. 마이그레이션이 성공한다면, 이 Helm v2의 Repository들이 Helm v3에도 그대로 옮겨질 것이다. 지금부터 한번 확인해 보자.

kycfeel-MBP:darwin-amd64 kycfeel$ helm3 2to3 move config
2019/12/28 17:08:11 WARNING: Helm v3 configuration maybe overwritten during this operation.
2019/12/28 17:08:11
[Move Config/confirm] Are you sure you want to move the v2 configration? [y/N]: y
2019/12/28 17:08:12
Helm v2 configuration will be moved to Helm v3 configration.
2019/12/28 17:08:12 [Helm 2] Home directory: /Users/kycfeel/.helm
2019/12/28 17:08:12 [Helm 3] Config directory: /Users/kycfeel/Library/Preferences/helm
2019/12/28 17:08:12 [Helm 3] Data directory: /Users/kycfeel/Library/helm
2019/12/28 17:08:12 [Helm 3] Cache directory: /Users/kycfeel/Library/Caches/helm
2019/12/28 17:08:12 [Helm 3] Create config folder "/Users/kycfeel/Library/Preferences/helm" .
2019/12/28 17:08:12 [Helm 3] Config folder "/Users/kycfeel/Library/Preferences/helm" created.
2019/12/28 17:08:12 [Helm 2] repositories file "/Users/kycfeel/.helm/repository/repositories.yaml" will copy to [Helm 3] config folder "/Users/kycfeel/Library/Preferences/helm/repositories.yaml" .
2019/12/28 17:08:12 [Helm 2] repositories file "/Users/kycfeel/.helm/repository/repositories.yaml" copied successfully to [Helm 3] config folder "/Users/kycfeel/Library/Preferences/helm/repositories.yaml" .
2019/12/28 17:08:12 [Helm 3] Create cache folder "/Users/kycfeel/Library/Caches/helm" .
2019/12/28 17:08:12 [Helm 3] cache folder "/Users/kycfeel/Library/Caches/helm" created.
2019/12/28 17:08:12 [Helm 3] Create data folder "/Users/kycfeel/Library/helm" .
2019/12/28 17:08:12 [Helm 3] data folder "/Users/kycfeel/Library/helm" created.
2019/12/28 17:08:12 [Helm 2] starters "/Users/kycfeel/.helm/starters" will copy to [Helm 3] data folder "/Users/kycfeel/Library/helm/starters" .
2019/12/28 17:08:12 [Helm 2] starters "/Users/kycfeel/.helm/starters" copied successfully to [Helm 3] data folder "/Users/kycfeel/Library/helm/starters" .
2019/12/28 17:08:12 Helm v2 configuration was moved successfully to Helm v3 configration.

명령어를 실행하면, 내 기존 Helm v2 폴더의 여러 설정 데이터들이 Helm v3에서 사용하는 폴더들로 옮겨진 걸 확인할 수 있다. 필자는 macOS에서 마이그레이션을 진행했는데, Helm v3부터는 더 macOS-Native한 설치 경로를 사용하는 게 보인다. 기존 Unix 스타일과 macOS-Only 스타일. 뭐가 더 효율적일지는 나도 모르겠다 🤔.

이제 helm3 repo list 명령어를 한번 실행해 보자. 별다른 문제가 없었다면 아래와 같이 Repository들이 정상적으로 보일 것이다. 필자의 경우 이미 테스트 전부터 Helm v2에 이것저것 추가해둔 덕에, 독자의 환경과 표시되는 리스트 목록이 조금 다를 수 있다. 신경쓰지 말고 넘어가자.

kycfeel-MBP:darwin-amd64 kycfeel$ helm3 repo list
NAME           	URL
stable         	https://kubernetes-charts.storage.googleapis.com
local          	http://127.0.0.1:8879/charts
coreos         	https://s3-eu-west-1.amazonaws.com/coreos-charts/stable/
(...)

Helm v2의 Release 마이그레이션

설정값들을 옮겼으니, 이제 진짜배기를 옮길 차례다. 설치된 Helm 릴리즈들을 Helm v3로 승계하는 것을 말하는 거다. 우리는 조금 전 test-redis라는 이름의 Redis 릴리즈를 만들었으니, 그 릴리즈를 v3으로 옮겨보자.

kycfeel-MBP:darwin-amd64 kycfeel$ helm ls
NAME      	REVISION	UPDATED                 	STATUS  	CHART      	NAMESPACE
test-redis	1       	Sat Dec 28 16:35:52 2019	DEPLOYED	redis-5.1.0	default

helm ls 명령어로 릴리즈 이름과 목록을 다시한번 확인한 후, 아래 명령어로 릴리즈를 v3로 승계해보자.

kycfeel-MBP:darwin-amd64 kycfeel$ helm3 2to3 convert test-redis
2019/12/28 17:26:27 Release "test-redis" will be converted from Helm v2 to Helm v3.
2019/12/28 17:26:27 [Helm 3] Release "test-redis" will be created.
2019/12/28 17:26:27 [Helm 3] ReleaseVersion "test-redis.v1" will be created.
2019/12/28 17:26:27 [Helm 3] ReleaseVersion "test-redis.v1" created.
2019/12/28 17:26:27 [Helm 3] Release "test-redis" created.
2019/12/28 17:26:27 Release "test-redis" was converted successfully from Helm v2 to Helm v3.
2019/12/28 17:26:27 Note: The v2 release information still remains and should be removed to avoid conflicts with the migrated v3 release.
2019/12/28 17:26:27 v2 release information should only be removed using `helm 2to3` cleanup and when all releases have been migrated over.

뭔가 정상적으로 진행된 것 같다. 이제 helm3 ls 명령어로 선택한 릴리즈가 정상적으로 옮겨졌는지 확인해 보자.

kycfeel-MBP:darwin-amd64 kycfeel$ helm3 ls
NAME      	NAMESPACE	REVISION	UPDATED                              	STATUS  	CHART      	APP VERSION
test-redis	default  	1       	2019-12-28 07:35:52.6889687 +0000 UTC	deployed	redis-5.1.0	4.0.11

완벽하다 😄.

Helm v2 정리하기

필요한 모든 설정값과 릴리즈를 Helm v3로 옮겼다면, 이제 정든 Helm v2와 작별을 고해야겠지. 아쉽지만 어쩌하리. 인간은 결국 앞으로 나아가야만 하는 존재니.

아래 명령어로 Helm v2를 깔끔하게 삭제할 수 있다.

kycfeel-MBP:darwin-amd64 kycfeel$ helm3 2to3 cleanup
WARNING: "Helm v2 Configuration" "Release Data" "Release Data" will be removed.
This will clean up all releases managed by Helm v2. It will not be possible to restore them if you haven't made a backup of the releases.
Helm v2 may not be usable afterwards.

[Cleanup/confirm] Are you sure you want to cleanup Helm v2 data? [y/N]: y
2019/12/28 17:29:41
Helm v2 data will be cleaned up.
2019/12/28 17:29:41 [Helm 2] Releases will be deleted.
2019/12/28 17:29:42 [Helm 2] ReleaseVersion "test-redis.v1" will be deleted.
2019/12/28 17:29:42 [Helm 2] ReleaseVersion "test-redis.v1" deleted.
2019/12/28 17:29:42 [Helm 2] Releases deleted.
2019/12/28 17:29:42 [Helm 2] Tiller in "kube-system" namespace will be removed.
2019/12/28 17:29:42 [Helm 2] Tiller "deploy" in "kube-system" namespace will be removed.
2019/12/28 17:29:43 [Helm 2] Tiller "deploy" in "kube-system" namespace was removed successfully.
2019/12/28 17:29:43 [Helm 2] Tiller "service" in "kube-system" namespace will be removed.
2019/12/28 17:29:43 [Helm 2] Tiller "service" in "kube-system" namespace was removed successfully.
2019/12/28 17:29:43 [Helm 2] Tiller in "kube-system" namespace was removed.
2019/12/28 17:29:43 [Helm 2] Home folder "/Users/kycfeel/.helm" will be deleted.
2019/12/28 17:29:43 [Helm 2] Home folder "/Users/kycfeel/.helm" deleted.
2019/12/28 17:29:43 Helm v2 data was cleaned up successfully.

그렇게 님은 가셨다.

만약 다시 Helm v2 명령어를 실행한다면, 아래와 같이 Tiller Pod를 찾을 수 없다는 메시지가 뜰 것이다.

kycfeel-MBP:darwin-amd64 kycfeel$ helm ls
Error: could not find tiller

더 이상 흔적을 찾지 말자. 나한테만 남은 미련은 곧 비극이다.

마무리

지금까지 위의 과정을 통해 Helm v2를 v3로 별다른 어려움 없이 마이그레이션 했다. Helm에서 잘 만들어진 플러그인을 제공해주는 덕에, 서버에 깊게 얽혀있는 메이저 버전 업그레이드 치고 아주 손쉽게 마이그레이션을 마칠 수 있었다.

이제 기존에 사용하던 helm install이나 helm upgrade` 등을 테스트해보며 모든 기능이 원하는데로 작동하는지도 꼭 확인하자.

하나 더, 위에도 언급했지만 Helm v3는 출시된지 이제 약 한달밖에 지나지 않은 말 그대로의 신생 버전이다. 나름 stable 릴리즈인 만큼 큰 문제는 없을 것으로 예상하지만, 아주 크리티컬한 프로덕션에서 Helm을 사용해야 한다면 앞으로 최소 몇개월은 Helm v2를 사용하며 v3의 동향을 보는 것을 추천한다. Helm같은 로우 레벨 유틸리티의 버그는 시스템 관리자의 흰머리 생성에 아주 큰 기여를 하니까 말이다 😉.

마지막으로, helm3보다 helm 으로 명령어를 호출하는 것이 더 익숙하다면 /usr/local/binhelm3helm으로 리네이밍 해주자.

끗.