Terraformを使ってみる
概要
役割と期待すること
TerrafomとはHashicorpが開発したソフトウェアで、役割はインフラの構築・変更を定義ファイルベースで行うことです。
構築作業を定義ファイルベースで行うことで、次のことが期待できます。
自動化 | 構築作業の自動化と複数回の実行 |
---|---|
可視化 | 構築定義・変更定義の可視化 |
版管理 | 各種定義の版管理 |
定義を作成により実行を自動化するという流れや、それによって受けられる恩恵が単体テストの自動化と似ていますね。また実行に関しても最適化されており依存性のない作業同士は並列で実行されるという非機能面での恩恵もあります。
対応する環境
2016年10月現在では次のサービスに対応しています。色々とあり過ぎておなかが減ってきますね。今回は公式サイトのGetting Startedの流れに倣ってAWS環境を利用してゆきます。
Archive | Atlas | AWS | Bitbucket | Bitbucket |
Chef | CenturyLinkCloud | CloudFlare | CloudStack | Cobbler |
Consul | Datadog | DigitalOcean | DNSMadeEasy | DNSimple |
Docker | Google Cloud | Dyn | GitHub | Fastly |
Grafana | Heroku | InfluxDB | Librato | Logentries |
Mailgun | Microsoft Azure | Microsoft Azure(Legacy ASM) | ||
MySQL | OpenStack | Packet | PostgreSQL | PowerDNS |
RabbitMQ | Random | Rundeck | StatusCake | SoftLayer |
Scaleway | Template | Terraform | TLS | Triton |
UltraDNS | VMware vCloud Director | VMware vSphere |
公式サイト
こちらが公式サイトになります。詳細情報や関連ソフトウェアの情報が掲載されていますので確認してみてください。
Terraform by HashiCorp
インストール
さて実際にインストールから実行してゆきます。公式サイトより適切なパッケージ(下記のOSに対応)をダウンロードしてください。現時点での最新版は0.7.7となります。
- Mac OS X (32-bit, 64-bit)
- FreeBSD (32-bit, 64-bit, Arm)
- Linux (32-bit, 64-bit, Arm
- OpenBSD (32-bit, 64-bit)
- Solaris (64-bit)
- Windows (32-bit, 64-bit)
ダウンロードが完了したら環境に応じた方法でPATHを通してください。(僕は面倒なので /usr/local/sbinに実行ファイルを入れました) 終わったら正常にインストール出来たかterraform -v
で確認してみましょう。
$ terraform -v Terraform v0.7.7
定義ファイルの作成
環境が出来たら定義ファイルを作成してゆきます。正式名称は Terraform Configurationとなります。
定義ファイルの形式
形式は独自の Terraform Format(*.tf)または JSON(*.tf.json) の何れかを任意で選択します。公式では人間の可視性の観点から前者の利用を推奨しています。後者はプログラム等による出力を想定して用意したものの様です。個人的にはJSONでも充分見やすいと思います。
ファイルの定義
では実際に定義ファイルを作成します。定義ファイルの内容は、対応するサービス種別(provider)と、内部資源(resource)の 2部で構成されます。なお今回はサンプルなので providerの認証情報も内部定義していますが、版管理の観点から外部ファイルに切り出すことも可能です。
provider "aws" { access_key = "(自身のAWS環境のアクセスキーを設定)" secret_key = "(自身のAWS環境のシークレットキーを設定)" region = "us-east-1" } resource "aws_instance" "example" { ami = "ami-0d729a60" instance_type = "t2.micro" }
計画
terraform plan
で実行計画を確認することができます。実環境は変更しない点で後述のterraform apply
とは異なります。
$ terraform 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. The Terraform execution plan has been generated and is shown below. Resources are shown in alphabetical order for quick scanning. Green resources will be created (or destroyed and then created if an existing resource exists), yellow resources are being changed in-place, and red resources will be destroyed. Cyan entries are data sources to be read. Note: You didn't specify an "-out" parameter to save this plan, so when "apply" is called, Terraform can't guarantee this is what will execute. + aws_instance.example ami: "ami-0d729a60" availability_zone: "<computed>" ebs_block_device.#: "<computed>" ephemeral_block_device.#: "<computed>" instance_state: "<computed>" instance_type: "t2.micro" key_name: "<computed>" network_interface_id: "<computed>" placement_group: "<computed>" private_dns: "<computed>" private_ip: "<computed>" public_dns: "<computed>" public_ip: "<computed>" root_block_device.#: "<computed>" security_groups.#: "<computed>" source_dest_check: "true" subnet_id: "<computed>" tenancy: "<computed>" vpc_security_group_ids.#: "<computed>" Plan: 1 to add, 0 to change, 0 to destroy.
実行
terraform apply
で実行をかけます
$ terraform apply aws_instance.example: Creating... ami: "" => "ami-0d729a60" availability_zone: "" => "<computed>" ebs_block_device.#: "" => "<computed>" ephemeral_block_device.#: "" => "<computed>" instance_state: "" => "<computed>" instance_type: "" => "t2.micro" key_name: "" => "<computed>" network_interface_id: "" => "<computed>" placement_group: "" => "<computed>" private_dns: "" => "<computed>" private_ip: "" => "<computed>" public_dns: "" => "<computed>" public_ip: "" => "<computed>" root_block_device.#: "" => "<computed>" security_groups.#: "" => "<computed>" source_dest_check: "" => "true" subnet_id: "" => "<computed>" tenancy: "" => "<computed>" vpc_security_group_ids.#: "" => "<computed>" aws_instance.example: Still creating... (10s elapsed) aws_instance.example: Still creating... (20s elapsed) aws_instance.example: Still creating... (30s 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を選択します。
どうやら無事動いている様です。
尚 AccessKey/SecretAccessKey のオーナーとなるAWS上のIAMユーザにEC2へのアクセス権が無いと以下の様にエラーとなります。
Error applying plan: 1 error(s) occurred: * aws_instance.example: Error launching source instance: UnauthorizedOperation: You are not authorized to perform this operation. Encoded authorization failure message: DyxG53T..... status code: 403, request id: 81414ade-9598-403f-af9a-5d264bff26a3 Terraform does not automatically rollback in the face of errors. Instead, your Terraform state file has been partially updated with any resources that successfully completed. Please address the error above and apply again to incrementally change your infrastructure.
この場合、AWSのマネージメントコンソール上で サービスからIAM (Identity and Management Service)を選択し、該当ユーザに適切な権限を与えて下さい。(下の画面では暫定でEC2のフルアクセスを与えています)
結果の確認
先にAWSの管理コンソールから結果を確認しましたが、実は Terraformのコマンドからも結果の確認が可能です。
terraform show
で以下の様な表示が出ます。
aws_instance.example: id = i-xxxxxxxx ami = ami-xxxxxxxx availability_zone = us-east-1b disable_api_termination = false ebs_block_device.# = 0 ebs_optimized = false ephemeral_block_device.# = 0 iam_instance_profile = instance_state = running instance_type = t2.micro key_name = monitoring = false network_interface_id = eni-xxxxxxxx private_dns = ip-xxx-xx-xx-xxx.ec2.internal private_ip = xxx.xxx.xxx.xxx public_dns = ec2-xxx-xxx-xxx-xxx.compute-1.amazonaws.com public_ip = xxx.xxx.xxxx.xxx root_block_device.# = 1 root_block_device.0.delete_on_termination = true root_block_device.0.iops = 0 root_block_device.0.volume_size = 8 root_block_device.0.volume_type = standard security_groups.# = 0 source_dest_check = true subnet_id = subnet-xxxxxxxx tags.% = 0 tenancy = default vpc_security_group_ids.# = 1 vpc_security_group_ids.xxxxxxxxxx = sg-xxxxxxxx
尚、この情報は実行時に作成された terraform.tfstateというファイルが入力元となっています。
$ ls
example.tf terraform.tfstate terraform.tfstate.backup