LoginSignup
3
1

More than 1 year has passed since last update.

terraformでclusterからk8sのリソースを作ってみてmanifestの棲み分けについて考えてみる

Posted at

はじめに

k8sでIacをやる場合はGCPとかAWSの世界はterraformでk8sの世界はmanifestで設定するパターンでそれぞれの設定ファイルを書いてる人は多いんじゃ無いかなと思います。

k8s固有のリソースといいつつIngressService(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戦略に合わせて考えてみると面白そうですね。

とりとめなく感想を書いただけで結論はないんですが以上です。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1