ども、 cloudpackかっぱ (@inokara) です。

はじめに

terraform を独りハンズオンしてみたのでメモ。

terraform とは

参考

自分なりの terraform

  • インフラの構築・変更・バージョン管理を安全かつ効率的に行うための hashicorp 謹製ツール
  • 各種クラウドプロバイダに対応している
  • コードを使って(独自のDSL:※ JSON でも書ける)インフラの構成を記述することが出来る
  • 設定ファイルを実行する前に実行計画(plan)にて設定ファイルの事前の動作確認、適用(Apply)、実行結果の確認(show)を行うことが出来る
  • Provisioners を利用することで任意の構築手順(Chef/Ansible/Shell etc…)を利用して一気通貫で環境を構築することが出来る

で、何が出来るのか?

  • Terraform を使えば各種クラウド環境の構成をコードで管理することが出来るようになる!(はず)
  • クラウドベンダに依存しない環境(複数のクラウド環境を跨いだ環境)を管理出来るようになる!(はず)

俺の terraform イメージ

とりあえず自分の中での terraform のイメージを絵にしてみた。
terraform 独りハンズオン(1): 俺の terraform イメージ
多分、上図のような感じだと思ふ。

さて、ハンズオン

課題

以下のような環境を構築する。
terraform 独りハンズオン(1):  構築イメージ図

  • Security Group を 4 つ作成
  • Default VPC 内に EC2 を 3 台構築する
  • ELB を作成
  • EC2 には ApacheConsul をインストール
  • Apache を起動して ELB にぶら下げて外部からのアクセスを確認する
  • consul を起動して Atlas を利用してクラスタを構成する

terraform のインストール

バイナリパッケージのダウンロード

MacOS X 用のバイナリが配布されているのでダウンロード。

cd ~/bin/
wget https://dl.bintray.com/mitchellh/terraform/terraform_0.3.7_darwin_amd64.zip

展開

適当なディレクトリに展開する。

cd ~/bin/
unzip terraform_0.3.7_darwin_amd64.zip

パスを通す

MacOS X の場合であれば /User/${user}/bin には既にパスが通っているはずなので特に設定を行わない。但し、任意のパスに展開した場合にはパスを通す必要がある。

初めての Terraform

% terraform version
Terraform v0.3.7

ついでに help も確認。

% terraform help
usage: terraform [--version] [--help]  []

Available commands are:
    apply      Builds or changes infrastructure
    destroy    Destroy Terraform-managed infrastructure
    get        Download and install modules for the configuration
    graph      Create a visual graph of Terraform resources
    init       Initializes Terraform configuration from a module
    output     Read an output from a state file
    plan       Generate and show an execution plan
    pull       Refreshes the local state copy from the remote server
    push       Uploads the the local state to the remote server
    refresh    Update local state file against real resources
    remote     Configures remote state management
    show       Inspect Terraform state or plan
    version    Prints the Terraform version

準備が出来たところで…。

サンプルコード

以下にアップした。
inokappa/oreno-terraform

上記をもし利用するなら適宜 git clone する。

terraform.tfvars の修正

terraform.tfvars.exampleterraform.tfvars にリネームして環境に応じて適宜修正する。

access_key    = "AKxxxxxxxxxxxxxxxxxxxxxxxxxxx"
secret_key    = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
ssh_key_name  = "your_ssh_key"
ssh_allow_ip  = "xxx.xxx.xxx.xxx/32"
key_file_path = "/path/to/your_ssh_key.pem"
build_script  = "your_remote_script_endpoint/build.sh"

access_keysecret_key 等の情報は事前に作成しておく。また、terraform.tfvars ファイルには認証情報等の公に出来ない情報を記載しておいて .gitignore に登録してリポジトリでは管理しないようにしておく。

少しコードを見てみる

main.tf の冒頭、以下は Providor として AWS を使いまっせと宣言している。

provider "aws" {
    access_key = "${var.access_key}"
    secret_key = "${var.secret_key}"
    region = "${var.region}"
}

続いて…

resource "aws_security_group" "tf_allow_all" {
  name = "tf_allow_all"
    description = "tf_allow_all"

上記では aws_security_group リソースを利用して Security Group の作成を宣言している。このように terraform では Provider の各コンポーネントをリソースと呼んでおりこのリソースを定義していくことで環境を構築することになる。

各種 Provider 及びリソースに関しては以下を確認する。

Providor やリソースについては独自に作成、拡張することが出来るとのことなので機会があれば試してみたいけど…(Go Lang の知識が必要そうなので個人的には無理かもしれない…orz)

また、以下は provisioner "remote-exec" を用いて起動した EC2 インスタンス内でスクリプトを実行してミドルウェア等の設定を行っている。

  provisioner "remote-exec" {
    inline = [
      "sudo yum -y install wget",
      "sleep 1",
      "wget ${var.build_script} && chmod 755 ./build.sh",
      "sudo ./build.sh",
    ]
    connection {
      user = "ec2-user"
      key_file = "${var.key_file_path}"
    }
  }

inline を使ってコマンドの羅列を行っている。また、connection にてインスタンスにアクセスするユーザー名、SSH 鍵ファイルを指定している。

terraform plan

早速、環境を構築!…その前に terraform plan を実行してどのように構築されるかを確認する。

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


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.

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_elb.oreno_tf_test
    availability_zones.#:                        "" => ""
    dns_name:                                    "" => ""
    health_check.#:                              "" => "1"
    health_check.1986875447.healthy_threshold:   "" => "3"
    health_check.1986875447.interval:            "" => "60"
    health_check.1986875447.target:              "" => "HTTP:80/"
    health_check.1986875447.timeout:             "" => "5"
    health_check.1986875447.unhealthy_threshold: "" => "3"
    instances.#:                                 "" => ""
    internal:                                    "" => ""
    listener.#:                                  "" => "1"
    listener.3057123346.instance_port:           "" => "80"
    listener.3057123346.instance_protocol:       "" => "http"
    listener.3057123346.lb_port:                 "" => "80"
    listener.3057123346.lb_protocol:             "" => "http"
    listener.3057123346.ssl_certificate_id:      "" => ""
    name:                                        "" => "tf-test-elb"
    security_groups.#:                           "" => ""
    subnets.#:                                   "" => ""

+ aws_instance.oreno_tf_test.0
    ami:                        "" => "ami-18869819"
 
(略)

上記のように出力される。

terraform apply

それでは terraform apply を実行して環境を構築する。

terraform apply

以下のように出力される。
terraform 独りハンズオン(1):  terraform apply の出力
さらに暫くすると以下のように出力されて構築完了となる。
terraform 独りハンズオン(1):  terraform apply の出力 (2)
三台のインスタンスの起動、セットアップで 5 分も掛らないスピードにビックリ。

terraform show

terraform show を実行して構築した内容を改めて確認してみる。

% terraform show                                                                                                                                                                                 [~/git/myrepo/oreno-atlas]
aws_elb.oreno_tf_test:
  id = tf-test-elb
  availability_zones.# = 1
  availability_zones.3773642014 = ap-northeast-1a
  dns_name = tf-test-elb-xxxxxxxxxxx.ap-northeast-1.elb.amazonaws.com
  health_check.# = 1
  health_check.1986875447.healthy_threshold = 3
  health_check.1986875447.interval = 60
  health_check.1986875447.target = HTTP:80/
  health_check.1986875447.timeout = 5
  health_check.1986875447.unhealthy_threshold = 3
  instances.# = 3
  instances.1188170523 = i-xxxxxxxx
  instances.2577922738 = i-yyyyyyyyy
  instances.3003354613 = i-zzzzzzzz
  internal = false
  listener.# = 1
  listener.3057123346.instance_port = 80
  listener.3057123346.instance_protocol = http
  listener.3057123346.lb_port = 80
  listener.3057123346.lb_protocol = http
  listener.3057123346.ssl_certificate_id =
  name = tf-test-elb
  security_groups.# = 1
  security_groups.928549659 = sg-xxxxxxxx
  subnets.# = 1
  subnets.1735695288 = subnet-xxxxxxxx
aws_instance.oreno_tf_test.0:
  id = i-xxxxxxxx
  ami = ami-18869819
  availability_zone = ap-northeast-1a
  block_device.# = 0
  instance_type = t2.micro
  key_name = xxxxxxxxxxxxxxx
  private_dns = ip-172-31-xxx-xxx.ap-northeast-1.compute.internal
  private_ip = 172.31.xxx.xxx
  public_dns = ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com
  public_ip = xxx.xxx.xxx.xxx

(略)

おお、インスタンスも ELB もセキュリティグループも作られているっぽい。

ELB へのアクセス、consul クラスタの確認

環境構築は出来たので ELB のエンドポイントにアクセスしてみる。

$ http HEAD tf-test-elb-xxxxxxxxxx.ap-northeast-1.elb.amazonaws.com
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Type: text/html; charset=UTF-8
Date: Sat, 21 Mar 2015 01:25:04 GMT
ETag: "401ac-0-511c2176dc1d7"
Last-Modified: Sat, 21 Mar 2015 01:09:57 GMT
Server: Apache/2.2.29 (Amazon)
Connection: keep-alive

念の為にマネジメントコンソールで ELB の状態も確認。
terraform 独りハンズオン(1):  ELB へアクセス

美しい、全て InService や。
次に consul クラスタの状態を Atlas のコンソールから確認してみる。
terraform 独りハンズオン(1):  consulクラスタの状態をAtlasのコンソールから確認

ちゃんとジョインされておりクラスタが構成されている。 念の為にメンバーの一台にログインしてリーダーノード等を確認してみる。
メンツを確認。

$ consul members
Node              Address             Status  Type    Build  Protocol
ip-172-31-xx-126  172.31.xx.126:8301  alive   server  0.5.0  2
ip-172-31-xx-37    172.31.xx.37:8301    alive   server  0.5.0  2
ip-172-31-xx-108   172.31.xx.108:8301   alive   server  0.5.0  2

リーダーを確認。

$ curl localhost:8500/v1/status/leader
"172.31.xx.126:8300"

よしきた。満足、満足。

terraform destroy で後片付け

そこそこ満足したので terraform destroy を実行して環境を丸っと削除してしまう。
terraform 独りハンズオン(1): terraform destroy で後片付け

有難うございました。

おつかれさまでした

簡単な構成を terraform を使って構築してみた感想。

  • 何よりもコードになっているのがとても良い(ELB や SG を含めて活字になっているのは嬉しい)
  • 速い(今回の構成で 3 分程度)
  • 構築した環境を一気通貫で削除も出来るのがなにげに嬉しい
  • 独自 DSL だが簡単なので学習コストは低いと思う
  • DSL 以外に各クラウドサービスの仕様についてはもちろん把握しておく必要がある
  • たまによくわらかないエラーに遭遇する(二回目実行すると成功する…とか)

今後やってみたいこと。

  • AWS 以外のクラウドサービスとの合わせ技

ということで、インフラ構築、運用の悩みを解決していこうとすると気づいたら Hashicorp に辿り着いていた感じなので consul や Atlas を含めて terraform は勉強していきたいなー。

元記事はこちらです。
terraform 独りハンズオン(1)