Terraformを試すときに困ったこと

サクッとTerraformを試してみたいと思ったときに悩む要素の一つがProviderの準備かと思います。
ベタなのはAWS/Azure/Google Cloud Platformあたりだと思います。ただそのためにわざわざアカウント作るのも手間だし、何よりTerraformを試したいだけなのにコストやセキュリティのことを心配したくないなと億劫になっていました。

Ansibleを使っていた頃はVagrant + VirtualBoxで簡単に実行先を作れたんですが、Terraformの場合どうするのがいいかと思ってProvider一覧を見ていたんですがKubernetesが意外といいんじゃないかと思い試してみました。

環境準備

% sw_vers
ProductName:		macOS
ProductVersion:		13.0.1
BuildVersion:		22A400

TerraformのインストールはHomebrewで行います。

Install Terraform

brew tap hashicorp/tap
brew install hashicorp/tap/terraform
[koh@Kohs-MacBook-Pro-M1-387] ~
% terraform --version
Terraform v1.3.7
on darwin_arm64
[koh@Kohs-MacBook-Pro-M1-387] ~
%

KubernetesはDocker Desktop for Macを利用します。

Install on Mac

インストールした後にKubernetesをenableするとローカルで利用できるようになります。

Deploy on Kubernetes

[koh@Kohs-MacBook-Pro-M1-387] ~
% kubectl config get-contexts
CURRENT   NAME             CLUSTER          AUTHINFO         NAMESPACE
*         docker-desktop   docker-desktop   docker-desktop
[koh@Kohs-MacBook-Pro-M1-387] ~
% kubectl get all
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   110d
[koh@Kohs-MacBook-Pro-M1-387] ~
%

動作確認

まずは適当なディレクトリを作成します。

[koh@Kohs-MacBook-Pro-M1-387] ~/work
% mkdir terraform-with-k8s
[koh@Kohs-MacBook-Pro-M1-387] ~/work
% cd !$
cd terraform-with-k8s
[koh@Kohs-MacBook-Pro-M1-387] ~/work/terraform-with-k8s
%

ここからドキュメントをもとにTerraformを書いていきます。
最初にmain.tfを用意し、Example Usageの内容をコピペします。
ローカルのDocker Desktopを利用するためconfig_contextを docker-desktopに変更します。

[koh@Kohs-MacBook-Pro-M1-387] ~/work/terraform-with-k8s
% cat main.tf
provider "kubernetes" {
  config_path    = "~/.kube/config"
  config_context = "docker-desktop"
}

resource "kubernetes_namespace" "example" {
  metadata {
    name = "my-first-namespace"
  }
}
[koh@Kohs-MacBook-Pro-M1-387] ~/work/terraform-with-k8s
%

terraform initによりKubernetes Providerをインストールします。

[koh@Kohs-MacBook-Pro-M1-387] ~/work/terraform-with-k8s
% terraform init

Initializing the backend...

Initializing provider plugins...
- Finding latest version of hashicorp/kubernetes...
- Installing hashicorp/kubernetes v2.16.1...
- Installed hashicorp/kubernetes v2.16.1 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
[koh@Kohs-MacBook-Pro-M1-387] ~/work/terraform-with-k8s
%

terraform planでドライランします。

[koh@Kohs-MacBook-Pro-M1-387] ~/work/terraform-with-k8s
% terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
  + create

Terraform will perform the following actions:

  # kubernetes_namespace.example will be created
  + resource "kubernetes_namespace" "example" {
      + id = (known after apply)

      + metadata {
          + generation       = (known after apply)
          + name             = "my-first-namespace"
          + resource_version = (known after apply)
          + uid              = (known after apply)
        }
    }

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

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run
"terraform apply" now.
[koh@Kohs-MacBook-Pro-M1-387] ~/work/terraform-with-k8s
%

terraform applyで実際に適用します。

[koh@Kohs-MacBook-Pro-M1-387] ~/work/terraform-with-k8s
% terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
  + create

Terraform will perform the following actions:

  # kubernetes_namespace.example will be created
  + resource "kubernetes_namespace" "example" {
      + id = (known after apply)

      + metadata {
          + generation       = (known after apply)
          + name             = "my-first-namespace"
          + resource_version = (known after apply)
          + uid              = (known after apply)
        }
    }

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

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

kubernetes_namespace.example: Creating...
kubernetes_namespace.example: Creation complete after 0s [id=my-first-namespace]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
[koh@Kohs-MacBook-Pro-M1-387] ~/work/terraform-with-k8s
%

kubectl get namespaceでnamespaceが作成されていることがわかります。

[koh@Kohs-MacBook-Pro-M1-387] ~/work/terraform-with-k8s
% kubectl get namespace
NAME                 STATUS   AGE
default              Active   110d
kube-node-lease      Active   110d
kube-public          Active   110d
kube-system          Active   110d
my-first-namespace   Active   16s
[koh@Kohs-MacBook-Pro-M1-387] ~/work/terraform-with-k8s
%

ここでnamespaceの名前をmy-second-namespaceに更新してplanしてみます。

[koh@Kohs-MacBook-Pro-M1-387] ~/work/terraform-with-k8s
% cat main.tf
provider "kubernetes" {
  config_path    = "~/.kube/config"
  config_context = "docker-desktop"
}

resource "kubernetes_namespace" "example" {
  metadata {
    name = "my-second-namespace"
  }
}
[koh@Kohs-MacBook-Pro-M1-387] ~/work/terraform-with-k8s
% terraform plan
kubernetes_namespace.example: Refreshing state... [id=my-first-namespace]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # kubernetes_namespace.example must be replaced
-/+ resource "kubernetes_namespace" "example" {
      ~ id = "my-first-namespace" -> (known after apply)

      ~ metadata {
          - annotations      = {} -> null
          ~ generation       = 0 -> (known after apply)
          - labels           = {} -> null
          ~ name             = "my-first-namespace" -> "my-second-namespace" # forces replacement
          ~ resource_version = "7148807" -> (known after apply)
          ~ uid              = "3c73d846-24c1-45b7-9e58-ad99c5c275c7" -> (known after apply)
        }
    }

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

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run
"terraform apply" now.
[koh@Kohs-MacBook-Pro-M1-387] ~/work/terraform-with-k8s
%

namespaceの名前を変更したことにより再作成されます。
ちなみにforces replacementは一度リソースを削除してから新規で作成するという意味なので、状況によっては注意が必要です。

実際にapplyすると my-first-namespaceが削除され、my-second-namespaceが作成されることがわかります。

[koh@Kohs-MacBook-Pro-M1-387] ~/work/terraform-with-k8s
% terraform apply
kubernetes_namespace.example: Refreshing state... [id=my-first-namespace]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # kubernetes_namespace.example must be replaced
-/+ resource "kubernetes_namespace" "example" {
      ~ id = "my-first-namespace" -> (known after apply)

      ~ metadata {
          - annotations      = {} -> null
          ~ generation       = 0 -> (known after apply)
          - labels           = {} -> null
          ~ name             = "my-first-namespace" -> "my-second-namespace" # forces replacement
          ~ resource_version = "7148807" -> (known after apply)
          ~ uid              = "3c73d846-24c1-45b7-9e58-ad99c5c275c7" -> (known after apply)
        }
    }

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

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

kubernetes_namespace.example: Destroying... [id=my-first-namespace]
kubernetes_namespace.example: Destruction complete after 6s
kubernetes_namespace.example: Creating...
kubernetes_namespace.example: Creation complete after 0s [id=my-second-namespace]

Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
[koh@Kohs-MacBook-Pro-M1-387] ~/work/terraform-with-k8s
% kubectl get namespace
NAME                  STATUS   AGE
default               Active   110d
kube-node-lease       Active   110d
kube-public           Active   110d
kube-system           Active   110d
my-second-namespace   Active   5s
[koh@Kohs-MacBook-Pro-M1-387] ~/work/terraform-with-k8s
%

まとめ

環境構築からterraform applyまでローカルで完結できました。
これでTerraform初心者でも気軽に色々試せるのでいいなと思いました。

Share on: このエントリーをはてなブックマークに追加