Geek-Side

<< < 1 > >>

TerraformでSnapshotからAMI作って立ち上げる


独自のAMIを作ってたら、どうもうまく行かず。Try and Errorの様相を呈してきた。
何度もSnapshot作ってAMIを作ってLaunchってやり始めたので、Terraformでこの辺をやるようにした。

ただ、EBSボリュームからSnapshotを作る部分は見つけられなかったので、Snapshotを作るところは手動です。


resource "aws_ami" "origin-base" {
    name = "origin-base-20161124"
    virtualization_type = "hvm"
    root_device_name = "/dev/sda1"

    ebs_block_device {
        device_name = "/dev/sda1"
        snapshot_id = "snap-60559eee"
        volume_size = 10
    }
}

resource "aws_instance" "gside-origin" {
    ami                         = "${aws_ami.origin-base.id}"
    availability_zone           = "${aws_subnet.main.availability_zone}"
    ebs_optimized               = false
    associate_public_ip_address = false
    instance_type               = "t2.nano"
    monitoring                  = false
    key_name                    = "${aws_key_pair.gside-key.key_name}"
    vpc_security_group_ids      = ["${aws_security_group.basic.id}"]
    associate_public_ip_address = true
    disable_api_termination     = "true"
    source_dest_check           = "false"
    subnet_id 			= "${aws_subnet.main.id}"

    root_block_device {
        volume_type           = "gp2"
        volume_size           = 10
        delete_on_termination = true
    }

    tags {
        "Name" = "gside-origin"
    }
}

Terraformで追加のEBSをインスタンスにAttacheする


とあるインスタンスに追加でEBS VolumeをAttacheしたかったのですが、
現在のTerraform(Ver 0.7.9)では新規にインスタンスを作成し直さないとできないようです。
残念。

ebs_block_deviceの箇所で追加のEBSについて記載しています。
サイズとマウントポイントを記載するだけ。
簡単なんだけどやはりインスタンス作りなおしなのは惜しいですね。

resource "aws_instance" "gside" {
    ami                         = "ami-0c11b26d"
    availability_zone           = "${aws_subnet.main.availability_zone}"
    ebs_optimized               = false
    associate_public_ip_address = false
    instance_type               = "t2.nano"
    monitoring                  = false
    key_name                    = "${aws_key_pair.gside-key.key_name}"
    vpc_security_group_ids      = ["${aws_security_group.basic.id}"]
    associate_public_ip_address = true
    private_ip                  = "10.0.1.10"
    disable_api_termination     = "true"
    source_dest_check           = "false"
    subnet_id 			= "${aws_subnet.main.id}"

    root_block_device {
        volume_type           = "gp2"
        volume_size           = 10
        delete_on_termination = true
    }

    ebs_block_device {
	device_name = "/dev/xvdb"
        volume_size           = 10	
    }

    tags {
        "Name" = "gside"
    }
}

インスタンスにログインしてディスクの状況を確認します。

[ec2-user@ip-10-0-1-10 ~]$ lsblk 
NAME    MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
xvda    202:0    0  10G  0 disk 
└─xvda1 202:1    0  10G  0 part /
xvdb    202:16   0  10G  0 disk 

sshの鍵をTerraformで扱う


AMIを作る時に必要なSSHのキーですが、
Terraformでは鍵のインポートのみサポートしています。
確かに秘密鍵をダウンロードするより、公開鍵をアップロードするほうが健全ですね。

鍵の作成


手元のPCで秘密鍵と公開鍵のペアを作成します。

$ ssh-keygen -t rsa -b 2048
Generating public/private rsa key pair.
Enter file in which to save the key
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in 
Your public key has been saved in 
The key fingerprint is:

Terraformで公開鍵をアップロード


リソースにaws_key_pairを使って、公開鍵をアップロードします。
key_nameの参照には${aws_key_pair.gside-key.key_name}を使います。

resource "aws_key_pair" "gside-key" {
  key_name = "gside-key" 
  public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCvGSftV0pe4Pu4AA6CIwZ5QwUnVmO1YZ6LnkUuY1oti0OBuwNhvKE2gJ7eELwUmXLixq5OsccItAeUyIstp8u86AJqaO4DeZBE6gHwaBlrKKG+0b0jFsNCtfFu/jFsmnTuED5I/MpggUk0NKV4BFveqX9Wi7fxaOt5XEsx4XR9mJD+RrtrVAuzSoSK3y3jJgLKpBku1TqcaPZutE6fHIE6OalPRY0JCrN9WzQmFWXL+whTe9KaPMKs6PdHeFG+KBpnY9VjQxxc+lPmMfcID1t/xAuYpi5TZQbtB+YH5Qrn4uz+v1FyL9N/GYmcX8dVz9d9HMgXDUgzgEZU3JpWd6uf gside"
}

resource "aws_instance" "gside" {
    ami                         = "ami-0c11b26d"
    availability_zone           = "${aws_subnet.main.availability_zone}"
    ebs_optimized               = false
    associate_public_ip_address = false
    instance_type               = "t2.nano"
    monitoring                  = false
    key_name                    = "${aws_key_pair.gside-key.key_name}"
    vpc_security_group_ids      = ["${aws_security_group.basic.id}"]
    associate_public_ip_address = true
    private_ip                  = "10.0.1.10"
    disable_api_termination     = "true"
    source_dest_check           = "false"
    subnet_id 			= "${aws_subnet.main.id}"

    root_block_device {
        volume_type           = "gp2"
        volume_size           = 10
        delete_on_termination = true
    }

    tags {
        "Name" = "gside"
    }
}

まとめ


これで秘密鍵をダウンロードする気持ち悪さからもおさらばです。

Route53のHealthをTerraformで設定してみる


先日入門したTerraform、Route53のURL監視も入れてみました。
ポイントとしては、Route53のCloudWatchアラームはN.Virginiaのリージョンで作る必要がある点です。
それ以外のリージョンは現在はサポートされていません。

Route53のヘルスチェックを作成する


Route53のヘルスチェックを作成します。

resource "aws_route53_health_check" "gside" {
  fqdn = "gside.org"
  port = 80
  type = "HTTP"
  resource_path = "/blowg/b"
  failure_threshold = "3"
  request_interval = "30"

  tags = {
    Name = "gside"
   }
}

Cloudwatchアラームを作成する


前述したように、N.VirginiaのリージョンにClouwdWatchアラームを作成します。
dimensionsには先程作成したRoute53のヘルスチェックのIDを指定します。

provider "aws" {
    region = "us-east-1"
    alias = "virginia"
}

resource "aws_cloudwatch_metric_alarm" "gside-healthcheck" {
    provider      = "aws.virginia"
    alarm_name = "gside-healthcheck"
    comparison_operator = "GreaterThanThreshold"
    evaluation_periods = "1"
    metric_name = "HealthCheckStatus"
    namespace = "AWS/Route53"
    period = "60"
    statistic = "Minimum"
    threshold = "1"
    alarm_description = "This metric monitor gside url healthcheck"
    dimensions {
        HealthCheckId="${aws_route53_health_check.gside.id}"
	}
    alarm_actions = ["arn:aws:sns:xxxxxxx"]
}

まとめ


ClouwdWatchアラームをN.Virgnia以外で作成して、なかなかRoute53ヘルスチェックと関連づかずハマりましたが、
それ以外は問題なく作成できる内容でした。
ちなみにアラート時のEmail送信用SNSを作るところもTerraform化しようとしましたが、
Emailは送信者認証が入るところがTerraformのモデルに合わず未サポートだそうです。

Terraform入門してみた


まずはこのBlogをホストしている環境をTerrraorrm化してみました。
いまだにClassic EC2を使ってたので、そろそろ再構築したかったんですよね。

インストール


https://www.terraform.io/downloads.html
ダウンロードしたファイルを解凍して、terraformファイルにパスを通しておきます。

構成


1つのVPCに1つのsubnetを割り振って、その中でインスタンスを起動します。
ELBは使わず、EIPを割り振ります。

実行


アクセスキーとシークレットキーを環境変数に設定します。
$ export AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXXXXX
$ export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
$ export AWS_DEFAULT_REGION=ap-northeast-1

$ terraform plan
で変更箇所を確認して、
$ terraform apply
で実行します。

terraform.tfstateの管理


terraformはterraform.tfstateというファイルで、対象のインフラ構成の状態を管理しています。
実際のインフラ構成の状態をこのファイルで管理しているので、重要なファイルです。

こいつはterraformを実行するどの環境でも同じ物である必要があります。
というわけで、こいつをS3で管理してみます。

$ aws s3 mb s3://gside-terraform-state
make_bucket: s3://gside-terraform-state/
$ terraform remote config -backend=S3 -backend-config="bucket=gside-terraform-state" -backend-config="key=terraform.tfstate"
Remote configuration updated
Remote state configured and pulled.

この設定の後は、S3でterraform.tfstateファイルを管理しつつ、特にS3を意識することなくterraformが使えます。

まとめ


拍子抜けするくらい簡単にterraform化が終わってしまいました。
既存の環境をimportする機能もついたということで、ますます利用するシーンが増えそうです。

参考に今回実行したコードを載せておきます。

resource "aws_vpc" "main" {
    cidr_block = "10.0.0.0/16"
}

resource "aws_internet_gateway" "gw" {
    vpc_id = "${aws_vpc.main.id}"

    tags {
        Name = "main"
    }
}

resource "aws_subnet" "main" {
    vpc_id = "${aws_vpc.main.id}"
    cidr_block = "10.0.1.0/24"

    tags {
        Name = "Main"
    }
}

resource "aws_route_table" "r" {
    vpc_id = "${aws_vpc.main.id}"
    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = "${aws_internet_gateway.gw.id}"
    }

    tags {
        Name = "main"
    }
}

resource "aws_route_table_association" "a" {
    subnet_id = "${aws_subnet.main.id}"
    route_table_id = "${aws_route_table.r.id}"
}

resource "aws_security_group" "basic" {
    name        = "basic"
    description = "basic security group for web"
    vpc_id      = "${aws_vpc.main.id}"

    ingress {
        from_port       = 22
        to_port         = 22
        protocol        = "tcp"
        cidr_blocks     = ["0.0.0.0/0"]
    }

    ingress {
        from_port       = 80
        to_port         = 80
        protocol        = "tcp"
        cidr_blocks     = ["0.0.0.0/0"]
    }

    ingress {
        from_port       = 443
        to_port         = 443
        protocol        = "tcp"
        cidr_blocks     = ["0.0.0.0/0"]
    }


}

resource "aws_instance" "gside" {
    ami                         = "ami-c1fe26a2"
    availability_zone           = "${aws_subnet.main.availability_zone}"
    ebs_optimized               = false
    associate_public_ip_address = false
    instance_type               = "t1.micro"
    monitoring                  = false
    key_name                    = "ec2Key"
    vpc_security_group_ids      = ["${aws_security_group.basic.id}"]
    associate_public_ip_address = true
    private_ip                  = "10.0.1.10"
    disable_api_termination     = "true"
    source_dest_check           = "false"
    subnet_id 			= "${aws_subnet.main.id}"

    root_block_device {
        volume_type           = "gp2"
        volume_size           = 10
        delete_on_termination = true
    }

    tags {
        "Name" = "gside"
    }
}

resource "aws_eip" "gside" {
  vpc = true

  instance                  = "${aws_instance.gside.id}"
  associate_with_private_ip = "10.0.1.10"
}
</code>