はじめに
k8sでIacをやる場合はGCPとかAWSの世界はterraformでk8sの世界はmanifestで設定するパターンでそれぞれの設定ファイルを書いてる人は多いんじゃ無いかなと思います。
k8s固有のリソースといいつつIngress
やService(type:LoadBalancer)
などはPaaS側にロードバランサーのリソースが生成されたり、GCPのNEGなんかはk8sの設定にリソースの設定が依存するということがあります。
上記のような場合、どこら辺で双方の棲み分けを区切るのが良いのか考えてみることとしました。
注意:この記事では結論が出ません
とりあえず書いてみる
とりあえず下記のように書いてみました。
k8s.tf
https://gist.github.com/junpayment/825b1cc35608036eaa37b3bf9c0e65ef
vars.tfvars
https://gist.github.com/junpayment/3cd661d75bbdb7439e4820ebe0d9f26e
オペレーションはこう
terraform init
terraform apply -var-file=vars.tfvars
感想s
terraformのk8sの構造はk8s manifest yamlの構造と大体同じ
Deployment
の構造を比較してみると構造はほぼ同じです。各パラメタの名前だけlowerCamel -> snake_case
になってますね。
terraformで記述していくとk8s側のmanifestでのオペレーションを忘れそうな気がしてたんですが、変に抽象化してるわけじゃなかったんで大丈夫そうですね。
k8s
https://kubernetes.io/ja/docs/concepts/workloads/controllers/deployment/
terraform
https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/deployment_v1
context名が事前にわからない
ローカルで作業してるのでgcloud container get-credentials
をした後にterraform apply
をすることになるんですが、その時までconfig_context
の文字列が決まらない問題があります。
provider "kubernetes" {
config_path = "~/.kube/config"
config_context = var.config_context
}
context名は例えばgke_project-name_us-central1-a_cluster-name
のようにプラットフォーム名やゾーン名である程度予測はできるとは思いますが。
PaaSのリソースとk8sのリソースの依存関係について
depends_on
で依存関係->ビルド順番を定義できるのはマニフェストを分けてたら出来ないのでこれは良いです。
k8s側のリソースの依存関係ルートはnamespace
と決めておくのが良さそうです。
resource "kubernetes_namespace" "test" {
depends_on = [
google_container_cluster.test,
google_container_node_pool.test
]
metadata {
name = "test"
}
}
リポジトリの責務の分解
PaaSリソースとk8sリソースの設定について書いてきましたが、アプリケーションのリポジトリはどこまでを責務にするのかも考える必要がありますよね。
例えばwebアプリケーションであればDockerfile
でExposeするポート番号やCDは何をトリガーにするのかとか。
今回はnginxdemos/hello:plain-textというコンテナイメージを使ったんですがどのポートでListenしてるかはDockerfile
というかアプリケーションに依存してます。
image = "nginxdemos/hello:plain-text"
resource "kubernetes_service" "test" {
metadata {
name = "test"
namespace = kubernetes_namespace.test.metadata[0].name
}
spec {
selector = {
app = kubernetes_deployment.test.spec[0].template[0].metadata[0].labels.app
}
session_affinity = "ClientIP"
port {
port = 80
target_port = 80
}
type = "LoadBalancer"
}
}
関心の分離を図りたいならお互いのリポジトリを意識したく無いですよね。
k8sのapi versionに追随したいぞ
k8s apiのバージョンアップに伴い、k8s manifestも構造変化が発生するので、kubectl apply
をする場合でも都度構造をメンテナンスする必要があります。
terraform側で構造を抽象化してる訳でも無いっぽいので、全部terraformにしてもメンテナンスコストも同時に解決できるって訳でも無さそうですね。
まとめ
terraformで全部書く=k8s manifestをterraformで書くこと自体はterraformのstateや依存関係とかのエコシステムを利用できるようになるので、メリットがありそうです。
どこで各リポジトリの責務を分けて行くのかはチームの責務やCI/CD戦略に合わせて考えてみると面白そうですね。
とりとめなく感想を書いただけで結論はないんですが以上です。