はじめまして、SREのid:renjikari です。この記事はfreee Developers Advent Calendar 2019の3日目です!
はじめに
freeeではKubernetesを本番環境にも利用しており、そのマニフェスト管理にはhelm&helmfileを使っています。 helmについてはたくさんの情報がインターネットにあるものの、helmfileに関しては今のところ記事や事例が少なく、 とても便利なmoduleなんですが、ちょっと導入障壁が高いのかなと思ったりします。
helmfileかなりいいと思うんだけど、あんまり解説とかないし、ググると大体社内の人が引っかかるのでお手製スクリプトかなんかに思えてくる
— レンジ (@renjikari) November 11, 2019
先日こんなつぶやきをしたところ、脳内に「お前がやるんだよ!」という言葉が響いてきたので書いていきます。
(なお、このAdvent Calendarは会社の公式ブログでやることを前日に知ったのでなんかちょっと他と毛並みが違かったらすいません)
helmについて
本記事はhelmfileの入門を目指すものですが、一応helmについても少しだけ触れておきます。 helmはKubernetesのためのpackage managerと呼ばれています。KuberntesのManifestをCharts(設計図)としてまとめて管理することのできるものになっています。 CNCFで管理されており、今日時点でIncubating Projectに位置しています。
helmの大きな3つの特徴だけ説明します。
- Chartがpackageになっていること。Chartの中にはK8sで動くリソース定義が入っています。Apt dpkgやYum RPM fileに似ているものと考えられます。
- ChartのためのRepositoryが存在します。Chartを集め、共有するためです。これもAptやYumのrepositoryを想像するとわかりやすいかもしれません
- 最後はK8s上で動くchartのinstanceに相当するReleaseです。heleはChartをReleaseという単位でデプロイしていくものになります。
さらに詳しくは別のhelmの解説をお読みください
How to install helmfile
公式のinstallationを参考に簡単にinstallできます。
helmfileについて
helmfileはhelm chartをより宣言的にデプロイするためのものです。 helmfileを使うことで以下のようなことができます
- ChartやReleaseのための変数を宣言するファイルをきれいなディレクトリ構造に収めバージョン管理すること。またそれによる再現性の確保
- Chartの再利用性をより高める
- 変更に対してCI/CDを使いやすくなる
ここからは実際にデプロイする際のhelmとhelmfileの差について解説していきます。
実行環境について
つい半月ほど前にhelm v3.0.0が出たんですが今回はv2.14.3で以下を実行しています。 また、Kubernetes ClusterはDocker for MacのKubernetesを利用しており、clientもserverもversionは1.14です。
実際にhelmとhelmfileを使うところをみて実感を得る
さて、ここからはhelmの利点でもあるstableにあるChart(今回はenvoy)をKubernetes Clusterにデプロイするところで違いをみていきます。 なお、すべての工程において、実際にはcreate namespaceが必要なので実際に試される際には注意して下さい
その1 シンプルにstable/envoyをinstall
helmの場合
- 以下のように簡単にinstallできます
helm tiller run -- helm install stable/envoy --name helm-envoy
- こんな感じで確認できます(いらない出力はばっさりカットしてます)
❯ helm tiller run -- helm ls Running: helm ls NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE helm-envoy 1 Tue Dec 3 01:08:13 2019 DEPLOYED envoy-1.9.0 1.11.2 helm-envoy
❯ kubectl run -it --rm --image alpine:3.9 tester sh / # apk add --update curl / # curl -I http://envoy:10000 HTTP/1.1 200 OK
helmfileの場合
- ディレクトリ構成とyamlファイルはこんな感じです
❯ tree . ├── envoy │ └── helmfile.yaml └── helmfile.yaml
❯ cat ./helmfile.yaml helmfiles: - ./envoy/helmfile.yaml #- ./other-app/helmfile.yaml
❯ cat ./envoy/helmfile.yaml releases: - name: helmfile-envoy namespace: helmfile-envoy chart: stable/envoy
- デプロイするためのコマンド
helm tiller run -- helmfile sync
- helmのときと同様に適当なコンテナを立ててcurlすると200が返ってきます。
- このhelmとhelmfileを比べるとまだあまりhelmfileの良さが分かりづらいですが、より宣言的に記述できそうに見えますね
- 次はChartに渡したい変数がある場合についてみていきます
その2 envoyをinstallするときに変数を渡す
helmの場合
- 今回はこんな変数を渡します
- type: LoadBalancer にすることで直接envoyを呼べます
service: type: LoadBalancer ports: n0: port: 11111 targetPort: 10000 protocol: TCP
- valuesを読んでデプロイ
helm tiller run -- helm install stable/envoy --name helm-envoy -f envoy/values.yaml
- 結果
❯ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE envoy LoadBalancer 10.103.54.185 <pending> 11111:32001/TCP,10000:30175/TCP 3s ❯ curl -I localhost:11111 #localから実行 HTTP/1.1 200 OK
helmの場合
- valuesは同じものを利用します
- 一つ前の例から変更したhelmfileとディレクトリ構造はこんな感じ
❯ tree . ├── envoy │ ├── helmfile.yaml │ └── values.yaml └── helmfile.yaml
❯ cat ./envoy/helmfile.yaml releases: - name: helmfile-envoy namespace: helmfile-envoy chart: stable/envoy values: - values.yaml
- deployコマンドは全く同じで
helm tiller run -- helmfile sync
- この例をみると、まずhelmではvalues fileを呼ぶことがコマンドベースで表現されていますが、helmfileでは宣言的に表現されています。
- 実際の本番運用にはたくさんの変数を利用することを考えると、これは大きな利点になります
さらなるhelmfileの利点
- ここまで読んでいただいて、helmfileの使い方はわかったかと思います。
- 実際にK8sを本番サービスの基盤として利用する場合には、production/staging/developなどの環境が必要になるでしょう
- そんな場合にもうまく再利用しつつ対応できます
- まずはディレクトリ構造とyamlの差分をすべて書きます
❯ tree . ├── envoy │ ├── environment │ │ ├── develop │ │ │ └── values.yaml │ │ ├── production │ │ │ └── values.yaml │ │ └── staging │ │ └── values.yaml │ ├── helmfile.yaml │ └── values.yaml └── helmfile.yaml
❯ cat ./helmfile.yaml environments: develop: staging: production: helmfiles: - ./envoy/helmfile.yaml #- ./other-app/helmfile.yaml
❯ cat ./envoy/helmfile.yaml environments: develop: values: - environment/develop/values.yaml staging: values: - environment/staging/values.yaml production: values: - environment/production/values.yaml releases: - name: helmfile-envoy-{{ .Values.stage }} namespace: helmfile-envoy-{{ .Environment.Name }} chart: stable/envoy values: - values.yaml
❯ cat ./envoy/environment/staging/values.yaml stage: staging
- この状態で
helm tiller run -- helmfile -e staging sync
というコマンドを打てば- release nameが
helmfile-envoy-staging
- namespaceが
helmfile-envoy-staging
- release nameが
- となってデプロイされます。
- このようにhelmfile自体にもchartにも変数を渡すことができ便利です。
- ここまで紹介してきたような利点を使いさらにCI/CDと組み合わすことで、複数環境/複数clusterに対応可能な柔軟なマニフェスト管理を行えます。
参考と引用
- https://landscape.cncf.io/format=card-mode&project=incubating&selected=helm
- https://helm.sh/docs/intro/using_helm/
- https://github.com/roboll/helmfile#about
明日は新卒のid:MitubaEX です!楽しみ!!