はじめに
Kubernetes / Openshift の テンプレートエンジンとして、Openshift のテンプレート機能を試してみたので、その結果をアウトプットとして残しておきます。もし、他にも同じような取り組みをされている方がいらっしゃいましたら、よい方法を教えていただけると幸いです。
Kubernetesにおける 宣言的な設定 について
「宣言的な記述による設定」は、Kubernetes/Openshiftの最も重要な機能です。(と私は考えています)
「宣言的な記述」とは、アプリケーションを稼働させるシステムの「あるべき姿」を記述することです。「宣言的な記述による設定」は、それだけで、そのあるべき姿が実現できることです。Kubernetes/Openshiftにおいて、コンテナそのものに限らず、ストレージやネットワーク、シークレットやレジストリなど、アプリケーションを稼働させるために必要な構成を、全て「宣言的な記述による設定」として管理することができます。
今まで
従来、以下のようなツールを用いて、クラウドサービスやその上のOS・ミドルウェアへ、宣言的な記述での設定・構成が行われてきました。ツールを用いた宣言的な記述を通して、ITインフラをコードで構成・管理する考え方を Infrastructure as Code と呼びます。
- クラウドサービスに対して ... AWS CFn, Azure ARM Template, Terraform
- OS・ミドルウェアに対して ... ChefやAnsibleなどの構成管理ツール
一方、以下のようなことに起因して理想的に宣言的なコードが書けないシーンがあることも、また事実です。
- ツールの仕様がしょぼい、機能が足りない
- そもそもクラウドサービスやOS・ミドルウェアが宣言的な記述での設定を想定して作られていない
- 手作業前提の手順をそのまま無理やり宣言的なコードで記述しようとしている
結果、「Infrastructure as Code疲れ」という言葉を産み出してしまいました。
これから
一方、Kubernetesは リソースをあるべき姿と突き合わせ、差分があると埋めてくれるReconciliation Loop (突合せループ)と呼ばれる機能が実装されているなど、Infrastructure as Code Nativeなソフトウェアです。これにより、従来、TerraformやChefでやりたかった宣言的な記述による設定が、よりシンプルに・強力に・実用的になったと感じています。
Kubernetes/Openshift の宣言的な記述をもつ設定ファイルをマニフェストといいます。再掲しますが、Kubernetes/Openshiftにおいて、コンテナそのものに限らず、ストレージやネットワーク、シークレットやレジストリなど、アプリケーションを稼働させるために必要な構成を、全て「宣言的な記述による設定」として管理することができます。
また、マニフェストは通常YAML形式で記述します。YAML形式はプレーンテキストであり、Gitでバージョン管理するのに適した形式です。
ゆえに、Kubernetes/Openshiftでアプリケーションやシステムを運用する上で、Gitによるマニフェストの管理は非常に重要です。Gitによるマニフェストの管理することは、GitでKubernetes/Openshiftを管理することとほぼ同義です。私達が今までやってきた運用、これからやろうとしている運用が、上記のKubernetes/Openshiftのメリットを崩さないように十分注意する必要があります。
テンプレートエンジンが必要な理由
Git(Github)を中心とした Kubernetes/Openshiftの運用を考える上で、基本的な考え方は以下の通りです。
- 開発環境でコンテナイメージとマニフェストを開発・テスト
- Gitレポジトリのdevブランチにpush 1
- devブランチ -> prodブランチに Pull Request
- Merge後、本番環境にマニフェストをapply
ところが現実世界では、なかなかそうはうまくいきません。開発環境での開発・テストを終え、いざ本番環境にapplyしようとすると、いろいろな不都合が生じます。
- Dev環境とProd環境でパラメータを変えたい(からマニフェストを修正しないといけない)
- そもそも権限分離の関係で、namespaceが違う(からマニフェストを修正しないといけない)
- もっというとコンテナレジストリも違う(からマニフェストを修正しないといけない)
本番環境にマニフェストを適用する際に、開発環境でテスト済みのマニフェストを手で編集してから適用するのは、私達自身のあるべき姿ではないはずです。所謂、「運用で回避」は悲劇しか生みません。上記の制約を解決する仕組みづくりが大切です。
上記を解決するための一つの方策が、manifestをパラメータに応じて生成してくれるテンプレートエンジンの活用です。マニフェストのテンプレートエンジンとして代表的なものとしては以下が挙げられます。
- Helm
- Kustomize
- Openshift テンプレート機能
結論から言うと、今回、私は Red Hat Openshiftで使うマニフェストのテンプレートエンジンを探していたので、3. Openshift テンプレート機能
を採用してみました。
Helm
Helm(公式) は 設定済みのKubernetesリソースパッケージである Helm Chartsを管理するためのツールです。マニフェストの生成ができますが、機能的にtoo muchであったため、まずは見送りました。
Kustomize
Kustomizeは、Kubernetes向けのマニフェストManagementツールです。(公式Github) Kubernetesの設定コマンドである kubectl
と統合され、kubectl
経由で利用することができます。
ただし、以下のような記述を見つけたので、IBM CloudのOpenshift3.11ユーザーな私は採用を見送りました。
注記:バージョン 3.11 を実行する OpenShift クラスターでは Kustomize はサポートされていません。
Openshift テンプレート機能の検証
早速、Openshiftのテンプレート機能を試してみます。コマンド的には、Openshiftの ocコマンドに統合されているため、新規に準備するものは マニフェストのテンプレートファイルと設定値ファイルの2つになります。
テンプレートファイル
手元にあったNetwork LoadBalancerのマニフェストを元にテンプレートを作成します。実際のマニフェストは objects:
から parameters:
までになります。置換したいパラメータを "${PRIVATE_VLANID}"
のように変数化します。テンプレートファイルを配置するディレクトリは、分かりやすければどこでも良いようです。
apiVersion: v1
kind: Template
metadata:
name: nlb-template
annotations:
description: "NLB template for cluster"
tags: "sample-tag"
objects:
- apiVersion: v1
kind: Service
metadata:
name: nlb
annotations:
service.kubernetes.io/ibm-load-balancer-cloud-provider-ip-type: private
service.kubernetes.io/ibm-load-balancer-cloud-provider-vlan: "${PRIVATE_VLANID}"
spec:
type: LoadBalancer
selector:
app: sampleapp
ports:
- name: port01
protocol: TCP
port: 12345
- name: port02
protocol: TCP
port: 12346
loadBalancerIP: ${LBIP}
parameters:
- description: private_vlanid
displayName: private_vlanid
name: PRIVATE_VLANID
required: true
- description: LoadBalancer_IP
displayName: LoadBalancer_IP
name: LBIP
required: true
パラメータファイル
パラメータ化の実際の値を記入するパラメータファイルを作成します。本番環境用と開発環境用のパラメータファイルを作成し、いずれもテンプレートファイルと一緒にバージョン管理します。パラメータファイルを配置するディレクトリは、分かりやすければどこでも良いようです。
PRIVATE_VLANID=010001
LBIP=10.0.0.1
PRIVATE_VLANID=000001
LBIP=192.168.0.1
生成
早速マニフェストを生成してみます。まずは、開発環境用です。
$ oc process --local -f template/nlb_template.yaml --param-file build/dev --output yaml
apiVersion: v1
items:
- apiVersion: v1
kind: Service
metadata:
annotations:
service.kubernetes.io/ibm-load-balancer-cloud-provider-ip-type: private
service.kubernetes.io/ibm-load-balancer-cloud-provider-vlan: "010001"
name: nlb
spec:
loadBalancerIP: 10.0.0.1
ports:
- name: port01
port: 12345
protocol: TCP
- name: port02
port: 12346
protocol: TCP
selector:
app: sampleapp
type: LoadBalancer
kind: List
metadata: {}
パラメータ化した部分が実際の値に置き換わっているのが分かります。
次に、本番環境用のマニフェストを生成します。
$ oc process --local -f template/nlb_template.yaml --param-file build/prod --output yaml
apiVersion: v1
items:
- apiVersion: v1
kind: Service
metadata:
annotations:
service.kubernetes.io/ibm-load-balancer-cloud-provider-ip-type: private
service.kubernetes.io/ibm-load-balancer-cloud-provider-vlan: "000001"
name: nlb
spec:
loadBalancerIP: 192.168.0.1
ports:
- name: port01
port: 12345
protocol: TCP
- name: port02
port: 12346
protocol: TCP
selector:
app: sampleapp
type: LoadBalancer
kind: List
metadata: {}
パラメータファイルの値によって、本番環境用のマニフェストが生成されたのが分かります。
また、以下のようにすることで、生成されたマニフェストを直接 oc apply
することも可能です。実際には、このコマンドをShell Scriptでラッピングして生成・適用を一気に行ったり、CIに登録することになるでしょう。
$ oc process --local -f template/nlb_template.yaml --param-file build/prod | oc apply -f -
まとめ
マニフェストのテンプレートエンジンが必要な理由を説明した上で、実際に Openshiftのテンプレート機能を使って、テンプレートから本番環境・開発環境用のマニフェストを生成してみました。
Kubernetes/Openshiftを実際に運用することを見据えると、理想通りにいかないことが増えてくるものです。それを今まで通り、「運用で回避」「職人が手で対応」とかやっていると、Kubernetes/Openshiftの良いところをスポイルしてしまうことになります。ノウハウやツールを共有することで、より楽に運用できるように取り組みたいと思います。
参考
運用課題の指南書、Kubernetesで実践するクラウドネイティブDevOps
「Kubernetesで運用する」その前に Kubernetesを本番環境で利用する際のポイント
-
featureブランチにpushして、devブランチへのPull Requestを挟むかもしれません ↩