Geek-Side

<< < 1 > >>

S3でバージョニングを有効にした時に以前のバージョンに戻す方法

aws 

S3のバージョニングの機能は知っていたのですが、
古いバージョンをリストアする方法をちゃんと調べていませんでした。

バックアップとっててリストアできないなんて、最低ですね。

バージョニングが有効なバケットを作成する


まずはバージョニングが有効なS3バケットを作成しましょう。
今回もTerraformでお手軽に作っていきます。

resource "aws_s3_bucket" "version-test" {
    bucket = "gside-version-test"
    acl = "private"
    versioning {
        enabled = true
    }
}

ファイルをアップロードする。


適当なファイルを作ってS3にアップします。

$ echo "hoge" > ~/hoge.txt
$ aws s3 cp ~/hoge.txt s3://gside-version-test/

aws s3api コマンドでバージョン情報を見てみます。

$ aws s3api list-object-versions --bucket gside-version-test
{
    "Versions": [
        {
            "VersionId": "i4ngO7osXqV4GrFoXpHzblnWD7y3jIRa",
            "Owner": {
                "DisplayName": "foobar",
                "ID": "2614e1fe5abbd1f85bc3c9b930b22f8f4f6eced59986b995b5e38cf655d7a7e0"
            },
            "LastModified": "2016-12-11T13:16:50.000Z",
            "StorageClass": "STANDARD",
            "ETag": "\"c59548c3c576228486a1f0037eb16a1b\"",
            "Key": "hoge.txt",
            "IsLatest": true,
            "Size": 5
        }
    ]
}

ファイルを更新して、バージョン情報を見てみます。

$ echo "fuga" > ~/hoge.txt
$ aws s3 cp ~/hoge.txt s3://gside-version-test/
$ aws s3api list-object-versions --bucket gside-version-test 
{
    "Versions": [
        {
            "LastModified": "2016-12-11T13:18:01.000Z", 
            "VersionId": "URhALfhfq69Zdqoh_z.b6j4ac5XR43oK", 
            "ETag": "\"11c9c5d7c37e614b4d99eea11672227e\"", 
            "StorageClass": "STANDARD", 
            "Key": "hoge.txt", 
            "Owner": {
                "DisplayName": "foobar", 
                "ID": "2614e1fe5abbd1f85bc3c9b930b22f8f4f6eced59986b995b5e38cf655d7a7e0"
            }, 
            "IsLatest": true, 
            "Size": 5
        }, 
        {
            "LastModified": "2016-12-11T13:16:50.000Z", 
            "VersionId": "i4ngO7osXqV4GrFoXpHzblnWD7y3jIRa", 
            "ETag": "\"c59548c3c576228486a1f0037eb16a1b\"", 
            "StorageClass": "STANDARD", 
            "Key": "hoge.txt", 
            "Owner": {
                "DisplayName": "foobar", 
                "ID": "2614e1fe5abbd1f85bc3c9b930b22f8f4f6eced59986b995b5e38cf655d7a7e0"
            }, 
            "IsLatest": false, 
            "Size": 5
        }
    ]
}

ファイルをリストアする。


ファイルをアップロードするにはaws s3api get-objectコマンドを利用して、上記のversion-idを指定してファイルを取得します。

$ aws s3api get-object --bucket gside-version-test --key hoge.txt --version-id i4ngO7osXqV4GrFoXpHzblnWD7y3jIRa /tmp/hoge.txt
{
    "AcceptRanges": "bytes", 
    "ContentType": "text/plain", 
    "LastModified": "Sun, 11 Dec 2016 13:16:50 GMT", 
    "ContentLength": 5, 
    "VersionId": "i4ngO7osXqV4GrFoXpHzblnWD7y3jIRa", 
    "ETag": "\"c59548c3c576228486a1f0037eb16a1b\"", 
    "Metadata": {}
}
$ cat /tmp/hoge.txt 
hoge

まとめ


復旧するファイルが少ない場合は、コマンドラインで淡々とリストアする方法で行けそうです。
ファイルが多くなると、もうちょっと工夫が必要そうですね。
ちなみにファイルが消した場合でも aws s3api list-object-versions の情報は消えないので、復旧することができます。

GentooのAMIを作る


GentooをAWS上で動かすために、イメージを作ってみました。
クラウドに使えるstage4ファイルを利用すれば、簡単にできてしまいます。

追加ボリュームにgentooをインストール後、snapshot作成、AMI作成という手順でいきました。

追加ディスクにGentooをインストールする。


何でもいいんで、LinuxベースのAMIを立ち上げ、
EBSボリュームを追加であタッチするところから始めます。

まずはディスクの用意から。/dev/xvdb が追加ディスクです。

parted -a optimal /dev/xvdb
(parted) mklabel gpt
(parted) unit mib                                                         
(parted) mkpart primary 1 3                                               
(parted) name 1 grub                                                      
(parted) set 1 bios_grub on       
(parted) mkpart primary 3 9000                                                    
(parted) name 2 cloudimg-rootfs
(parted) mkpart primary 9000 -1                                           
(parted) name 3 swap                                                      
(parted) print                                                            
Model: Xen Virtual Block Device (xvd)
Disk /dev/xvdb: 10240MiB
Sector size (logical/physical): 512B/512B
Partition Table: gpt

Number  Start    End       Size     File system     Name             Flags
 1      1.00MiB  3.00MiB   2.00MiB  ext4            grub             bios_grub
 2      3.00MiB  9000MiB   8997MiB                  cloudimg-rootfs
 3      9000MiB  10239MiB  1239MiB  linux-swap(v1)  swap
(parted) quit 

ファイルシステムを構築します。

$ mkfs.ext4 /dev/xvdb2
$ e2label /dev/xvdb2 cloudimg-rootfs
$ mkswap --label swap /dev/xvdb3
$ mkdir -p /mnt/gentoo
$ mount /dev/xvdb2 /mnt/gentoo
$ swapon /dev/xvdb3 

stageファイルを展開します。

$ cd /mnt/gentoo
$ wget http://distfiles.gentoo.org/releases/amd64/autobuilds/current-stage3-amd64/stage4-amd64-cloud-20161201.tar.bz2
$ tar xjf stage4-amd64-cloud-20161201.tar.bz2

もろもろmountして、

$ mount -t proc proc /mnt/gentoo/proc
$ mount --rbind /sys /mnt/gentoo/sys
$ mount --rbind /dev /mnt/gentoo/dev
$ chroot /mnt/gentoo/ /bin/bash 
$ source /etc/profile

portageツリーを最新化。

$ emerge --sync
$ emerge --ask --update --deep --newuse @world

ローケールを設定します。

$ echo "Asia/Tokyo" > /etc/timezone
$  emerge --config sys-libs/timezone-data


Configuring pkg...

 * Updating /etc/localtime with /usr/share/zoneinfo/Asia/Tokyo

$ vi /etc/locale.gen
ja_JP.UTF-8 UTF-8

$ locale-gen 
 * Generating 3 locales (this might take a while) with 1 jobs
 *  (1/3) Generating en_US.ISO-8859-1 ...                                                                                                    [ ok ]
 *  (2/3) Generating en_US.UTF-8 ...                                                                                                         [ ok ]
 *  (3/3) Generating ja_JP.UTF-8 ...                                                                                                         [ ok ]
 * Generation complete

$ eselect locale list
  [1]   C
  [2]   en_US
  [3]   en_US.iso88591
  [4]   en_US.utf8 *
  [5]   ja_JP.utf8
  [6]   POSIX
  [ ]   (free form)

$ eselect locale set 5
Setting LANG to ja_JP.utf8 ...
Run ". /etc/profile" to update the variable in your shell.
$ env-update && source /etc/profile
>>> Regenerating /etc/ld.so.cache...

/etc/fstabを編集します。

LABEL=cloudimg-rootfs / ext4 defaults 0 0
LABEL=swap            none swap sw    0 0

/etc/conf.d/netを編集します。

config_eth0="dhcp"

ネットワークを設定します。

$ cd /etc/init.d/
$ ln -s net.lo net.eth0
$ rc-update add net.eth0 default

Grubを設定します。

$ grub-install /dev/xvdb
Installing for i386-pc platform.
Installation finished. No error reported.

$ grub-mkconfig -o /boot/grub/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/kernel-genkernel-x86_64-4.4.26-gentoo-openstack
Found initrd image: /boot/initramfs-genkernel-x86_64-4.4.26-gentoo-openstack
done

/mnt/gentoo/etc/cloud/cloud.cfgに下記を追記

datasource_list: [ Ec2, None ]

SnapshotからGentooインスタンスを立ち上げる


ここまで来たら、作るためにsnapshotを取ります。
作ったSnapshotからAMIを作ってインスタンスを起動するTerraformの設定は下記になります。

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

    ebs_block_device {
        device_name = "/dev/sda1"
        snapshot_id = "snap-1c6e4993"
        volume_size = 10
    }
}

resource "aws_instance" "gside-gentoo" {
    ami                         = "${aws_ami.gentoo-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-gentoo"
    }
}

起動後はgentooユーザーでsshログインできます。

まとめ


CloudフレンドリーなStage4ファイルが有るおかげで、色々楽ちんでした。
中身は下記が詳しいです。

https://mthode.org/posts/2016/Jan/stage4-tarballs-minimal-and-cloud/

stage4の中身についてもここからたどれます。


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

まとめ


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

Ansibleを使ってみる


仕事では利用しているAnsible。
プライベートで使っているサーバーも、構成管理することにしました。
まずは初期構築の部分をまとめてみました。

ansibleのインストール


Ansibleを利用するクライアント側にansibleをインストールします。

$ pip install ansible
$ ansible --version
ansible 2.1.2.0

手元ではbotoが入ってなかったので、インストールしました。

$ pip install boto

Dynamic Inventoryのインストール


AWSのインスタンスをAnsibleで管理する場合、
インスタンスのIPではなく、Tag Nameで管理できると便利です。
Terminateして立ち上げ直した場合などはIPが変わりますし、
冗長構成の場合は複数台に対して同じ作業がしやすくなります。

そこで、Dynamic Inventoryという仕組みを使います。

ec2.pyとec2.iniをダウンロードします。
https://raw.githubusercontent.com/ansible/ansible/devel/contrib/inventory/ec2.py
https://raw.githubusercontent.com/ansible/ansible/devel/contrib/inventory/ec2.ini

動作確認です。

$ export AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXX
$ export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXXXXX
$ export AWS_DEFAULT_REGION=ap-noartheast-1
$ ./ec2.py --list

SSHの設定を書くために、同じディレクトリにansible.cfgを設置します。
sshの設定ファイルを読む設定と、Persistの設定を記載しています。

[ssh_connection]c
ontrol_path = %(directory)s/%%h-%%r
ssh_args = -o ControlPersist=15m -F ssh_config -q
scp_if_ssh=True

SSH接続する際の設定をssh_configに記載します。
接続ユーザーと鍵の設定をしています。

Host *
  User ec2-user
  IdentityFile /aws.pem

動作確認


ansibleコマンドでuptimeを打ってみます。

ansible -i ec2.py tag_Name_gside -m command -a "uptime"
192.0.2.0 | SUCCESS | rc=0 >>
 12:13:54 up 13 days, 14:16,  1 user,  load average: 0.04, 0.03, 0.00

まとめ


そんなにハマるところはなかったですが、繋がらないなとハマったら、
sshの接続を疑うとこからはじめて見ましょう。

ssh -vv -F ssh_config

鍵の場所が正しくないとか、大体のミスは発見できます。

S3のEtagの値はMD5と同じ?

aws 

MD5でファイルが同じかどうかを判定することがあります。
S3ではETAGにMD5値が格納されているという事になっていますが、
結論から言うと、Multipart Updateされた場合と、そうでない場合で異なります。

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


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

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

Bucketにコピーします。

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

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

 $ 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はというと

$ md5sum ~/test9M
b82b4ab87e44976024abc14a1670dac

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

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


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

$ 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コマンドを使います。

$ 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のヘルスチェックを作成します。

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のモデルに合わず未サポートだそうです。

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

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プロフェッショナルにも挑戦していこうと思います。



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>