DRYな備忘録

Don't Repeat Yourself.

Terraformってなんぞや

目的

  • Terraformのなんたるかを知る
  • Terraformの初歩的な使い方を知る
  • Terraformを使ってみる

調査

サンプルを眺める

より。HCL(HashiCorp Configuration Language) という文法で記述される。

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"
}

# aws_elb.frontendという名前のELBを建てて、80番ポートで受けて、
# その参照先が aws_instance.appという名前に帰属する
# 5つのインスタンスの8000番に向いているんだろうな、
# という雰囲気がなんとなくわかる。
# だけどこれ、VPCとかSecurityGroupとかどうなってるんだ?
# An AMI
variable "ami" {
  description = "the AMI to use"
}

/* A multi
   line comment. */
resource "aws_instance" "web" {
  ami               = "${var.ami}"
  count             = 2
  source_dest_check = false

  connection {
    user = "root"
  }
}

terraformのインストール

% brew search terraform
% brew info terraform
% brew install terraform
# 中略...
/usr/local/Homebrew/Library/Homebrew/brew.rb:12:in `<main>': Homebrew must be run under Ruby 2.3! (RuntimeError)

だっる。

% ruby --version
ruby 2.0.0p648 (2015-12-16 revision 53162) [universal.x86_64-darwin16]

クソ古いやん。

% rbenv versions
* system (set by /Users/otiai10/.rbenv/version)
% rbenv install --list | grep 2.3
% rbenv install 2.3.5
% rbenv global 2.3.5
% rbenv rehash
% ruby --version
ruby 2.3.5p376 (2017-09-14 revision 59905) [x86_64-darwin16]
% brew install terraform
% terraform --version
Terraform v0.10.7

はい。

Hello, Terraform!

% mkdir -p ~/tmp/terraform/hello
% cd ~/tmp/terraform/hello
% vi hello.tf
# プロバイダの設定。
# AWSを使うこと、API keys、リージョンなどを指定する。
provider "aws" {
    #  > Terraform will automatically search for saved API credentials (for example, in ~/.aws/credentials)
    # とのことなので、AWS Keysは割愛します
    /*
    access_key = "ACCESS_KEY"
    secret_key = "SECRET_KEY"
    */

    # ワケあってシドニー
    region = "ap-southeast-2"
}

# 具体的な構成の設定。
resource "aws_instance" "hello-terraform" {
    ami = "ami-2757f631"
    instance_type = "t2.micro"
}

この状況でplanしてみると、

Plugin reinitialization required. Please run "terraform init".
Reason: Could not satisfy plugin requirements.

Plugins are external binaries that Terraform uses to access and manipulate
resources. The configuration provided requires plugins which can't be located,
don't satisfy the version constraints, or are otherwise incompatible.

1 error(s) occurred:
# プロバイダの設定。

* provider.aws: no suitable version installed
  version requirements: "(any version)"
  versions installed: none

Terraform automatically discovers provider requirements from your
configuration, including providers used in child modules. To see the
requirements and constraints from each module, run "terraform providers".

error satisfying plugin requirements

まずinitしろと叱られる。

% terraform init

Initializing provider plugins...
- Checking for available provider plugins on https://releases.hashicorp.com...
- Downloading plugin for provider "aws" (1.1.0)...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.aws: version = "~> 1.1"

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

aws pluginがインストールされた模様。あらためてplanする

% 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.


------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  + aws_instance.hello-terraform
      id:                           <computed>
      ami:                          "ami-2757f631"
      associate_public_ip_address:  <computed>
      availability_zone:            <computed>
      ebs_block_device.#:           <computed>
      ephemeral_block_device.#:     <computed>
      instance_state:               <computed>
      instance_type:                "t2.micro"
      ipv6_address_count:           <computed>
      ipv6_addresses.#:             <computed>
      key_name:                     <computed>
      network_interface.#:          <computed>
      network_interface_id:         <computed>
      placement_group:              <computed>
      primary_network_interface_id: <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>
      volume_tags.%:                <computed>
      vpc_security_group_ids.#:     <computed>


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

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

当たり前だけど、もっと色々指定可能であることが分かる。前述の疑問(「だけどこれ、VPCとかSecurityGroupとかどうなってるんだ?」)は、vpc_security_group_idsあたりだろうか。いよいよ、applyしてローンチしてみる。

% terraform apply
# 中略
Error applying plan:

1 error(s) occurred:

* aws_instance.hello-terraform: 1 error(s) occurred:

* aws_instance.hello-terraform: Error launching source instance: InvalidAMIID.NotFound: The image id '[ami-2757f631]' does not exist
    status code: 400, request id: 00d6f091-b677-47ca-bc17-f8671eb07501

適当にドキュメントに書かれたAMI IDを使っていたので「AMIが存在しない」と叱られる。region変えたからかな。ちゃんと書いてやる。シドニーでいちばん簡単なAmazon Linuxってこれami-66fbe605でいいんだろうか。

resource "aws_instance" "hello-terraform" {
-    ami = "ami-2757f631"
+    ami = "ami-66fbe605"
    instance_type = "t2.micro"
}

あらためて。

% terraform apply
# 中略...
Apply complete! Resources:1 added, 0 changed, 0 destroyed.

f:id:otiai10:20171017143708p:plain

いいですね。

% terraform show

で色々確認できる。気づいたこと、

  • VPCを指定しなかったので、default VPCになってる
  • SecurityGroupも、defaultのものを使っている
    • 新規作成したい場合は、おそらくsgも.tfに書いて参照させればよいのだろう
    • VPC.tfでつくれるのかな?
  • key pairを指定しなかったので、おそらくsshはできない気がする
  • public IPも消せるのだろう
    • associate_public_ip_address = true これだ
  • Build Infrastructure - Terraform by HashiCorp
    • インスタンスつくった後のプロビジョニング(前述で「サーバ設定」と呼称したもの)もできるっぽい
    • その場合、key pairは自動でつくられるのかな?
  • このhello.tfによって定義されインスタンス化されクラスタへの参照は、terraform.tfstate, terraform.tfstate.backup に保存されているっぽい

クラスタインスタンスの変更・編集

The prefix "-/+" means that Terraform will destroy and recreate the resource, versus purely updating it in-place. While some attributes can do in-place updates (which are shown with a "~" prefix), AMI changing on EC2 instance requires a new resource. Terraform handles these details for you, and the execution plan makes it clear what Terraform will do.

resource "aws_instance" "hello-terraform" {
-    ami = "ami-66fbe605"
-    instance_type = "t2.micro"
+    ami = "ami-5bc2f938"
+    instance_type = "t2.nano"
}

AMIの変更・インスタンスタイプの変更は、インスタンスの作り直しが発生するので、かならず-/+となるはず。

% terraform plan
# 中略...
-/+ aws_instance.hello-terraform (new resource required)
      id:     "i-0f4c9ccc6ad36fb74" => <computed> (forces new resource)
      ami:    "ami-66fbe605" => "ami-5bc2f938" (forces new resource)
# 中略...

% terraform apply

クラスタインスタンスの削除

% terraform plan -destroy
% terraform destroy
# 中略
Destroy complete! Resources: 1 destroyed.

その他

DevOpsを支えるHashiCorpツール大全 ThinkIT Books

DevOpsを支えるHashiCorpツール大全 ThinkIT Books

雑感

  • 結局DSLを覚えるコストがあるけれど、覚えてしまえば便利そう
  • CloudFormationをポチポチやるよりはよっぽどよさそう
  • また肉離れした。全力で動いても壊れない身体が欲しい...

DRYな備忘録として