AWS

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

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

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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"
    }
}

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

1
2
3
4
5
[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で秘密鍵と公開鍵のペアを作成します。

1
2
3
4
5
6
7
8
$ 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}を使います。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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"
    }
}

まとめ

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

S3のEtagの値はMD5と同じ?

MD5でファイルが同じかどうかを判定することがあります。

S3ではETAGにMD5値が格納されているという事になっていますが、 結論から言うと、Multipart Updateされた場合と、そうでない場合で異なります。

s3 cpコマンドで試してみる(9M)

9Mのテストファイルを作ります。

1
2
3
4
$ dd if=/dev/zero of=~/test9M bs=1M count=9
9+0 レコード入力
9+0 レコード出力
9437184 バイト (9.4 MB) コピーされました、 0.0269213 秒、 351 MB/秒

Bucketにコピーします。

1
2
$ aws s3 cp ~/test9M  s3://gside-test/test9M
upload: ../test9M to s3://gside-test/test9M

このコマンドでアップロードされた9Mのファイルは、ETAGがこんな感じ

1
2
3
4
5
6
7
8
9
 $ aws s3api head-object --bucket gside-test --key test9M
{
    "Metadata": {},
    "ETag": "\"d126ef08817d0490e207e456cb0ae080-2\"",
    "ContentLength": 9437184,
    "LastModified": "Sat, 22 Oct 2016 14:20:04 GMT",
    "ContentType": "binary/octet-stream",
    "AcceptRanges": "bytes"
}

ETagの値は “d126ef08817d0490e207e456cb0ae080-2” とハイフン付きの値です。 一方MD5はというと

1
2
$ md5sum ~/test9M
b82b4ab87e44976024abc14a1670dac

ETAGの値とは違ってますね。Multipartアップロードされたのが原因です。

s3 cpコマンドで試してみる(8M)

8Mのテストファイルで同様のことをやってみます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
$ dd if=/dev/zero of=~/test8M bs=1M count=8
8+0 レコード入力
8+0 レコード出力
8388608 バイト (8.4 MB) コピーされました、 0.0204059 秒、 411 MB/秒

$ aws s3 cp ~/test8M  s3://gside-test/test8M
upload: ../test8M to s3://gside-test/test8M

$ aws s3api head-object --bucket gside-test --key test8M
{
    "LastModified": "Sat, 22 Oct 2016 14:19:07 GMT",
    "AcceptRanges": "bytes",
    "Metadata": {},
    "ContentType": "binary/octet-stream",
    "ETag": "\"96995b58d4cbf6aaa9041b4f00c7f6ae\"",
    "ContentLength": 8388608
}

$ md5sum ~/test8M
96995b58d4cbf6aaa9041b4f00c7f6ae

今度はEtagとMD5が一致しています。Multipartでアップロードされなかったからですね。

解決策

s3api put-objectコマンドを使います。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ aws s3api put-object --bucket gside-test --key test9M --body ~/test9M
{
    "ETag": "\"b82b4ab87e44976024abc14a1670dac0\""
}

$ aws s3api head-object --bucket gside-test --key test9M
{
    "AcceptRanges": "bytes",
    "ContentLength": 9437184,
    "Metadata": {},
    "ContentType": "binary/octet-stream",
    "ETag": "\"b82b4ab87e44976024abc14a1670dac0\"",
    "LastModified": "Sat, 22 Oct 2016 14:36:02 GMT"
}

今度はEtagとMD5が一致しています。

最後に

MD5とETAGを比較して、同一性を検証しているようなスクリプトを書いててハマりました。 AWSコンソールからアップロードした場合は64Mを超える辺りから、Multipart Uploadになるようです。 気をつけましょう。

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

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

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

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
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を指定します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
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のモデルに合わず未サポートだそうです。

AWSソリューションアーキテクト プロフェッショナルに合格した

AWSソリューションアーキテクト プロフェッショナルに合格しました! これで今あるAWS試験で残すはDevOps プロフェッショナルのみとなりました。

AWSの経験値

ここ1年間くらいはAWSでインフラ運用・構築したり、アプリケーション基盤作ったり。 オンプレのインフラの構築・運用経験もあるけど、AWSとのハイブリット環境とかではないです。

勉強方法

Linux Academy っていうオンラインの対策コースを淡々とやりました。

動画とハンズオンで勉強をしていくサイトです。 英語なんで辛い部分もありますが、そこまで難しい英語じゃないと感じました。 動画で使ったスライドはダウンロードできるので、聞き取れなかったところも後でじっくり読めます。

あとは練習問題があるので、それをAnkiにほりこんで通勤時間に見てました。 練習問題は、不正解の選択肢の何がおかしいか、もしくは正解の選択肢と比較してどの点が劣っているかをを突っ込めるようになるまで勉強しました。 実際の試験で似たような問題もでましたが、問題丸暗記で通るほどゆるい試験ではないです。

また、会社がこの試験の推奨セミナー「Architecting on AWS – Advanced Concepts」を受講させてくれたのもでかかったです。 使ったことのなかったKinesisとかDirectConnectあたりのサービスの理解が進んだのがよかったです。 あれはいいセミナーでした。

勉強期間

2016年8月にシステムオペレーション(SysOps)アドミニストレーター – アソシエイト試験に合格してからすぐに勉強を始めたので、 期間としては2ヶ月ほど。 勉強時間はちゃんと測ってないけど、60時間くらいかな。

模擬試験

1週間前にうけた模試は、それなりに自信があったのに 33%で不合格。 点数が悪かった言い訳としては日本語が微妙でしたっていう所なんですが、 実際理解が甘いところもあったので、模擬試験の問題をじっくり、淡々と復習しました。

最後に

本番は結局75%で合格。 大体の問題は自分の中でロジックを組み立てて選択していけました。 あまり資格試験自体好きじゃないんですが、AWS試験はこれまで受験してきて実務にそれなりに役に立ってます。 少し休んでDevOpsプロフェッショナルにも挑戦していこうと思います。