検証によく使う Oracle Cloud Infrastructure(OCI)環境を Terraform で作成してみる。

下記の記事で整理した OCI環境 を Terraform で作成してみるやで彡(ﾟ)(ﾟ)

> 検証によく使う Oracle Cloud Infrastructure(OCI) の 環境構成(VCN, Seculity List, 各種Gateway, Route Table, Subnet, Compute)まとめ
> https://qiita.com/ora_gonsuke777/items/08e4781af8c4f7e114ff

# 1. 構成図(再掲)

下記構成図の環境を Terraform で作成してみます。(再掲載)
![a_Networking.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110066/f2318c16-45fe-2fe5-f639-85bdd0723897.jpeg)


# 2. Terraform の事前準備

下記の記事で Terraform のインストールや動作確認は済ませておきます。

> Windows端末(PC) に Terraform をインストールして OCI(Oracle Cloud Infrastructure) で動作させるための準備
> https://qiita.com/ora_gonsuke777/items/fb2abfbb7d76de2afc93

# 3. Compute Instance用の キーペア(*.pub + *.pem or *.ppk) を 2セット作成

Compute Instance用 の SSHキーペア(*.pub + *.pem or *.ppk) を Public Compute用 と Private Compute用に 2セット作成しておきます。puttygen や ssh-keygen のどちらでも。

> Linuxインスタンスでのキー・ペアの管理
> https://docs.oracle.com/cd/E97706_01/Content/Compute/Tasks/managingkeypairs.htm

# 4. Terraform の定義ファイル(*.tf)サンプルのダウンロード

下記にTerraform定義ファイル(*.tf)のサンプルをアップロードしています。Network, Compute, Object Storage を作成するサンプルです。任意のディレクトリに git clone するか Download して下さい。

> https://github.com/gonsuke777/terraform/tree/master/oci_test_env1

```git
git clone https://github.com/gonsuke777/terraform
```

# 5. 変数定義ファイル(vars.tf) の 編集

vars.tf に変数を集約しています。下記の通り編集して下さい。

| 変数名 | 説明 |
|---|---|
| os_image_source_id | OSイメージIDを記述します。このIDはリージョンごとに異なります。https://docs.cloud.oracle.com/iaas/images/ をご覧ください。 |
| public_compute_ssh_key <BR> private_compute_ssh_key | Public Compute と Private Compute の SSH鍵(*.pub, 公開鍵) のパスを記述して下さい。 |
| public_compute_ad_num <BR> private_compute_ad_num | Public Compute と Private Compute を 作成する AD(Availability Domain) の番号を記述して下さい。1AD のリージョンの場合は 1 のみ記述可能です。 |
| oci_resource_prefix | リソースのプレフィックス名を 4文字以内 で記述して下さい。 |

上記以外の変数については下記記事を参照して下さい。

> Windows端末(PC) に Terraform をインストールして OCI(Oracle Cloud Infrastructure) で動作させるための準備
> https://qiita.com/ora_gonsuke777/items/fb2abfbb7d76de2afc93

# 6. terraform の実行(init, plan, apply)

terraform を実行します。下記コマンドを実行します。

```terraform
cd ＜tfファイルを格納したディレクトリ＞
terraform init
terraform plan
terraform apply
(確認が求められるので) yes
```

ログは以下の通り、上手くいってるやで彡(^)(^)

```terraform
> terraform init

Initializing the backend...
:
Terraform has been successfully initialized!
:

> terraform plan
Refreshing Terraform state in-memory prior to plan...
:
Plan: 13 to add, 0 to change, 0 to destroy.
:

> terraform apply
data.oci_identity_availability_domains.ads: Refreshing state...
:
Apply complete! Resources: 13 added, 0 changed, 0 destroyed.
:
```

# 7. OCIリソースの確認 と 接続

OCI Console から作成されたリソースを確認してみます。
![01_pub_subnet.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110066/0ab6e196-d552-a903-a8eb-806c75fa17d9.jpeg)
![02_pub_compute.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110066/34f6c1ad-1a90-4f3a-9c32-ba79ea85dd05.jpeg)
![03_ObjectStorage.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110066/bcac671d-656c-2ea6-8e7b-0be0916250a9.jpeg)

出来てますね！Compute の ssh接続も確認

![04_ssh_connection.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110066/a097d3cd-4517-5c55-7a13-09628dc4be21.jpeg)

Compute に上手く接続できたやで!彡(^)(^)

# 8. 後始末(terraform destroy) 

terraform destroy すると、terraform で作成したリソースを削除できます。

```terraform
cd ＜tfファイルを格納したディレクトリ＞
terraform destroy
(確認が求められるので) yes
```

ログは下記の通り

```terraform
> terraform destroy
data.oci_objectstorage_namespace.export_ns: Refreshing state...
:
oci_core_vcn.export_VCN1: Destruction complete after 1s

Destroy complete! Resources: 13 destroyed.
> 
```

上手く削除できたもよう。

# 9. 工夫した、というか困った箇所

様々なリージョンで汎用的に使える Terraform定義 にしようとした場合、AD名(Avilability Domain) や Service Gatewayのサービス名 を動的に解決する必要がありました。下記のあたり。
彡(ﾟ)(ﾟ)

```terraform
# availability_domain.tf
:
# Get a list of Availability Domains, this code from https://www.terraform.io/docs/providers/oci/guides/best_practices.html
data "oci_identity_availability_domains" "ads" {
  compartment_id = "${var.tenancy_ocid}"
}
:
```

```terraform
# compute.tf
:
resource oci_core_instance export_BASTION1 {
  compartment_id      = "${var.compartment_ocid}"
  display_name        = "${upper(var.oci_resourcel_prefix)}-BASTION1"
  # This code from https://www.terraform.io/docs/providers/oci/guides/best_practices.html
  # It to get a single AD name based on the index:
  availability_domain = "${lookup(data.oci_identity_availability_domains.ads.availability_domains[var.public_compute_ad_num - 1], "name")}"
:
```

```terraform
# networking.tf
:
data "oci_core_services" "sgw_services" {
  filter {
    name   = "name"
    values = ["All .* Services In Oracle Services Network"]
    regex  = true
  }
}
:
  # Get the service id dynamically. this code from github examples.
  services {
    service_id = "${lookup(data.oci_core_services.sgw_services.services[0], "id")}"
  }
:
```

下記のサンプル群を参考にしつつ書いて期待通りの動作はしたものの、何故この書き方で動くのかイマイチ理解できない……
彡(-)(-)

> OCI - Terraform Provider Best Practices
> https://www.terraform.io/docs/providers/oci/guides/best_practices.html
> 
> terraform-provider-oci/examples/networking/service_gateway/service_gateway.tf
> https://github.com/terraform-providers/terraform-provider-oci/blob/master/examples/networking/service_gateway/service_gateway.tf

# 10. OCIリソース の Terraform定義 を export する機能(terraform-provider-oci)

terraform-provider-oci という機能で OCIリソースの Terraform定義 をエクスポートできます。下記記事が参考になります。tfファイル を ゼロ から作り上げるのは相当キツいので、この機能でエクスポートした tfファイル を参考にしながら書いてみるとエエと思います。使い方も簡単
彡(^)(^)

> terraform-provider-ociのエクスポート機能がとても便利
> https://qiita.com/yamada-hakase/items/5c224c5a3343b1f2f27e

# 11. まとめ

Terraform で 環境を作成できたやで！彡(^)(^) しかし Terraform を プログラミング言語 と捉えた場合、main に相当する機能が無かったり、前述の通りAD名やSGW Service名を動的に解決する辺りのブラックボックス感が中々に凄い……要修行や！
彡(ﾟ)(ﾟ)