TerraformでOKEのクラスタを作成する

# はじめに
OKE（Container Engine for Kubernetes）のクラスタをTerraformで作ってみたいと思います。

# 前提条件
VCNおよびサブネットは、こちらの例の通りに作成済みです。

https://docs.oracle.com/ja-jp/iaas/Content/ContEng/Concepts/contengnetworkconfigexample.htm#example-oci-cni-publick8sapi_privateworkers_publiclb

作成済みのVCN、サブネットにTerraformでOKEクラスタをプロビジョニングします。

# Stackの作成
TFファイルを一から作るのは大変なので、OCIコンソールでクラスタを設定して、最後に「クラスタの作成」ではなく、`スタックとして保存`をクリックします。
（VCNなどのネットワークリソースを一緒に作成する`クイック作成`ではなく、クラスタのみを作成する`カスタム作成`を使用します）

![スクリーンショット 2023-11-08 8.09.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/e9b3976d-fae9-884c-d4a8-4145b188bbbc.png)

作成したスタックからTerraform構成をダウンロードします。

![スクリーンショット 2023-11-08 8.10.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/2ddb887f-5522-52a7-9c64-8618087009f2.png)

ダウンロードしたTerraform構成はZip形式ですので、展開すると`main.tf`ファイルになります。

# 設定ファイルの編集、作成

## main.tfファイル
ダウンロードした`main.tf`ファイルは各変数がそのまま書かれていますので、汎用的にするために変数は別ファイルで管理するようにします。

以下のように編集しました。
- 1行目
    - provider は別ファイルで定義するので、コメントアウトします。
- 3-26行目
    - クラスタを作成する部分
    - 各変数は`var.変数名`に書き換え
- 28-62行目
    - ノードプールを作成する部分
    - 各変数は`var.変数名`に書き換え
- 29行目
    - 3-26行目で作成したクラスタのcluster_idを引き継いでいます。
        - 3行目で宣言してる変数？からcluster_idを引き継いでいるらしい（調べ切れてない）

```main.tf
     1  # provider "oci" {}
     2
     3  resource "oci_containerengine_cluster" "generated_oci_containerengine_cluster" {
     4          cluster_pod_network_options {
     5                  cni_type = var.cluster_pod_network_options
     6          }
     7          compartment_id = var.compartment_id
     8          endpoint_config {
     9                  is_public_ip_enabled = var.is_public_ip_enabled
    10                  subnet_id = var.endpoint_config_subnet_id
    11          }
    12          kubernetes_version = var.kubernetes_version
    13          name = var.cluster_name
    14          options {
    15                  kubernetes_network_config {
    16                          services_cidr = var.kubernetes_network_config_cider
    17                  }
    18                  persistent_volume_config {
    19                  }
    20                  service_lb_config {
    21                  }
    22                  service_lb_subnet_ids = [var.service_lb_subnet_ids]
    23          }
    24          type = var.cluster_type
    25          vcn_id = var.vcn_id
    26  }
    27
    28  resource "oci_containerengine_node_pool" "create_node_pool_details0" {
    29          cluster_id = "${oci_containerengine_cluster.generated_oci_containerengine_cluster.id}"
    30          compartment_id = var.compartment_id
    31          initial_node_labels {
    32                  key = "name"
    33                  value = var.nodepool_name
    34          }
    35          kubernetes_version = var.kubernetes_version
    36          name = var.nodepool_name
    37          node_config_details {
    38                  node_pool_pod_network_option_details {
    39                          cni_type = var.cluster_pod_network_options
    40                          max_pods_per_node = var.max_pods_per_node
    41                          pod_subnet_ids = [var.pod_subnet_ids]
    42                  }
    43                  placement_configs {
    44                          availability_domain = var.availability_domain
    45                          subnet_id = var.node_subnet_id
    46                  }
    47                  size = var.node_count
    48          }
    49          node_eviction_node_pool_settings {
    50                  eviction_grace_duration = var.eviction_grace_duration
    51                  is_force_delete_after_grace_duration = var.is_force_delete_after_grace_duration
    52          }
    53          node_shape = var.node_shape
    54          node_shape_config {
    55                  memory_in_gbs = var.memory_in_gbs
    56                  ocpus = var.ocpus
    57          }
    58          node_source_details {
    59                  image_id = var.image_id
    60                  source_type = var.source_type
    61          }
    62  }
```

## provider.tfファイル
認証関連のファイル。これまでと同様です。

```provider.tf
     1  provider "oci" {
     2    tenancy_ocid = var.tenancy_ocid
     3    user_ocid = var.user_ocid
     4    private_key_path = var.private_key_path
     5    fingerprint = var.fingerprint
     6    region = var.region
     7  }
     8
     9  terraform {
    10    required_providers {
    11      oci = {
    12        source  = "oracle/oci"
    13      }
    14    }
    15  }
```

## variables.tfファイル
変数の定義。
クラスタによってあまり変わらない値は`default`を設定しています。

```variables.tf
     1  ## provider
     2  variable "tenancy_ocid" {
     3    type = string
     4  }
     5  variable "user_ocid" {
     6    type = string
     7  }
     8  variable "private_key_path" {
     9    type = string
    10  }
    11  variable "fingerprint" {
    12    type = string
    13  }
    14  variable "region" {
    15    type = string
    16    default = "ca-toronto-1"
    17  }
    18
    19  ## OKE Cluster
    20  variable "cluster_pod_network_options" {
    21    type = string
    22    default = "OCI_VCN_IP_NATIVE"
    23  }
    24  variable "compartment_id" {
    25    type = string
    26  }
    27  variable "is_public_ip_enabled" {
    28    type = bool
    29    default = true
    30  }
    31  variable "endpoint_config_subnet_id" {
    32    type = string
    33  }
    34  variable "kubernetes_version" {
    35    type = string
    36    default = "v1.27.2"
    37  }
    38  variable "cluster_name" {
    39    type = string
    40  }
    41  variable "kubernetes_network_config_cider" {
    42    type = string
    43    default = "10.96.0.0/16"
    44  }
    45  variable "service_lb_subnet_ids" {
    46    type = string
    47  }
    48  variable "cluster_type" {
    49    type = string
    50    default = "BASIC_CLUSTER"
    51  }
    52  variable "vcn_id" {
    53    type = string
    54  }
    55
    56  ## Node Pool
    57  variable "nodepool_name" {
    58    type = string
    59  }
    60  variable "max_pods_per_node" {
    61    type = number
    62    default ="31"
    63  }
    64  variable "pod_subnet_ids" {
    65    type = string
    66  }
    67  variable "availability_domain" {
    68    type = string
    69    default = "TGjA:CA-TORONTO-1-AD-1"
    70  }
    71  variable "node_subnet_id" {
    72    type = string
    73  }
    74  variable "node_count" {
    75    type = number
    76  }
    77  variable "eviction_grace_duration" {
    78    type = string
    79    default = "PT60M"
    80  }
    81  variable "is_force_delete_after_grace_duration" {
    82    type = bool
    83    default = false
    84  }
    85  variable "node_shape" {
    86    type = string
    87    default = "VM.Standard.E4.Flex"
    88  }
    89  variable "memory_in_gbs" {
    90    type = number
    91    default = 16
    92  }
    93  variable "ocpus" {
    94    type = number
    95    default = 1
    96  }
    97  variable "image_id" {
    98    type = string
    99    default = "ocid1.image.oc1.ca-toronto-1.aaaaaaaaihukvlwwkkf4oklbg7mwxhxxe3nng5llyvckzk3lz6r2f4rlrf5a"
   100  }
   101  variable "source_type" {
   102    type = string
   103    default = "IMAGE"
   104  }
```

## terraform.tfvars ファイル
各変数の値を設定します。変数の中身は実際には記載しています。

```terraform.tfvars 
     1  ## provider
     2  tenancy_ocid = ""
     3  user_ocid = ""
     4  private_key_path = ""
     5  fingerprint = ""
     6  # region = "" # default = "ca-toronto-1"
     7
     8  ## OKE Cluster
     9  # cluster_pod_network_options = "" # default = "OCI_VCN_IP_NATIVE"
    10  compartment_id = ""
    11  # is_public_ip_enabled = "" # default = true
    12  endpoint_config_subnet_id = ""
    13  # kubernetes_version = "" # default = "v1.27.2"
    14  cluster_name = ""
    15  # kubernetes_network_config_cider = "" # default = "10.96.0.0/16"
    16  service_lb_subnet_ids = ""
    17  # cluster_type = "" # default = "BASIC_CLUSTER"
    18  vcn_id = ""
    19
    20  ## Node Pool
    21  nodepool_name = ""
    22  # max_pods_per_node = "" # default ="31"
    23  pod_subnet_ids = ""
    24  # availability_domain = "" # "TGjA:CA-TORONTO-1-AD-1"
    25  node_subnet_id = ""
    26  node_count = ""
    27  # eviction_grace_duration = "" # default = "PT60M"
    28  # is_force_delete_after_grace_duration = "" # default = false
    29  # node_shape = "" # default = "VM.Standard.E4.Flex"
    30  # memory_in_gbs = "" # default = 16
    31  # ocpus = "" # default = 1
    32  # image_id = "" # default = "ocid1.image.oc1.ca-toronto-1.aaaaaaaaihukvlwwkkf4oklbg7mwxhxxe3nng5llyvckzk3lz6r2f4rlrf5a" (OL8.8)
    33  # source_type = "" # default = "IMAGE"
```

以下4つのファイルを用意しました。

```
$ ls -l
total 48
-rw-rw-r--. 1 opc opc 1713 Nov  8 04:23 main.tf
-rw-rw-r--. 1 opc opc  265 Nov  8 03:17 provider.tf
-rw-rw-r--. 1 opc opc 1101 Nov  8 05:51 terraform.tfvars
-rw-rw-r--. 1 opc opc 1797 Nov  8 05:21 variables.tf
```

https://github.com/dingtianhongjie/terraform/tree/main/tf-oke

# Terraformの実行
## init

```
$ terraform init

Initializing the backend...

Initializing provider plugins...
- Reusing previous version of oracle/oci from the dependency lock file
- Using previously-installed oracle/oci v5.19.0

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.
```

## plan
クラスタとノードプールの2つのリソースが作成されることがわかります。

```
$ 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:
・・・
Plan: 2 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.
```

## apply

```
$ terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create
・・・
Plan: 2 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
・・・
oci_containerengine_cluster.generated_oci_containerengine_cluster: Creating...
oci_containerengine_cluster.generated_oci_containerengine_cluster: Still creating... [10s elapsed]
・・・
oci_containerengine_cluster.generated_oci_containerengine_cluster: Creation complete after 8m20s [id=ocid1.cluster.oc1.ca-toronto-1.aaaaaaaakoxuj73vvvv24rh2gpuhgqzei45xbkbq2oj5v5hb3c3t6j6pexka]
oci_containerengine_node_pool.create_node_pool_details0: Creating...
oci_containerengine_node_pool.create_node_pool_details0: Still creating... [10s elapsed]
・・・
oci_containerengine_node_pool.create_node_pool_details0: Creation complete after 3m9s [id=ocid1.nodepool.oc1.ca-toronto-1.aaaaaaaacje3bvvklnwnof4d3rlcs4vpvzjqjosdqlmytldzxn5fzpuihqmq]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
```

何度か変数を変えてみて、OKEクラスタがプロビジョニングできることを確認できました。
ただ、これだとやや汎用性に欠けることにも気づきました。（Virtual Nodeが設定できないなど）

まだまだTerraformは奥が深いです。