はじめに
この記事の内容は個人の見解です。
また、ここに書かれている手段が唯一の解決策だという意図もなく、特定のツールを中傷するつもりもありません。
このブログポストのオチ
- ksonnetを使えばHelm Chartをカスタマイズできる
- ただし、hook機構を利用したChartはだめ(stable/spinnakerなど)
Helm は便利なツール、だけど
Kubernetesとお友達の皆さん、Helm使ってますか?使ってますよね、この記事を読んでいるんですから。
色々なChartが公開されていて便利です、Helm。
Nginx IngressやPromethes、GrafanaからMinecraftのサーバまで、手軽にデプロイできて、とてもとても助かります。
素敵ツールのHelmですが、しょっちゅう、これでもかと、耳にタコができるほど言われるのが、**「カスタマイズが辛い」**だと思います。
「ちょっとDeploymentのあそこをごにょごにょしたい」、「DaemonSetのあれをこれしたい」なんてときに、取れる手段は「Chartを落としてきて手で直す」です。
めんどくさいですね。とっても。ぶっちゃけやりたくない。
解決手段っぽいもの
辛い思いをしている我々に救いの手を差し伸べるためかどうかは知りませんが、先日リリースされたあるツールの最新版でこんな機能が追加されました。
Added Helm Registry support where charts operate as ksonnet parts(意訳:Helm Chartをksonnetのパーツとして使えるよう、Helm Registryサポートを追加した)
はい、ksonnetです。
2018/08/02にリリースされたv0.12.0(リリースノート)でHelm Chartを使う機能が追加されました。
知名度がいまいちなksonnetですので、一旦さっくりと概要を説明します。
ksonnetはJsonnetの仕組みを使って、KubernetesのYAML地獄から逃れようというツールです。(jsonnetとはGoogleがjsonをなんやかんやするために作ったなんか難しいテンプレート言語です。)
ksonnetにもHelmのChartのようなものがあり、それはPrototypeと言います。これまたHelmのRepositoryのようなものはRegistryといいます。
そのRegistryとして、HelmのRepositoryを登録できるようになったというものが、前述のリリースノートで書かれた新機能です。
単純にいうと、ksonnetでHelmのChartがデプロイできるということです。
概要はこの程度にしておいて、実際に使う方法を解説します。
ksonnetでHelmのChartをデプロイする
とりあえずstable/rocketchatでRocket.Chatをデプロイします。MySQLとか入れても面白くないので。
ksonnetでHelmのRepositoryを追加するのはksonnetのアプリケーションを作ったあとなので、ツールのインストール(Mac)〜ksonnetのアプリケーション作成までをやります。
$ brew install ks kubernetes-cli# ksonnetと、kubectlをインストール
$ ks version # バージョン確認。ksonnet versionが0.12.0以上でなければならない。
ksonnet version: 0.12.0
jsonnet version: v0.11.2
client-go version: kubernetes-1.10.4
$ # なんとかしてkubernetesのAPIを叩けるようにしておく。~/.kube/configをなんとかしたり
$ ks init rocketchat # ksonnetアプリケーションの作成。この時点でKubernetesに接続できる必要あり
$ cd rocketchat
これでksonnetのアプリケーションができました。以下のようなファイルツリーになっています。
$ tree .
.
├── app.yaml
├── components
│ └── params.libsonnet
├── environments
│ ├── base.libsonnet
│ └── default
│ ├── globals.libsonnet
│ ├── main.jsonnet
│ └── params.libsonnet
├── lib
│ └── ksonnet-lib
│ └── v1.11.0
│ ├── k.libsonnet
│ ├── k8s.libsonnet
│ └── swagger.json
└── vendor
7 directories, 9 files
アプリケーションを作成したあとは以下の流れでHelmのChartをデプロイします。
- HelmのRepositoryをRegistryとして追加
- Prototypeを適用
- パラメータを指定
- デプロイ
HelmのRepositoryをRegistryとして追加
ks registry add --help
でヘルプを見ると、ks registry add helm-stable https://kubernetes-charts.storage.googleapis.com
をたたけと書かれているので叩きます。stableのリポジトリのURLですね。
$ ks registry add helm-stable https://kubernetes-charts.storage.googleapis.com
$ ks registry list # helm-stableが追加されている。
NAME OVERRIDE PROTOCOL URI
==== ======== ======== ===
helm-stable helm https://kubernetes-charts.storage.googleapis.com
incubator github github.com/ksonnet/parts/tree/master/incubator
追加されたRegistoryのPROTOCOLがhelmとなっていますね。
ちなみに、ファイルの変更点はapp.yamlのregistriesに数行追加されただけです。
diff --git a/app.yaml b/app.yaml
index a1cff24..62f7ee1 100644
--- a/app.yaml
+++ b/app.yaml
@@ -9,6 +9,9 @@ environments:
kind: ksonnet.io/app
name: rocketchat
registries:
+ helm-stable:
+ protocol: helm
+ uri: https://kubernetes-charts.storage.googleapis.com
incubator:
protocol: github
uri: github.com/ksonnet/parts/tree/master/incubator
Prototypeを適用
Prototypeを適用する前にまずPackageをインストールする必要があります。ksonnetではPrototypeはかならずPackageに含まれているので、先にPackageをインストールします。
$ ks pkg list # Packageの一覧を確認する。
REGISTRY NAME VERSION INSTALLED ENVIRONMENTS
======== ==== ======= ========= ============
helm-stable acs-engine-autoscaler 2.2.0
helm-stable aerospike 0.1.7
helm-stable anchore-engine 0.2.0
...(すごく多いので略
helm-stable risk-advisor 2.0.4
helm-stable rocketchat 0.1.3
helm-stable rookout 0.1.0
...(さらに略
incubator redis 40285d8a14f1ac5787e405e1023cf0c07f6aa28c
incubator tomcat 40285d8a14f1ac5787e405e1023cf0c07f6aa28c
$
$ ks pkg install helm-stable/rocketchat # helm-stableのrocketchatをインストール
Packageをインストールした段階で、vendorディレクトリにHelmのChartが追加され、app.yamlが修正されます。
$ tree .
.
├── app.yaml
(略
└── vendor
└── helm-stable
└── rocketchat
└── helm
└── 0.1.3
└── rocketchat # HelmのChartがそのままここに追加されている。
├── Chart.yaml
├── charts
│ └── mongodb
│ ├── Chart.yaml
│ ├── README.md
│ ├── templates
│ │ ├── NOTES.txt
│ │ ├── _helpers.tpl
│ │ ├── deployment.yaml
│ │ ├── pvc.yaml
│ │ ├── secrets.yaml
│ │ └── svc.yaml
│ └── values.yaml
├── requirements.lock
├── requirements.yaml
├── templates
│ ├── NOTES.txt
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── ingress.yaml
│ ├── pvc.yaml
│ ├── secrets.yaml
│ └── svc.yaml
└── values.yaml
16 directories, 29 files
diff --git a/app.yaml b/app.yaml
index 62f7ee1..672b666 100644
--- a/app.yaml
+++ b/app.yaml
@@ -7,6 +7,11 @@ environments:
k8sVersion: v1.11.0
path: default
kind: ksonnet.io/app
+libraries:
+ rocketchat:
+ name: rocketchat
+ registry: helm-stable
+ version: ""
name: rocketchat
registries:
helm-stable:
これでPrototypeが使えるようになったので、適用します。
$ ks prototype list #一覧を確認
NAME DESCRIPTION
==== ===========
io.ksonnet.pkg.configMap A simple config map with optional user-specified data
io.ksonnet.pkg.deployed-service A deployment exposed with a service
io.ksonnet.pkg.helm-stable-rocketchat Helm Chart rocketchat from the helm-stable registry
io.ksonnet.pkg.namespace Namespace with labels automatically populated from the name
io.ksonnet.pkg.single-port-deployment Replicates a container n times, exposes a single port
io.ksonnet.pkg.single-port-service Service that exposes a single port
$
$ ks generate io.ksonnet.pkg.helm-stable-rocketchat -h # prototypeのパラメータを確認する
Usage of prototype-flags:
--module string Component module
--name string Name of the component
--values string Helm values (default "{}")
--values-file string Prototype values file (file returns a Jsonnet object)
-v, --verbose count[=-1] Increase verbosity. May be given multiple times.
--version string Version of the Helm chart. If blank, it will use latest installed version (default "0.1.3")
$ ks generate io.ksonnet.pkg.helm-stable-rocketchat my-app --name my-rocketchat # 適用。とりあえずは最低限だけ指定。
components/my-app.yamlが作成され、components/params.libsonnetが変更されました。my-app.yamlがデプロイするアプリケーション本体です。params.libsonnetはアプリケーションに設定するパラメータのデフォルト値が格納されます。ks generate
時に指定したパラメータがparams.libsonnetに格納されています。
$ tree .
.
├── app.yaml
├── components
│ ├── my-app.jsonnet
│ └── params.libsonnet
├── environments
│ ├── base.libsonnet
(略
diff --git a/components/params.libsonnet b/components/params.libsonnet
index 4fe2a83..9603e7d 100644
--- a/components/params.libsonnet
+++ b/components/params.libsonnet
@@ -6,5 +6,10 @@
components: {
// Component-level parameters, defined initially from 'ks prototype use ...'
// Each object below should correspond to a component in the components/ directory
+ "my-app": {
+ name: "my-rocketchat",
+ values: {},
+ version: "0.1.3",
+ },
},
}
パラメータを指定
このままではChartにパラメータを指定しないのと変わりないので、values.yamlにあたる設定をします。
ksonnetでmy-appにvaluesを指定するときはcomponents/params.libsonnetのcomponents.my-app.valuesに値を設定します。
たとえば、Rocket.ChatのChartでIngressを有効にする場合は、ingress.enabledにtrueを設定します。これをksonnetで指定する場合、components.my-app.values.ingress.enabledにtrueを指定します。
$ ks param set my-app values.ingress.enabled true # ingress.enabledにtrueを設定する
$ ks param list # 確認
COMPONENT PARAM VALUE
========= ===== =====
my-app name 'my-rocketchat'
my-app values { ingress: {
enabled: true,
} }
my-app version '0.1.3'
diff --git a/components/params.libsonnet b/components/params.libsonnet
index 34469d7..eccdbad 100644
--- a/components/params.libsonnet
+++ b/components/params.libsonnet
@@ -6,6 +6,9 @@
"my-app": {
name: 'my-rocketchat',
values: {
+ ingress: {
+ enabled: true,
+ },
},
version: '0.1.3',
},
これで、パラメータが設定出来ました。
デプロイする
デプロイでは特に特殊なことはなく、ksonnetでデプロイするときのいつものやり方になります。
$ ks apply default
デプロイが完了したらポートフォワードを使って接続してみましょう
$ kubectl rollout status deployment my-rocketchat-rocketchat # デプロイが完了するのを待つ
$ kubectl port-forward my-rocketchat-rocketchat-68558f8689-hsm7z 8888:3000 # pod名はの後半はランダムなので、自分の環境で出来たものを確認してください。
http://localhost:8888 に接続すると、こんな画面が出るはずです。
これで、HelmのChartがksonnetで無事デプロイ出来ました。
ksonnetでHelmのChartをカスタマイズする
さて、ここからが本番です。
HelmのChartをカスタマイズするわけですが、いい例が全く思い浮かばないので、すべてのリソースにmetadata.labels.maintainer=fujiokaを追加しようと思います。
$ kubectl get deployment -o=custom-columns=NAME:.metadata.name,MAINTAINER:.metadata.labels.maintainer
NAME MAINTAINER
my-rocketchat-mongodb fujioka
my-rocketchat-rocketchat fujioka
変更するファイルはcomponents/my-app.jsonnetです。ks generate
で生成されたファイルですね。
カスタマイズするように修正したcomponents/my-app.jsonnetと、元ファイルとのdiffがこちら↓になります。
local env = std.extVar("__ksonnet/environments");
local params = std.extVar("__ksonnet/params").components["my-app"];
local chart_org = std.prune(std.native("renderHelmChart")(
// registry name
"helm-stable",
// chart name
"rocketchat",
// chart version
params.version,
// chart values overrides
params.values,
// component name
params.name,
));
[
w + {
metadata+: {
labels+: {
maintainer: "fujioka"
},
},
}
for w in chart_org
]
diff --git a/components/my-app.jsonnet b/components/my-app.jsonnet
index f3eb80e..c8b1532 100644
--- a/components/my-app.jsonnet
+++ b/components/my-app.jsonnet
@@ -1,7 +1,7 @@
local env = std.extVar("__ksonnet/environments");
local params = std.extVar("__ksonnet/params").components["my-app"];
-std.prune(std.native("renderHelmChart")(
+local chart_org = std.prune(std.native("renderHelmChart")(
// registry name
"helm-stable",
// chart name
@@ -12,4 +12,15 @@ std.prune(std.native("renderHelmChart")(
params.values,
// component name
params.name,
- ))
+ ));
+
+ [
+ w + {
+ metadata+: {
+ labels+: {
+ maintainer: "fujioka"
+ },
+ },
+ }
+ for w in chart_org
+ ]
HelmのChartから生成されたManifestをchart_orgに代入し、あとからちょろっと改造しているだけです。
今回は簡単な変更しかしていませんが、Jsonnetでできる修正であれば何でも可能なので、あなたがカスタマイズしたいようにJsonnetを書けば、あとは好き放題ということになります。
これで、Helm Chartのかゆいところに手が届きますね。
終わりに
ksonnetを使わなければHelmのChartがカスタマイズできないというわけではありませんのでご注意くださいませ。
Tillerを介さずデプロイすることになるため、HelmのHistory機能が使えなくなっていますし、そもそもJsonnetを覚えなければなりません。
ぶっちゃけhelm template
で生成したManifestをkustomizeでoverrideするだけでも事足りるし、簡単だと思います。(悔しいのでそのやり方はここでは書きません。)
Misc
- ksonnetで作られるファイルはJsonnetで書かれているものなので、さっぱり内容がわからないという方はJsonnetのチュートリアル(https://jsonnet.org/learning/tutorial.html)を参考にすると良いでしょう。
- 逆にJsonnetが読み書きできればかなりksonnetを使うのは楽だと思います。
- Jsonnetをググるときは
-Json.Net
をキーワードに追加したほうが良いと思います。 - VSCodeを使うとある程度補完が効いてManifestを楽に作れるようになるksonnetですが、HelmのChartをレンダリングする処理がksに入っているせいか、補完が効かなくなります。
-
パラメータの値にnullを指定すると、
ks param set
がエラーを吐きますが、ks apply
などは普通に出来ますので、ご安心を。 -
HelmのHook機構(これ)により起動されるものは、全て無視される。例えば、pre-installで動くJobがあった場合、そのJobは作られない。