TerraformでKubernetesのリソース(ConfigMapやSecretなど)を管理する

  • 4
    Like
  • 0
    Comment

TerraformはAWSなどのIaaS上でインフラを構築、管理するためのツールとしてよく使われてます。
一方、公式プラグインとしてKubernetesのリソースを管理するためのProviderが提供されており、これを使ってKubernetesのリソースを管理すると結構便利だったので紹介します。

kubectlでリソースを直接いじるのに比べると、

  • terraform planでDryRunできる
  • その際、もちろん既存のリソースとの差分を見ることができる
  • リソース同士の参照(Docker RegistryのSecretをPodから見るとか)をコード上で表現でき、参照が壊れてると実行前にエラーにできる
  • 変数や関数、モジュールを使用して定義を共通化できる
  • terraform destroyで全部なかったことにできる

あたりがメリットでしょうか。

では、以下Mac上にインストールしたminikubeにローカルのterraformからアクセスするというローカルに閉じた環境で、実際にKubernetesのリソースを管理する様をつらつらと書いていきます。

この記事で使用したterraformのプロジェクトは、以下にPushしているので併せてご参照ください。

https://github.com/literalice/terraform-kubernetes-demo

minikubeのインストールは超絶簡単なので、以下を参考にインストールしてみていただければと思います。

https://github.com/kubernetes/minikube

Kubernetes Providerの設定

terraformからKubernetesのクラスタを設定するために、本来は以下を参考に、apiserverのURLやユーザー名などの認証情報を設定する必要があります。

https://www.terraform.io/docs/providers/kubernetes/

ただ、minikube.kube/configに認証情報を書き込み、またterraformのKubernetes Providerはデフォルトで.kube/configを見るので、minikube環境にローカルからアクセスする場合は単に宣言だけで大丈夫です。

ここでは、terraform-kubernetes-demoというディレクトリを作成して、以下のファイルを作成することにします。

provider "kubernetes" {}

terraform initを実行することでKubernetes Providerがダウンロードされ、kubernetes-provider-demoディレクトリに設定されます。

Initializing provider plugins...
- Checking for available provider plugins on https://releases.hashicorp.com...
- Downloading plugin for provider "kubernetes" (1.0.0)...

ConfigMapをTerraformで管理する

まず、ConfigMapを管理してみます。現時点のKubernetes Providerだと、このConfigMapとSecretの管理が一番便利に感じるところです。

tfファイルは、以下のようになります。

resource "kubernetes_config_map" "infra" {
  metadata {
    name = "infra-env"
  }

  data {
    db_host = "dbhost:5432"
    cache_host = "cache:6379"
  }
}

さて、上記ファイルを適当なファイル名で作成し、terraform planでDry Runしてみます。
すると、以下のように作成されようとしているConfigMapが表示されます。

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  + kubernetes_config_map.infra
      id:                          <computed>
      data.%:                      "2"
      data.cache_host:             "cache:6379"
      data.db_host:                "dbhost:5432"
      metadata.#:                  "1"
      metadata.0.generation:       <computed>
      metadata.0.name:             "infra-env"
      metadata.0.namespace:        "default"
      metadata.0.resource_version: <computed>
      metadata.0.self_link:        <computed>
      metadata.0.uid:              <computed>


Plan: 1 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

実際に作成する前に内容を確認できるのがいいですね。

terraform applyとすると、実際にkubernetesクラスタにこのConfigMapが作成されます。

terraform apply

# kubernetes_config_map.infra: Creating...
#   data.%:                      "" => "2"
#   data.cache_host:             "" => "cache:6379"
#   data.db_host:                "" => "dbhost:5432"
#   metadata.#:                  "" => "1"
#   metadata.0.generation:       "" => "<computed>"
#   metadata.0.name:             "" => "infra-env"
#   metadata.0.namespace:        "" => "default"
#   metadata.0.resource_version: "" => "<computed>"
#   metadata.0.self_link:        "" => "<computed>"
#   metadata.0.uid:              "" => "<computed>"
# kubernetes_config_map.infra: Creation complete after # 0s (ID: default/infra-env)

# Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

kubectl describe cm infra-env

# Name:         infra-env
# Namespace:    default
# Labels:       <none>
# Annotations:  <none>

# Data
# ====
# cache_host:
# ----
# cache:6379
# db_host:
# ----
# dbhost:5432
# Events:  <none>

さらに、以下のようにConfigMapを変更してみます。

resource "kubernetes_config_map" "infra" {
  metadata {
    name = "infra-env"
  }

  data {
    db_host = "dbhost2:5432" # 変更する
    cache_host = "cache:6379"
  }
}

ここでterraform planを行うと、AWS Providerのような他Provider同様、差分が表示されます。

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  ~ kubernetes_config_map.infra
      data.db_host: "dbhost:5432" => "dbhost2:5432"


Plan: 0 to add, 1 to change, 0 to destroy.

------------------------------------------------------------------------

このように、実際に変更される前に、どのようにConfigMapが変更されるのか確認できます。
差分OKであれば、 terraform apply で差分を適用します。

terraform apply

# kubernetes_config_map.infra: Refreshing state... (ID: default/infra-env)
# kubernetes_config_map.infra: Modifying... (ID: default/infra-env)
#   data.db_host: "dbhost:5432" => "dbhost2:5432"
# kubernetes_config_map.infra: Modifications complete # after 0s (ID: default/infra-env)

SecretをTerraformで管理する

ConfigMap同様、Secretもterraformで管理できます。kubectlで作るのに比べてbase64エンコードもしてくれたりで直感的にSecretを作成できます。

まず、tfファイルを作成します。

resource "kubernetes_secret" "basic_auth" {
  metadata {
    name = "basic-auth"
  }

  data {
    username = "admin"
    password = "Admin"
  }

  type = "kubernetes.io/basic-auth"
}

terraform applyを実行すると、上記内容でSecretが作られます。base64でエンコードする必要もありません。

kubernetes_secret.basic_auth: Creating...
  data.%:                      "" => "2"
  data.password:               "<sensitive>" => "<sensitive>"
  data.username:               "<sensitive>" => "<sensitive>"
  metadata.#:                  "" => "1"
  metadata.0.generation:       "" => "<computed>"
  metadata.0.name:             "" => "basic-auth"
  metadata.0.namespace:        "" => "default"
  metadata.0.resource_version: "" => "<computed>"
  metadata.0.self_link:        "" => "<computed>"
  metadata.0.uid:              "" => "<computed>"
  type:                        "" => "kubernetes.io/basic-auth"
kubernetes_secret.basic_auth: Creation complete after 0s (ID: default/basic-auth)

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

では、少しこのtfファイルを変更してみます。ついでに、変数も使ってみます。

variable "basicPassword" {
}

resource "kubernetes_secret" "basic_auth" {
  metadata {
    name = "basic-auth"
  }

  data {
    username = "admin"
    password = "${var.basicPassword}"
  }

  type = "kubernetes.io/basic-auth"
}
TF_VAR_basicPassword=aaa terraform plan

# An execution plan has been generated and is shown below.
# Resource actions are indicated with the following symbols:
#   ~ update in-place

# Terraform will perform the following actions:

#   ~ kubernetes_secret.basic_auth
#       data.password: <sensitive> => <sensitive> (attribute changed)


# Plan: 0 to add, 1 to change, 0 to destroy.

このように、terraformであれば変数や参照、関数が利用できるので、構成を共有するのが楽そうですね。

Kubernetes ProviderのSecretリソースは、ファイルやテンプレートからSecretを作成することもできるので、Docker Registryの認証情報をKubernetesに設定するときなどに便利です。

https://www.terraform.io/docs/providers/kubernetes/r/secret.html

後片付け

terraform destroyで、上記で作成したリソースを全て削除できます。

terraform destroy


# kubernetes_config_map.infra: Refreshing state... (ID: default/infra-env)
# kubernetes_secret.basic_auth: Refreshing state... (ID: default/basic-auth)

# An execution plan has been generated and is shown below.
# Resource actions are indicated with the following symbols:
#   - destroy

# Terraform will perform the following actions:

#   - kubernetes_config_map.infra

#   - kubernetes_secret.basic_auth


# Plan: 0 to add, 0 to change, 2 to destroy.

# Do you really want to destroy?
#   Terraform will destroy all your managed infrastructure, as shown above.
#   There is no undo. Only 'yes' will be accepted to confirm.

#   Enter a value: yes

# kubernetes_config_map.infra: Destroying... (ID: default/infra-env)
# kubernetes_secret.basic_auth: Destroying... (ID: default/basic-auth)
# kubernetes_config_map.infra: Destruction complete after 0s
# kubernetes_secret.basic_auth: Destruction complete after 0s

# Destroy complete! Resources: 2 destroyed.

まとめ

Kubernetes Providerでは、その他にもServiceやPod、NamespaceやPVCなど、様々なリソースを管理できます(現時点ではPodはあってもDeploymentがないのが痛い)。

https://www.terraform.io/docs/providers/kubernetes/

terraformは差分が発生したことをコマンドのexit codeで知ることができたり、べき等性のあるコマンドでリソースを管理できたりとCIに組み込むのにとても便利な作りなので、インフラをJenkinsなどで管理しているのであれば一度Kubernetes Providerを試してみてはいかがでしょうか。