Pulumi を使って Kubernetes へ CRD を登録
Pulumi は JavaScript・Python・Go のようなプログラミング言語で Infrastructure as Code するためのツールです。
今回は、この Pulumi を使って Kubernetes(k3s を使用)へカスタムリソースを登録してみます。
ソースは http://github.com/fits/try_samples/tree/master/blog/20190825/
はじめに
今回は、k3s(Lightweight Kubernetes) がインストール済みの Ubuntu 環境を使います。※
※ ただし、k3s の前に microk8s をインストールしたりしているので クリーンな環境とは言えないかもしれない (Istio と Knative のために Helm 等をインストールしていたりもする)
Pulumi を以下のようにインストールします。
Pulumi インストール例
$ curl -fsSL https://get.pulumi.com | sh
$HOME/.pulumi
ディレクトリへ各種ファイルが展開され、.bashrc
ファイルへ PATH の設定が追加されました。
なお、このままだと pulumi コマンド実行時に kubeconfig を参照できないようだったので、とりあえず /etc/rancher/k3s/k3s.yaml
を $HOME/.kube/config
ファイルとしてコピーし chown しています。
動作確認
$ pulumi version v0.17.28
Kubernetes へ CRD を登録(Node.js 使用)
準備
プロジェクトを作成する前に、まずは Pulumi でログインを実施しておきます。
今回はローカル環境の Kubernetes を使うので --local
を指定して login を実施しました。
ログイン
$ pulumi login --local
プロジェクト作成
適当なディレクトリを用意し、テンプレートを指定してプロジェクトのひな型を作成します。
今回は Kubernetes を対象とした Node.js 用のプロジェクトを作成するため kubernetes-javascript
を指定しました。
プロジェクト作成
$ mkdir sample $ cd sample $ pulumi new kubernetes-javascript ・・・ project name: (sample) project description: (A minimal Kubernetes JavaScript Pulumi program) Created project 'sample' stack name: (dev) Enter your passphrase to protect config/secrets: Re-enter your passphrase to confirm: Created stack 'dev' Enter your passphrase to unlock config/secrets (set PULUMI_CONFIG_PASSPHRASE to remember): Installing dependencies... ・・・
実装
上記で生成された index.js
ファイルに Kubernetes へ登録する内容を実装していきます。
今回は下記のようなカスタムリソースの登録を実装します。
例. カスタムリソース登録内容
apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: name: items.example.com spec: group: example.com version: v1alpha1 scope: Namespaced names: kind: Item plural: items singular: item preserveUnknownFields: false validation: openAPIV3Schema: type: object properties: spec: type: object properties: value: type: integer note: type: string --- apiVersion: "example.com/v1alpha1" kind: Item metadata: name: item1 spec: value: 100 note: sample item 1 --- apiVersion: "example.com/v1alpha1" kind: Item metadata: name: item2 spec: value: 20 note: sample item 2
上記のカスタムリソースを実装したコードが以下です。
Pulumi でカスタムリソースを定義する場合、@pulumi/kubernetes
の CustomResourceDefinition
と CustomResource
を使えば良さそうです。
YAML と同等の内容を JavaScript の Object で表現して、CustomResourceDefinition 等のコンストラクタの第 2引数として渡すだけです。
index.js (カスタムリソース登録内容の実装)
'use strict' const k8s = require('@pulumi/kubernetes') const capitalize = s => `${s[0].toUpperCase()}${s.slice(1)}` const crdName = 'item' const crdGroup = 'example.com' const crdVersion = 'v1alpha1' const props = { value: 'integer', note: 'string' } const items = [ { name: 'item1', value: 100, note: 'sample item 1' }, { name: 'item2', value: 20, note: 'sample item 2' } ] const crdKind = capitalize(crdName) const crdPlural = `${crdName}s` new k8s.apiextensions.v1beta1.CustomResourceDefinition(crdName, { metadata: { name: `${crdPlural}.${crdGroup}` }, spec: { group: crdGroup, version: crdVersion, scope: 'Namespaced', names: { kind: crdKind, plural: crdPlural, singular: crdName }, preserveUnknownFields: false, validation: { openAPIV3Schema: { type: 'object', properties: { spec: { type: 'object', properties: Object.fromEntries( Object.entries(props).map(([k, v]) => [k, { type: v }] ) ) } } } } } }) items.forEach(it => new k8s.apiextensions.CustomResource(it.name, { apiVersion: `${crdGroup}/${crdVersion}`, kind: crdKind, metadata: { name: it.name }, spec: Object.fromEntries( Object.keys(props).map(k => [k, it[k]]) ) }) )
デプロイ
pulumi up でデプロイします。
デプロイ
$ pulumi up ・・・ Previewing update (dev): Type Name P + pulumi:pulumi:Stack sample-dev c + tq kubernetes:example.com:Item item2 c + tq kubernetes:example.com:Item item1 c + mq kubernetes:apiextensions.k8s.io:CustomResourceDefinition item c Resources: + 4 to create Do you want to perform this update? yes > no details
Do you want to perform this update?
で yes
を選択すると実際にデプロイが実施されます。
Do you want to perform this update? yes Updating (dev): Type Name S + pulumi:pulumi:Stack sample-dev c + tq kubernetes:apiextensions.k8s.io:CustomResourceDefinition item c + tq kubernetes:example.com:Item item1 c + mq kubernetes:example.com:Item item2 c Resources: + 4 created ・・・
ちなみに、details を選ぶと登録内容(YAML)を確認できます。
正常に登録されたか、kubectl コマンドで確認してみます。(k3s の一般的な環境では k3s kubectl とする必要があるかもしれません)
CRD の確認
$ kubectl get crd | grep items items.example.com 2019-08-14T08:57:22Z
カスタムリソースの確認
$ kubectl get item NAME AGE item1 13m item2 13m
カスタムリソース詳細1
$ kubectl describe item item1 Name: item1 Namespace: default Labels: app.kubernetes.io/managed-by=pulumi Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"example.com/v1alpha1","kind":"Item","metadata":{"labels":{"app.kubernetes.io/managed-by":"pulumi"},"name":"item1"},"spec":{... API Version: example.com/v1alpha1 Kind: Item Metadata: Creation Timestamp: 2019-08-14T08:57:22Z Generation: 1 Resource Version: 19763 Self Link: /apis/example.com/v1alpha1/namespaces/default/items/item1 UID: 87503274-be71-11e9-aeea-025c19d6acb9 Spec: Note: sample item 1 Value: 100 Events: <none>
カスタムリソース詳細2
$ kubectl describe item item2 Name: item2 Namespace: default Labels: app.kubernetes.io/managed-by=pulumi Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"example.com/v1alpha1","kind":"Item","metadata":{"labels":{"app.kubernetes.io/managed-by":"pulumi"},"name":"item2"},"spec":{... API Version: example.com/v1alpha1 Kind: Item Metadata: Creation Timestamp: 2019-08-14T08:57:22Z Generation: 1 Resource Version: 19764 Self Link: /apis/example.com/v1alpha1/namespaces/default/items/item2 UID: 875af773-be71-11e9-aeea-025c19d6acb9 Spec: Note: sample item 2 Value: 20 Events: <none>
問題なく登録できているようです。
アンデプロイ
デプロイ内容を削除(アンデプロイ)する場合は destroy を実行します。
アンデプロイ
$ pulumi destroy ・・・ Do you want to perform this destroy? yes Destroying (dev): Type Name S - pulumi:pulumi:Stack sample-dev d - tq kubernetes:apiextensions.k8s.io:CustomResourceDefinition item d - tq kubernetes:example.com:Item item2 d - mq kubernetes:example.com:Item item1 d Resources: - 4 deleted ・・・