インフラの構成管理を自動化するTerraform入門

2015年7月14日(火)
前佛 雅人(ぜんぶつ まさひと)

TerraformからAWSインスタンスの起動と停止を実行する

以降では、Terraformの基本的な使い方を見ていきます。ここではAWSを例に紹介しますが、Terraformは他にも様々なクラウド環境で利用できます。

事前準備

まずは、AWS上のEC2インスタンスを起動する方法を試してみます。ここでは、実際にAWSのアカウントが作成されていることに加えて、アクセスキーとシークレットキーの取得を前提としています。また、設定適用時にはインスタンスが稼働しますので、停止するまで課金対象となる点にご注意願います。

Terraformをインストールした環境上で、任意の名前のディレクトリを作成し、移動します。その中で「aws.tf」という名称のファイルを作成し、内容は次の通りにします。アクセスキーと、シークレットキーは自分のものを記入ください(なお、セキュリティ上、このファイルのパーミッションは他人から読めないように設定し、作業後はアクセスキー等の情報は削除するなど、ご注意願います)。

ソースコード

provider "aws" {
    access_key = "<アクセスキーを記入>"
    secret_key = "<シークレットキーを記入>"
    region = "us-east-1"
}

resource "aws_instance" "terraform_example" {
    ami = "ami-408c7f28"
    instance_type = "t1.micro"
        key_name = "<任意のキー名称>"
}

1つめのブロックは「プロバイダ」と呼ばれるもので、Terraformがアクセス可能なクラウドサービスごとに提供されています。今回はAWSを使うため「aws」と指定します。もし他のプロバイダを使う場合は、awsではなく各々のプロバイダ名を記入します(例:DigitalOceanのプロバイダ名は「digitalocean」)。

そしてAWSの場合は、どのリージョンで稼働させるかを記入します。この例では「us-east-1」としていますが、東京リージョンを使う場合は「ap-northeast-1」とします。

次のブロックは「リソース」と呼ばれるものです。EC2インスタンスを起動するために、リソース名「aws_instance」を使い、「terraform_example」という名称のインスタンスを起動するものです。ここではUbuntu 14.04 LTSのAMI(Amazon Machine Image)と、インスタンスの種類も指定しています。SSHログインに必要なキーは、マネジメントコンソール上で登録済みのキー名称を「key_name」に記述します。

なお、リソースには命名規則があります。例えばプロバイダが「aws」の場合、リソース名は「aws_」で始まります。

Terraformでインスタンス起動

それでは、実際にTerraformを使ってインスタンスを起動しましょう。aws.tfを作成したディレクトリで、「terraform plan」コマンドを実行します。シークレットキー等の情報が正しければ、次のように変更予定の情報が表示されます。

コンソール画面

$ terraform plan
Refreshing Terraform state prior to plan...
(省略)

+ aws_instance.terraform_example
    ami:                      "" => "ami-408c7f28"
    availability_zone:        "" => "<computed>"
    ebs_block_device.#:       "" => "<computed>"
    ephemeral_block_device.#: "" => "<computed>"
    instance_type:            "" => "t1.micro"
    key_name:                 "" => "<computed>"
    placement_group:          "" => "<computed>"
    private_dns:              "" => "<computed>"
    private_ip:               "" => "<computed>"
    public_dns:               "" => "<computed>"
    public_ip:                "" => "<computed>"
    root_block_device.#:      "" => "<computed>"
    security_groups.#:        "" => "<computed>"
    subnet_id:                "" => "<computed>"
    tenancy:                  "" => "<computed>"
    vpc_security_group_ids.#: "" => "<computed>"

この段階では設定は適用されておらず、あくまで設定変更を確認するだけです。もしAMIの設定や認証情報が正しくなければ、事前に警告が表示されます。その場合は、エラー内容に従って、適切に記述されているかどうか、確認します。

エラーが出なければ、適用準備は完了です。実際にインスタンスを起動するには「terraform apply」を実行します。

コンソール画面

$ terraform apply
aws_instance.terraform_example: Creating...
  ami:                      "" => "ami-408c7f28"
  availability_zone:        "" => "<computed>"
  ebs_block_device.#:       "" => "<computed>"
  ephemeral_block_device.#: "" => "<computed>"
  instance_type:            "" => "t1.micro"
(省略)
aws_instance.terraform_example: Creation complete

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

このように「1 added」と表示されていれば、正常に処理が完了しています。そして、割り当てられたIPアドレスの情報を確認するには「terraform show」を実行します。

コンソール画面

$ terraform show
aws_instance.terraform_example:
  id = i-4a60fc9c
  ami = ami-408c7f28
  availability_zone = us-east-1e
  ebs_block_device.# = 0
  ebs_optimized = false
  ephemeral_block_device.# = 0
  instance_type = t1.micro
  private_dns = ip-10-232-98-201.ec2.internal
  private_ip = 10.232.98.201
  public_dns = ec2-54-163-125-154.compute-1.amazonaws.com
  public_ip = 54.163.125.154
(省略)

ここで表示される情報は、AWSマネジメントコンソールで表示される情報と同一のものです。ブラウザでアクセスし、N.VirginiaリージョンのEC2インスタンス情報を確認すると、実際に作成されているものと同じ情報が表示されていることが分かります。

Terraformで作成したEC2インスタンスの情報を、AWSマネジメントコンソールで確認

図2:Terraformで作成したEC2インスタンスの情報を、AWSマネジメントコンソールで確認

インスタンスの削除

起動したインスタンスを削除する場合も、再び「terraform plan」を実行しますが、削除の場合は「-destroy」オプションを使います。表示される内容から、削除対象のリソースや名称が相違ないことを確認します。

コンソール画面

$ terraform plan -destroy
Refreshing Terraform state prior to plan...

aws_instance.terraform_example: Refreshing state... (ID: i-4a60fc9c)
(省略)
- aws_instance.terraform_example

最終的に削除するのは「terraform destroy」コマンドです。コマンドを実行すると、「本当に削除しても構いませんか?」と確認が表示されます。「Enter a value:」に「yes」と入力することで、次のように削除が進行します。

コンソール画面

$ 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

aws_instance.terraform_example: Refreshing state... (ID: i-4a60fc9c)
aws_instance.terraform_example: Destroying...
aws_instance.terraform_example: Destruction complete

Apply complete! Resources: 0 added, 0 changed, 1 destroyed.
これでインスタンスの削除が完了しました。ブラウザでマネジメントコンソールを開くと、同様に削除されていることが確認できます。以上がTerraformを使った基本的な操作の流れになります。 == Elastic IPをインスタンスに自動割り当て ここまでは、単にインスタンスを起動させる例を紹介しましたが、Terraformができるのはこれだけではありません。別々のリソースを自動的に割り当てることができます。 先ほどの「aws.tf」に、Elastic IPのリソース情報を追加させてみましょう。

ソースコード

resource "aws_eip" "ip" {
    instance = "${aws_instance.terraform_example.id}"
}

通常、インスタンス起動前に作成予定のインスタンスIDは分かりませんが、Terraformであれば変数として利用できます。

まず、「aws_eip」というリソースに「ip」という名前を割り当てます。その次のインスタンス名に「${aws_instance.terraform_example.id}」を指定しているのは、リソース「aws_instance」の名称「terraform_example」のインスタンスIDを変数として割り当てるものです。

ファイルに追加後、再び「terraform plan」コマンドを実行します。すると今度は、リソースaws_eipに関する情報が追加されていることが分かります。

コンソール画面

$ terraform plan
Refreshing Terraform state prior to plan...

+ aws_eip.ip
    allocation_id:     "" => "<computed>"
    association_id:    "" => "<computed>"
    domain:            "" => "<computed>"
    instance:          "" => "${aws_instance.terraform_example.id}"
    network_interface: "" => "<computed>"
    private_ip:        "" => "<computed>"
    public_ip:         "" => "<computed>"
(省略)

エラーがなければ準備完了です。設定を適用するため「terraform apply」コマンドを実行します。正常に処理が進むと、先ほどのインスタンス追加に加え、追加されたElastic IPの情報も参照できます。

コンソール画面

aws_instance.terraform_example: Creation complete
aws_eip.ip: Creating...
  allocation_id:     "" => "<computed>"
  association_id:    "" => "<computed>"
  domain:            "" => "<computed>"
  instance:          "" => "i-36f669e0"
  network_interface: "" => "<computed>"
  private_ip:        "" => "<computed>"
  public_ip:         "" => "<computed>"
aws_eip.ip: Creation complete

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

作成後は、先ほどのインスタンス同様に「terraform plan -destroy」「terraform destroy」コマンドを実行し、破棄しておきます。

その他のリソース

Terraformが扱えるのは、今回の例で紹介したインスタンスとElastic IPだけに留まりません。セキュリティグループや、IAM関係の管理、キーペア関連、Route53、VPC関連など、様々なリソースを扱えます。ただし、まだ実装途中のものもあり、詳しい動作範囲や挙動はドキュメントをお読みいただくか、実際にお試しいただければと思います。

DigitalOceanをTerraformで操作するには

最後にAWS以外にも使える例として、DigitalOceanの仮想サーバ(ドロップレット)の構築・削除を行ってみます。DigitalOceanは1分以内に仮想サーバが起動できるだけでなく、課金が時間単位であるなど、使い勝手が手頃です。しかし、毎回ブラウザを通して起動・削除するのは面倒ではないでしょうか。Terraformであれば、AWSと同様にDigitalOceanでも迅速な環境構築を行えます。

digitalocean.tfファイルの用意

任意のディレクトリに「digitalocean.tf」ファイルを作成します。この時、先ほど作業したAWS用のディレクトリとは別の場所で作業をします。これは、Terraformが実行時に同一ディレクトリ内にある*.tfファイル全てを読み込むことに加え、Terraform内部で使用する中間ファイルをディレクトリ内に置いているためです。

ファイルの中身は、次のようにします。あらかじめDigitalOceanのアカウントと、APIトークンの作成が必要です。

ソースコード

provider "digitalocean" {
    token = "<DigitalOceanのAPIトークン>"
}

resource "digitalocean_droplet" "example" {
    image = "centos-6-5-x64"
    name = "terraform.example.jp"
    region = "sgp1"
    size = "512mb"
    private_networking = true
    ssh_keys = ["<SSH鍵ID>"]
}

1つめのブロックは「digitalocean」のプロバイダを指定しています。2つめのブロックで、「digitalocean_droplet」というドロップレットに対するリソースを指定しています。あとは仮想マシン・イメージにCentOSを指定し、ホスト名、データセンタ、メモリ、プライベート・ネットワークの有効化を指定しています。

AWSの場合はプロバイダ「aws」に対して、リソース名は「aws_」で始まるという命名規則がありました。DigitalOceanも同様で、プロバイダ「digitalocean」に対応する各種のリソース名は「digitalocean_」で始まります。これは、他のプロバイダでも同様です。

なお、あらかじめSSH鍵をDigitalOceanに登録している場合は、その鍵を割り当てることもできます。登録済みの鍵IDを確認するためには、次のコマンドを実行して確認できます。

コンソール画面

$ curl -X GET -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer <DigitalOceanのAPIトークン>' \
    "https://api.digitalocean.com/v2/account/keys"

ドロップレトの起動と破棄

「terraform plan」を実行し、マシン・イメージやホスト名やスペックが適切かどうか確認できます。

コンソール画面

$ terraform plan

+ digitalocean_droplet.example
    image:                "" => "centos-6-5-x64"
    ipv4_address:         "" => "<computed>"
    ipv4_address_private: "" => "<computed>"
    ipv6_address:         "" => "<computed>"
    ipv6_address_private: "" => "<computed>"
    locked:               "" => "<computed>"
    name:                 "" => "terraform.example.jp"
    private_networking:   "" => "1"
    region:               "" => "sgp1"
    size:                 "" => "512mb"
    ssh_keys.#:           "" => "1"
    ssh_keys.0:           "" => "737302"
    status:               "" => "<computed>"

内容に問題がなければ「terraform apply」を実行します。正常に処理されれば、図3のようにドロップレットが自動作成されていることが分かります。

Terraformで作成したドロップレットの状態を確認する

図3:Terraformで作成したドロップレットの状態を確認する

作業後のドロップレット破棄も手軽です。

コンソール画面

$ terraform plan -destroy
$ 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

digitalocean_droplet.example: Refreshing state... (ID: 5195198)
digitalocean_droplet.example: Destroying...
digitalocean_droplet.example: Destruction complete

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

まとめ

これまで見てきたように、Terraformはインフラの状態をコードで管理することができるツールです。数台程度の利用環境であれば、その効果は実感しづらいかもしれませんが、管理対象の台数が多い場合や、繰り返し作業が多い環境では力を発揮するのではないでしょうか。

Terraformはまだ開発途上であり、多くのクラウド環境の全ての機能には対応できていません。しかしながら、機能追加やバグ修正の開発スピードは非常に速いです。バグ発見や機能追加を希望される場合は、GitHub上でissueやプルリクエストを送ってみてはいかがでしょうか。

次回は、Consulを使ったクラスタ管理の方法をご紹介予定です。

※本稿は、2015年7月現在のTerraform v0.6.0に対して確認を行っています。

【参考文献】

Terraform(アクセス:2015/07)
https://terraform.io/

TERRAFORM DOCUMENTATION(アクセス:2015/07)
https://terraform.io/docs/index.html

著者
前佛 雅人(ぜんぶつ まさひと)
クリエーションライン株式会社

Technology Evangelist
ホスティングサービスで運用保守サポートに携わった後、現職へ。サポート業務や新技術検証や開発業務を行う傍ら、実家で農作業のため東京と富山を往復する日々。趣味で監視や自動化に関するOSS検証や翻訳を行う。とりわけ運用・監視の省力化・最適化に興味。辛口の日本酒が大好き。
Twitter: @zembutsu (https://twitter.com/zembutsu)

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています