インフラの構成管理を自動化するTerraform入門
![](https://thinkit.co.jp/sites/default/files/styles/main_image_730x/public/main_images/6212_main_1.jpg?itok=qeHVKGhp)
Terraformとは?
これまでの連載で扱ってきたVagrantやPackerは、どちらかというと開発者向けのツールでした。それに対して今回紹介するTerraformは、インフラを構築するためのツールであり、開発者だけなく、運用担当者でも必要となりうるツールです。
TerraformはHashiCorpにより、オープンソースとして公開され、GitHub上で開発が進められています。ドキュメントでは、Terraformについて「インフラの構築・変更・バージョン管理を安全かつ効果的に行うためのツールです」と紹介されています。
Terraformは、Amazon Web Services(以下、AWS)だけでなく、DigitalOcean、GoogleCloud、Heroku、Docker、OpenStackなどの、様々なインフラに幅広く対応しています。
現時点では、それぞれのクラウドが提供する様々な機能に対応できていない箇所もあります。それでも、仮想サーバの起動や停止といった基本的な機能の多くには対応していますし、日々機能追加や改良がGitHub上で進められています。
Terraformが求められる背景
クラウド技術やサービスの普及によって、システムが動作する環境を必要な時に準備・調達し、すぐに利用できることが当たり前になりつつあります。しかもインフラは単に追加できるだけでなく、不要になった場合の削除もすぐに行えるようになりました。またそれらの作業は、ブラウザを通して簡単に行える点も魅力です。
その一方で、このクラウド上のインフラ(システム基盤)を、どのように管理・維持するのかという新しい課題が生まれつつあります。
例えばブラウザを通したGUIによって、インフラは誰でも手軽・簡単に操作できるようになりました。しかし作業者は人間であり、設定ミスを引き起こす懸念が少なからずあります。あるいは、しっかりした手順を作っていたとしても、クラウド上のサービスや仕様変更により、手順そのものを随時見直す必要性も生まれます。
インフラのコード化
インフラを安全かつ効率的に管理するために、Terraformはコードによってインフラの状態を定義します(Infrastructure as Code)。利用者は、テキスト形式のファイル上に、「どこのデータセンタで」、「どのようなスペックを持つ仮想サーバやリソースを使うのか」といったインフラの状態を、コードとして記述しておきます。
Terraformそのものは、コマンドライン上でインフラを操作するツールです。コード作成後は、「terraform plan」(計画)を実行して、どのように設定が反映されるのか確認します。内容に問題がなければ、「terraform apply」(適用)を実行し、実際のインフラに反映します。
インフラをコードとして記述することには、以下のような利点があります。
- GUIを通さずインフラに変更を加えられる
- コードを共有・再利用できる
- コードのバージョン管理ができる
- 設定適用前の第三者による確認ができる
この中でも特徴的なのは、GUIを通さずに環境の構築・変更・破棄ができる点です。しかもTerraformは自動的に作業を進行できますので、正確さと時間短縮という明確な利点をもたらします。
それだけでなく、インフラの状態をコードとして管理するため、一般的なソースコードと同じように、社内や組織での情報共有や、変更内容のレビューも簡単です。また、一時的に利用するような検証・デモ環境の構築や削除も、Terraformを使えば誰でも正確かつ迅速に行えるようになります。
一方で、Terraformを使うにあたっては、独自の書式を覚える必要があります。独自とはいえ、比較的シンプルなものですし、複雑な文法や記法でもありません。また、全てを覚える必要もなく、自分の使いたい機能に関する記法を覚えるだけで、すぐに利用できます。
APIや他のツールとの比較
Terraformと類似のツールや機能を比較してみると、そこにも違いがあります。クラウドごとにAPIやコマンドライン・ツールが提供されているほか、AWSにはCloudFormationが提供されています。
他のツールとの大きな違いは、使い始めるためには対象となるクラウドに関する知識だけでなく、APIやプログラミング言語に関する知識も必要となる点です。また、処理を実行する前の確認や、処理後に正常に動作しているかを確認する仕組みは提供されていません。
一方、Terraformは各クラウドの全ての機能を扱えるわけではなく、現時点では基本的なインフラや機能のサポートに留まっています。
Terraformは、ChefやPuppetのようなツールとも異なります。これらの構成管理ツールも、コードによってインフラを管理するものですが、管理する対象はOS上の設定やミドルウェア・開発環境です。一方Terraformは、クラウド用の仮想マシンやリソースを管理します。ですから必要があれば、TerraformはChefやPuppetと組みあわせて使うこともできます。
Terraformの構成と機能
Terraformは「リソース」と呼ばれる単位で、様々なクラウドの基盤を扱います。例えば、仮想サーバも1つのリソースです。他にも、マシン・イメージや、オブジェクト・ストレージ、DNSサービス、ロードバランサーなどの機能を、それぞれリソースとして扱います。
このリソース情報を、コードの中に記述します。コードを作成した後の流れは、次のようになります。
- コード(「.tf」形式のファイル)上で、インフラのリソース状態を定義する
- インフラの構築・変更・破棄を、すべてコマンドラインを通して行う
- 設定反映前にドライ・ラン機能(terraform plan)実行して確認後、設定を適用(terraform apply)する
- IPアドレスや仮想サーバに関する情報を確認する(terraform show)
この手順は環境を構築する時だけでなく、変更、削除の際も同じものです。作業は常に「terraform」コマンドを通して行います。コマンドを実行時、リソースで指定されたクラウドごとにterraform-providerが呼び出され、APIを通した自動処理を行います。仮想マシンが起動した後は、terraform-provisionerを通して、OS上の設定を自動的に行うプロビジョニングを行うこともできます(図1)。
Terraformのダウンロードとセットアップ
Terraformを使うにはバイナリファイルをダウンロードし、パスの通った場所にファイルをコピーします。
ダウンロード用ページから、最新安定版のTerraformをダウンロードします。以下はLinux(64bit版)バージョン0.6.0を例に、ダウンロードセットアップの手順を紹介します。ここではterraform(コマンド)本体と関連ファイルを「/usr/local/bin」に設置しています。
コンソール画面
$ wget -O terraform_0.6.0_linux_amd64.zip https://dl.bintray.com/mitchellh/terraform/terraform_0.6.0_linux_amd64.zip $ unzip terraform_0.6.0_linux_amd64.zip $ sudo cp ./terraform ./terraform-provider-* ./terraform-provisioner-* /usr/local/bin/
正常にセットアップされたかどうかを確認するには、「terraform version」コマンドを実行します。次のようにバージョン情報が表示されれば、準備完了です。
コンソール画面
$ terraform version Terraform v0.6.0
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 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.
ソースコード
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 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
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- マシン・イメージを自動構築し、作業効率を高めるPacker入門
- Iacツール「Terraform」の基本的な使い方
- TerraformからPulumiへの移行
- Oracle Cloud Hangout Cafe Season7 #2「IaC のベストプラクティス」(2023年7月5日開催)
- 「Terraform」のコードを自分で書けるようになろう
- SecretもPulumiで使いこなしたい! PulumiのSecurityを試してみよう
- 「Pulumi Stack」とは ー Pulumiによるマルチステージ環境の構築方法
- Policy as Codeでインフラのコンプライアンスを自動実現! 「Pulumi CrossGuard」を活用してみよう
- PulumiでAWSリソースをデプロイしよう
- 既に存在するリソースをPulumiで管理してみよう