Terraformでインフラのコード化を体験してみよう ~ その①基礎編


## 対象読者

- 「インフラ」という言葉に抵抗がある
- 基本的にサーバ等はインフラチームが管理しており、自分はあまり触ったことが無い
- AWSのインフラ構築は全てコンソール上で行っており、作業が属人化して困っている


## 目的

- インフラへの抵抗感をなくしてもらう
- `インフラのコード化`(Infrastructure as Code)を取り入れる事で相当インフラ構築が楽になることを実感してもらう

## Terraformってなんだ

[Terraform](https://www.terraform.io/)というのは、上に述べた「インフラのコード化」のツールの1つです。
インフラ構築・変更・削除等をコードで管理出来る代物です。
(例ではAWSの説明しかしませんが、他にもAzureやDocker,Heroku等色んなインフラに対応しています)

**サンプル**

実際にどんなものか。本家サイトのTOPページに例が載ってますが、
ELBと、EC2インスタンスを作るにはこんな感じでコードを書いていきます。

```
resource "aws_elb" "frontend" {
  name = "frontend-load-balancer"
  listener {
    instance_port     = 8000
    instance_protocol = "http"
    lb_port           = 80
    lb_protocol       = "http"
  }
 
  instances = ["${aws_instance.app.*.id}"]
}
 
resource "aws_instance" "app" {
  count = 5
 
  ami           = "ami-408c7f28"
  instance_type = "t1.micro"
}
```

## terraformの基本

terraformでインフラ構築するには、3段階の工程があります。

1. コードを書く
2. planで設定に問題無いか確認する
3. applyで実際に適用する

なので、実際に`apply`するまでは正直何も起きません。
`apply`して初めてインフラに対して構築を試みます。

## 実際に使ってみる

### 1. terraformのインストール

インストールの方法は[公式](https://www.terraform.io/intro/getting-started/install.html)に各環境毎のバイナリが配布されているので、それを使います。

Macの場合はbrewでインストール可能です。

```bash
$ brew install terraform

$ terraform -v
Terraform v0.9.4
```

※ 多分、今は`v0.10.2`が最新です

### 2. プロバイダーを設定する

基本的にTerraformでは、最初にどのプロバイダーを使うかという宣言をします。
今回はAWSを使うのでこんな感じになります。

```
provider "aws" {
    access_key = "ACCESS_KEY_HERE"
    secret_key = "SECRET_KEY_HERE"
    region = "ap-northeast-1"
}
```

AWSを使う場合には、`access_key`と`secret_key`が必要になります。
しかし、こんな感じでコードに直接クレデンシャルな値を書き込むのに抵抗がある人もいると思います。

その場合の解決策を紹介します。

#### A. 環境変数を使う

下記の2つを環境変数として`export`しておくと、terraformコマンドを実行する際に自動的にクレデンシャル情報を読み込んでくれます。

- `AWS_ACCESS_KEY_ID`
- `AWS_SECRET_ACCESS_KEY`

#### B. 変数を使う

terraformでは、variableブロックで変数を定義していきます。
`variable "{変数名}" {}`という風にからのブロックで書く事で変数を宣言することが出来ます。

また、この変数を参照するには、`${var.変数名}`というふうにします。
↓こんな感じになります。

```
variable "access_key" {}
variable "secret_key" {}
 
provider "aws" {
    access_key = "${var.access_key}"
    secret_key = "${var.secret_key}"
    region = "ap-northeast-1"
}
```

これはvariableブロックで、`access_key`と`secret_key`の2つを宣言して、
providerブロックで参照して使ってるという形です。

今、変数の宣言は出来ました。が、まだ値を入れてないのでこのままだと実行時にエラーになります。
じゃあ代入はどうするのか。

##### ⅰ. 環境変数を使う

```
$ export TF_VAR_access_key = "xxxxxxxxx"
$ export TF_VAR_secret_key = "xxxxxxxxx"
``` 

##### ⅱ. ファイルで渡す

terraformは、`terraform.tfvars`という名前でファイル名で作成しておくと、
実行時に定義した変数を読み込んでくれます。

また、ファイル名を`terraform.tfvars`にしない事も可能です。
terraformの実行時に下記のようにファイル指定すればOKです。

```
aws_access_key = "xxxx"
aws_secret_key = "xxxx"
```

```
$ terraform apply -var-file="{変数ファイル名}"
```

##### ⅲ. Terraformコマンドのオプションで値を渡す

最後は、terraform実行時に変数を指定する方法です。

```
$ terraform apply -var "access_key=xxxx" -var "secret_key=xxxxx"
```

### 変数が代入されてることを確認してみる

では早速、クレデンシャル情報を外から渡してみましょう。
terraformには、`output`というその属性に割り当てられた値を確認することが出来る方法があるので試してみます。

```test.tf
variable "aws_access_key" {}
variable "aws_secret_key" {}

output "aws_access_key" {
    value = "${var.aws_access_key}"
}

output "aws_secret_key" {
    value = "${var.aws_secret_key}"
}
```

```terraform.tfvars
aws_access_key = "test_access_key"
aws_secret_key = "test_secret_key"
```

`test.tf`側では`aws_access_key`と`aws_secret_key`という変数の定義だけ行い、
実際の変数への代入は`terraform.tfvars`を使ってみました。

さて、じゃあ実際に`apply`してどんなアウトプットが出るか見てみましょう。

```bash
$ terraform apply

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

Outputs:

aws_access_key = test_access_key
aws_secret_key = test_secret_key
```

ちゃんとそれぞれの変数に代入した値が入っている事が確認出来ました。

## 次回予告

明日は、この変数等の仕組みを使って、簡単なwebサーバの構成を作ってみようとおもいます。