Dockerのterraformイメージを利用してOracle Cloud Infrastructure(OCI)を試す

## はじめに

今までOracle Cloud Infrastructureのプロバイダーは公式では提供されていなかったのですが、  
最近デフォルトでOCIが使えるようになっていたので試してみました。  
[[Cloud] Oracle Cloud Infrastructure Terraform Provider Now Supported by HashiCorp](ttps://orablogs-jp.blogspot.com/2018/09/oracle-cloud-infrastructure-terraform.html)å

## 参考

[Link1]: https://community.oracle.com/docs/DOC-1024538

* [terraform Docker Container](https://github.com/hashicorp/docker-hub-images/tree/master/terraform)

* [コマンドライン(CLI)でOCIを操作する - Oracle Cloud Infrastructureアドバンスド](https://community.oracle.com/docs/DOC-1019624)

* [TerraformでOCIの構築を自動化する - Oracle Cloud Infrastructureアドバンスド][Link1]

* [Terraform Provider for Oracle Cloud Infrastructure の導入](https://cloudii.atomitech.jp/entry/2018/08/06/170323)

## TerraformのDockerイメージを取得

[Hashicorp公式のリポジトリ](https://hub.docker.com/r/hashicorp/terraform/)から提供されているイメージを利用します。
SIZEが131MBなので割と軽量

```bash-session
$ docker pull hashicorp/terraform:light
$ docker images
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
hashicorp/terraform   light               29edcab3b90b        2 weeks ago         131MB
```

コマンドは以下のように実行できます。

```bash-session
docker run -i -t hashicorp/terraform:light <command>
```

試しにバージョン確認

```bash-session
$ docker run -i -t hashicorp/terraform:light --version
Terraform v0.11.11
```

## 実行するための事前準備(OCI)

### APIキーの作成

```bash-session
mkdir -p ~/.oci
openssl genrsa -out ~/.oci/oci_tf_key.pem 2048
chmod go-rwx ~/.oci/oci_tf_key.pem
openssl rsa -pubout -in ~/.oci/oci_tf_key.pem -out ~/.oci/oci_tf_key_public.pem
```

```bash-session
cat ~/.oci/oci_tf_key_public.pem
## 出力① メモしておきます。
openssl rsa -pubout -outform DER -in ~/.oci/oci_tf_key.pem | openssl md5 -c
## 出力② メモしておきます
```

### APIキーの登録

OCIにてユーザ作成を行います。  
[MENU] > [Identity] > [Users]でユーザー画面に行きます。  
[Create User]を押します。  

<img width="1318" alt="ss_1_2019-01-02.png" src="https://qiita-image-store.s3.amazonaws.com/0/223761/ef41c3c4-657b-5c0d-427b-57833ecabe56.png">


ユーザを作成します。  

<img width="665" alt="ss_2_2019-01-02.png" src="https://qiita-image-store.s3.amazonaws.com/0/223761/049f591e-91eb-af2b-11b8-924a1ff394ef.png">


作ったユーザ画面に行き、[Add Public Key]を選択します。  

<img width="1316" alt="ss_3_2019-01-03.png" src="https://qiita-image-store.s3.amazonaws.com/0/223761/091cad71-c074-b0cf-f255-146c3a7529a6.png">


Public Keyを入力する画面が開くので、メモしておいた「出力①」を貼り付けます。

<img width="663" alt="ss_4_2019-01-03.png" src="https://qiita-image-store.s3.amazonaws.com/0/223761/8837dc03-0ffa-799a-4af5-b5dd82fb6f7f.png">



## 実行するための事前準備(Terraform)

まずはさっくりAD1を表示するTerraformを実行するファイルを準備。

### 環境変数ファイルの作成

tenancy_ocidなどの設定値は[TerraformでOCIの構築を自動化する - Oracle Cloud Infrastructureアドバンスド][Link1]を参考にするとわかります。  
`<PEM key fingerprint>`は上述した「出力②」を利用できます。

```Terraform:terraform.tfvars
tenancy_ocid = "<tenancy OCID>"
user_ocid = "<user OCID>"
fingerprint = ""<PEM key fingerprint>"
region = "<region in which to operate, example: us-ashburn-1, us-phoenix-1>"
compartment_ocid = "<compartment OCID>"
ssh_public_key = "id_rsa.pub" ★今回は利用しない
private_key_path = "oci_tf_key.pem" ★後述の手順で鍵をTerraform実行ディレクトリに直接配置するので上で作成したファイル名を記載
```

### AD1の名前を取得するTerraformファイル

```Terraform:tftest.tf
variable "tenancy_ocid" {}
variable "user_ocid" {}
variable "fingerprint" {}
variable "private_key_path" {}
variable "compartment_ocid" {}
variable "ssh_public_key" {}
variable "region" {}

provider "oci" {
  tenancy_ocid         = "${var.tenancy_ocid}"
  user_ocid            = "${var.user_ocid}"
  fingerprint          = "${var.fingerprint}"
  private_key_path     = "${var.private_key_path}"
  region               = "${var.region}"
  disable_auto_retries = "true"
}

data "oci_identity_availability_domains" "ADs" {
  compartment_id = "${var.tenancy_ocid}"
}

output "ADprint" {
  value = "${lookup(data.oci_identity_availability_domains.ADs.availability_domains[0],"name")}"
}
```

### 公開鍵の用意

dockerのterraformの場合、公開鍵など、Terraform実行の際に必要なファイルをコンテナから見えるようにします。  
今回は.tfファイルと同じ場所に[APIキーの作成](### APIキーの作成)で作成したファイルを配置します。

```bash-session
cp -p ~/.oci/oci_tf_key.pem <ファイルの配置先>
```

## 実行

### 初期化

```bash-session
$ cd <ファイルの配置先>
$ docker run -i -t -v $(pwd):/app/ -w /app/ hashicorp/terraform:light init

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

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.oci: version = "~> 3.11"

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

呪文だったので引数のコメント  
[コマンドリファレンス RUN](http://docs.docker.jp/engine/reference/commandline/run.html)

* -i コンテナの STDIN にアタッチ

* -t 疑似ターミナル (pseudo-TTY) を割り当て

* -v ホストディレクトリをコンテナにマウント、ここではカレントディレクトリをdocker内の/appにマウント

* -w コンテナ内の作業用ディレクトリを指定

### 確認

```bash-session
$ docker run -i -t -v $(pwd):/app/ -w /app/ hashicorp/terraform:light plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

data.oci_identity_availability_domains.ADs: Refreshing state...

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

No changes. Infrastructure is up-to-date.

This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.

```

### いよいよ実行

```bash-session
$ docker run -i -t -v $(pwd):/app/ -w /app/ hashicorp/terraform:light apply
data.oci_identity_availability_domains.ADs: Refreshing state...

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

Outputs:

ADprint = gype:US-ASHBURN-AD-1
```

できましたー！　　
今回はここまで、次回はリソース作成を予定しています。

## おまけ　ショートカットコマンドを作成する

profileなどに以下を記載して読み込ませることで、いちいちdockerコマンドを打たなくて済みます。

```bash-session
terraform() { docker run -i -t -v $(pwd):/app/ -w /app/ hashicorp/terraform:light "$@"; }
```

```bash-session
terraform --version
Terraform v0.11.11
```

## 備忘録

DockerコンテナのTerraformを使った場合でハマったところは  
ホストの環境変数やファイルをコンテナ上に持っていかないといけないこと  
以下のように環境変数ファイルを作成して、配置したとしても、コンテナ上には環境変数を引き継いでくれないので
variableの値が見つからないと怒られました。
同様にprivate_key_pathも初めはホストのパス(/.ssh配下)を指定指定たが、考えてみれば、これもコンテナ上から見えるディレクトリにおく必要がありました。
今回はappにカレントディレクトリをマウントしたので、カレントでイレクトリにとりあえず、ファイルを配置して設定ファイルにはその場所を指定して実行しました。

* 以下を参考に設定ファイルを作成。  

[env-var](https://raw.githubusercontent.com/terraform-providers/terraform-provider-oci/master/docs/examples/compute/instance/env-vars)

* 以下を読み込んでdockerで実行しても環境変数は引き継がれていませんでした。

```bash-seesion:.env-var
### Authentication details
export TF_VAR_tenancy_ocid="<tenancy OCID>"
export TF_VAR_user_ocid="<user OCID>"
export TF_VAR_fingerprint="<PEM key fingerprint>"
export TF_VAR_private_key_path="<path to the private key that matches the fingerprint above>"

### Region
export TF_VAR_region="<region in which to operate, example: us-ashburn-1, us-phoenix-1>"

### Compartment
export TF_VAR_compartment_ocid="<compartment OCID>"

### Public/private keys used on the instance
export TF_VAR_ssh_public_key=$(cat <path to public key>)
export TF_VAR_ssh_private_key=$(cat <path to private key>)
## NOTE: These are not your api keys. More info on the right keys see
## https://docs.us-phoenix-1.oraclecloud.com/Content/Compute/Tasks/managingkeypairs.htm
```