Blogs

    in  AWS

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

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

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

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

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

    1
    2
    3
    4
    5
    6
    7
    
    resource "aws_s3_bucket" "version-test" {
        bucket = "gside-version-test"
        acl = "private"
        versioning {
            enabled = true
        }
    }
    

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

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

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

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

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    $ 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
            }
        ]
    }
    

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

     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
    31
    32
    33
    
    $ 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を指定してファイルを取得します。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    $ 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 の情報は消えないので、復旧することができます。


    in  AWS

    GentooのAMIを作る

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

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

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

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

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

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    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
    

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

    1
    2
    3
    4
    5
    6
    
    $ 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ファイルを展開します。

    1
    2
    3
    
    $ 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して、

    1
    2
    3
    4
    5
    
    $ 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ツリーを最新化。

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

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

     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
    31
    32
    
    $ 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を編集します。

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

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

    1
    
    config_eth0="dhcp"
    

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

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

    Grubを設定します。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    $ 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に下記を追記

    1
    
    datasource_list: [ Ec2, None ]
    

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

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

     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
    31
    32
    33
    34
    35
    36
    
    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の中身についてもここからたどれます。


    in  AWS, Terraform

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

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

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

     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
    31
    32
    33
    34
    35
    36
    
    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"
        }
    }
    

    in  AWS, Terraform

    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
    

    in  AWS, Terraform

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

    まとめ

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


    in  Ansible

    Ansibleを使ってみる

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

    ansibleのインストール

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

    1
    2
    3
    
    $ pip install ansible
    $ ansible --version
    ansible 2.1.2.0
    

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

    1
    
    $ 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

    動作確認です。

    1
    2
    3
    4
    
    $ 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]
    control_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を打ってみます。

    1
    2
    3
    
    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の接続を疑うとこからはじめて見ましょう。

    1
    
    ssh -vv -F ssh_config
    

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


    in  AWS

    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になるようです。 気をつけましょう。


    in  AWS, Terraform

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


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


    in  AWS, Terraform

    Terraform入門してみた

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

    インストール

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

    構成

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

    実行

    アクセスキーとシークレットキーを環境変数に設定します。

    1
    2
    3
    
    $ export AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXXXXX
    $ export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    $ export AWS_DEFAULT_REGION=ap-northeast-1
    
    1
    
    $ terraform plan
    

    で変更箇所を確認して、

    1
    
    $ terraform apply
    

    で実行します。

    terraform.tfstateの管理

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

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

    1
    2
    3
    4
    5
    
    $ 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する機能もついたということで、ますます利用するシーンが増えそうです。

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

     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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    
    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"
    }