Terraform for さくらのクラウド スタートガイド (第一回) ~インストールから基本操作 ~

インフラを安全かつ効率的に構築、変更、バージョン管理するためのツール「Terraform」について、入門〜さくらのクラウドでの実践までを数回に分けてお届けいたします。
第1回である今回はTerraformインストールから基本操作までを扱います。

Terraformとは?

Terraformとは、インフラの構築、変更、バージョンの管理をコードで行うためのコマンドラインツールです。ここでいうインフラとは、コンピューティングリソースやストレージ、ネットワークといった基本的な部分から、ロードバランサーやDNS、データーベース、CDNといった応用的なものまでを含む、システムを構成する基盤の事を指しています。開発はVagrantやPacker、Consulといった製品を開発しているHashicorp社が主体となって行われており、GitHubにてオープンソース・プロジェクトとして進められています。

Terraformの主な機能は以下のようなものです。

Infrastructure as Code(コードとしてのインフラ)

Terraformではインフラを「HCL」というJSONライクなコードで定義します。
コード化されている事で、通常のアプリケーションのコードなどと同じくバージョン管理や他者との共有、再利用が容易になります。

注:定義にはHCLだけでなく、JSONを利用することも可能です。

実行計画を立てた上でインフラ構築を行う

Terraformでのインフラの構築には「計画」というステップがあります。実際にインフラの構築を行う前にどういった作業が行われるかが把握できるようになっています。

リソースのグラフ化

コードにて定義が与えられると、リソース間の関係を表すグラフを構築します。これにより、特定のリソースを修正した場合の影響範囲の算出や、関連のないリソース構築作業の並列化が行えるようになっています。

変更適用の自動化

インフラの変更をコードで宣言的に行うことができます。実際にどうやって変更を反映するかはTerraformによって自動的に決定されます。前述の実行計画/リソースグラフにより、何をどのように変更するかを事前に確認することもできます。

Terraformのインストール

それでは早速Terraformをインストールしてみましょう。インストールはzipファイル(terraformバイナリ)をダウンロード、unzipするだけでOKです。必須ではありませんが、PATHを通しておくと利用しやすいでしょう。

まずはダウンロードページからzipファイルのダウンロードを行います。
Terraform ダウンロードページ

Windows/Linux/MacOS/FreeBSDなどの各プラットフォームごとにzipファイルが用意されていますので、適切なものを選択してダウンロードします。

ダウンロード後unzipしたらインストール完了です。必要に応じてPATHを通しておいてください。
注:以降はPATHを通している前提で記載いたします

インストール後、以下のように`terraform version`を実行してバージョン情報が表示されればインストールは正常に行えています。

$ terraform version
Terraform v0.8.1

今回のTerraform実行環境

Terraformは様々なリソースに対応していますが、今回はAWSを例として用います。

なお、本連載においてはTerraformでさくらのクラウド上にインフラを構築できるようになることを目指しておりますが、まずはTerraformそのものを手軽にお試しいただくためにAWSを使用します。

Terraformでのさくらのクラウド上へのインフラ構築は連載第3回以降で扱う予定です。

インフラのビルド

最初の例として、AWS上にEC2インスタンスを1台作成してみます。

まずは作業用のディレクトリを作成し、その中に定義ファイル(.tf)を作成します。
注:コマンド例はbashでの実行例となっています。Windowsユーザーの方は適宜読み替えてください。

# 作業用のディレクトリ作成
$ mkdir example1
$ cd example1

[TIPS]
Terraformはコマンド実行時にカレントディレクトリにある「.tf」拡張子を持つファイルをすべて読み込みます(サブディレクトリの.tfファイルは読み込みません)。これを利用して.tfファイルを分割することもできます。

ディレクトリを作成したら定義ファイルを作成しましょう。

# 定義ファイル作成
$ vi example1.tf

定義ファイルには以下の内容を記述していきます。

プロバイダー設定の記述

まずは「プロバイダー」設定の記述を行います。

Terraformにおける「プロバイダー」とは、インフラを管理する対象プラットフォームを指し、それぞれのプロバイダーごとにAPIキーなどの情報などを設定することができます。
各リソースの操作を行う際は、それぞれが属するプロバイダーの設定を参照するようになっています。

今回はAWSを利用しますので、AWS用のプロバイダー設定を記述します。
以下の記述を行ってください。(参考:AWSプロバイダー設定ドキュメント

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

AWSのアクセスキー、シークレットキーが必要になりますので、お持ちでない場合は以下のページなどからアクセスキーを作成しておいてください。

AWSマネージメントコンソール セキュリティ認証情報

"ACCESS_KEY_HERE"と"SECRET_KEY_HERE"の部分は各自のアクセスキーで置き換えてください。

[TIPS]
ここではアクセスキーを定義ファイルに直接記述しましたが、定義ファイルのバージョン管理や他者との共有という点から見ると直接記述している状況は好ましくありません。(間違えてGitHub上のリポジトリにコミットしたら、、)

次回以降の記事でこれらを環境変数や設定ファイルに切り出す方法を扱います。

今回はAWSのみを利用しますのでプロバイダー設定の記述は一つだけですが、もしAzureやGCP、さくらのクラウドといったプロバイダーを組み合わせて利用する場合はプロバイダー設定の記述を複数行うことになります。

リソース(EC2)定義の記述

続いて以下の記述を行います。

resource "aws_instance" "example" {
  ami = "ami-0d729a60"
  instance_type = "t2.micro"
}

定義ファイルは以下のような構造になっています。

resource "リソースタイプ" "リソース名" {
  属性名 = 属性の値
}

"リソースタイプ"とは対象のリソースの種別を表すもので、"プロバイダ_"というプリフィックスを持ちます。(AWSの場合は"aws_"、GCPの場合は"google_"といった感じです)

"リソース名"はリソースの識別子で、任意の名前をつけることができます。

[TIPS]
Terraformでは定義ファイルにおいて、他のリソースの情報を参照する記述を行うことができます。その際にこのリソース名を用いて「${aws_instance.example}」というような記述を行います。
他のリソースの情報を参照する方法については次回以降の連載で扱います。

属性名や属性の値については各リソース固有で、どのような項目が指定できるかは各リソースのドキュメントに記載されています。EC2の場合は以下のドキュメントに記載されています。
参考:EC2リソース

今回の記述では、AMIにAmazon Linux(東京リージョン)、インスタンスタイプとして"t2.micro"を利用すると定義しています。

実行計画の表示(terraform plan)

次に、この定義ファイルを適用しようとした場合、Terraformが何をするか確認してみましょう。
先ほど作成した"example1.tf"ファイルと同じディレクトリにて以下のコマンドを実行します。

$ terraform plan

エラーが出た場合は定義ファイルの記述ミスの可能性があります。もう一度定義ファイルの確認を行ってください。正常な場合は以下のような表示となります。

example1$terraform plan
[省略]
+ aws_instance.example
    ami:                         "ami-0c11b26d"
    instance_type:               "t2.micro"
    [省略]

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

+」が先頭についているのは、EC2インスタンスが新規作成されることを表しています。

適用(terraform apply)

続いてこの定義を実際に反映してみましょう。
以下のコマンドを実行します。

$ terraform apply

実行すると、以下のような表示が行われます。

aws_instance.example: Creating...
 ami:                         "" => "ami-0c11b26d"
 instance_type:               "" => "t2.micro"
 [省略] 
aws_instance.example: Still creating... (10s elapsed)
aws_instance.example: Still creating... (20s elapsed)
aws_instance.example: Creation complete

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

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: terraform.tfstate

無事成功しましたね?
エラーなく実行できた場合、AWSのマネージメントコンソールからEC2インスタンスが作成されていることが確認できるはずです。

また、カレントディレクトリに「terraform.tfstate」というファイルが作成されているはずです。このファイルは「状態ファイル」という非常に重要なファイルで、作成したリソースのIDや取得/算出した属性の値などが格納されています。Terraformはこのファイルを参照することで、tfファイルで定義されたリソースに対し追加/更新/削除のどの操作が必要なのかを判定しています。

[TIPS]
Terraformを複数のマシンで動かす場合、状態ファイルをすべてのマシンで共有しておかないとリソースの状況の整合性が取れないため、重複したリソースが作成されてしまうとなどの問題が発生します。
Terraformには状態ファイルを共有するための仕組みとして"terraform remote"という機能が備わっています。"terraform remote"については次回以降の連載で扱います。

インフラの更新

続いてインフラの更新を行います。tfファイルのEC2部分を以下のように変更してください。

resource "aws_instance" "example" {
  ami = "ami-be4a24d9"
  instance_type = "t2.micro"
}

AMIをAmazon LinuxからUbuntu 16.04 LTSへと変更しています。
実行計画の確認のために"terraform plan"を実行してみましょう。

example1$ terraform plan
(省略)
-/+ aws_instance.example
    ami:                         "ami-0c11b26d" => "ami-be4a24d9" (forces new resource)
    instance_type:               "t2.micro" => "t2.micro"
    [省略]

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

-/+」が先頭についているのは、EC2インスタンスを一度破棄してから再度作成されることを表しています。今回はAMIを変更したために破棄/変更が必要になりましたが、変更する属性によってはインプレースアップデート(「-/+」の代わりに「~」がつく)も可能です。

何が起きたの?

"terraform plan"を実行することで、以下のような処理が行われています。

1)    「terraform.tfstate」などの状態ファイルが存在するか判定

1-1)   存在しない場合はリソースを新規作成
または
1-2)   存在する場合は状態ファイルからリソースのIDを取得、
       IDを元にリソースの最新状態をAPIなどから取得

2)     定義ファイルとリソースの最新状態に差分があるか判定

3)     差分の内容によって適用方法(破棄/作成 or 更新 or 何もしない)を決定

Terraformは定義ファイル、状態ファイル、実際のリソースの状態という3つから変更をどうやって適用するかを決定します。

それでは再度"terraform apply"を実行して変更を適用しましょう。

$ terraform apply

エラーなく実行できればインスタンスが破棄されて新しいインスタンスが作成されているはずです。AWSマネージメントコンソールなどから確認してみてください。

インフラの削除

今度はインフラの削除を行います。先ほどと同じくまずは実行計画を確認してみます。

$ terraform plan -destroy
[省略]
- aws_instance.example


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

削除されるリソースの表示が行われます。
続いて実際に削除を行ってみましょう。"terraform destroy"を実行します。

example1$terraform destroy
Do you really want to destroy?
  Terraform will delete all your managed infrastructure.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: ここで「yes」と入力すると削除が実行される

[省略]
Destroy complete! Resources: 1 destroyed.

途中で本当に削除して良いか確認(Do you really want to destroy?)されるので、「yes」と入力してください。しばらく待つとリソースの削除が行われます。エラーなく実行できればAWSマネージメントコンソールから削除されていることが確認できるはずです。

今回はリソースが一つだけの例でしたが、複数のリソースが存在する場合は各リソースの依存関係などを把握した上で順序立てて、または並列化して削除処理を行ってくれます。


以上でTerraformの基本的な操作は完了です。

本記事では定義ファイル(.tf)を記載し

  • "terraform plan"で実行計画を確認
  • "terraform apply(またはdestroy)"で実際にインフラへ反映

という流れでインフラの構築を行なっていく様子について扱いました。

ここまでの内容だけでも一通りのインフラ構築が可能ですが、
Terraformに備わっている、変数やプロビジョニング、モジュールといった機能を用いることで共有/再利用しやすく可読性の高いコードを書くことができるようになります。

次回はこれらのTerraformの便利な機能について扱う予定です。
お楽しみに!