AWS

AWS 認定 DevOpsエンジニア プロフェッショナルに合格した

AWS 認定 DevOps エンジニア – プロフェッショナル に合格しました! これでAWS認定5冠達成です!

AWSの経験値

ここ3年間くらいはAWSでインフラ運用・構築したり、アプリケーション基盤作ったり。 TerraformとAnsibleで環境作ることが多いけど、試験範囲であるElastic BeanstalkやOpsWorksはほとんど使ったことがなく。 CloudFrontは少々使ったことがある程ででした。

勉強方法

これまでAWSの試験対策はもっぱら Linux Academy っていうオンラインの対策コースをやってきたのですが、 今回はA CLOUD GURUに浮気しました。

A CLOUD GURUは動画による講義とクイズにより構成されています。Linux Academyと違ってハンズオンがなかったのが残念な点です。 動画のクオリティはいいんですけどね。 Linux Academy 同様、英語なんで辛い部分もありますが、スライドと見ながら聞けば、何とかついていけるレベルです。

また、上司がこの試験の推奨セミナー「DevOps Engineering on AWS」を受講させてくれたのですが、 これは試験対策という意味合いは薄かったです。 試験では出ないCode CommitやCode CompleteなどのCode 5兄弟の話にだいぶ時間が割かれていたのが要因の一つですが、 AWSでのDevOpsを学ぶ上ではCode 5兄弟の話は欠かすことのできないものであると感じれたので、トータルでは無駄ではありません。 デプロイ戦略などの話も、良い復習になりました。

勉強期間

期間としては4ヶ月ほど。すごくダラダラと勉強してました。 勉強時間はちゃんと測ってないけど、60時間くらいかな。

内訳は

  • A CLOUD GURU 15H
  • 各サービスを触ってみる 10H
  • AWSのドキュメントを読む 10H
  • セミナー受講+復習 25H

試験を終わって振り返ると、業務でIAMのクロスアカウントを設定したり、 Terraformで環境を構築してきた経験が非常に効いたなと感じました。 勉強ではAWS固有のテクノロジーや用語を抑えて行きました。 例えばCloudFormationのWaitHandlerとかは勉強しとかないとですね。

模擬試験

1ヶ月前にうけた模試は、40%で不合格。 トピックレベルスコアリングの"Security, Governance, and Validation"なんて0%。 が、この模擬試験をしっかり復習したのは、合格のポイントだったと今では思います。 サンプル問題も解いておいて損はないです。 復習の甲斐あってか、本試験では"Security, Governance, and Validation"のスコア100%まで行きました。

最後に

実は一度は不合格をくらい、半額のバウチャーチケットがあったとはいえ16000円がパー。 非常に痛かった。。。。 2度目の受験では結局71%で合格しました。

セミナーでも話があったのですが、はDevOpsは文化なので、ツールだけでは実践できない面が多々あります。 先日読んだ、「The DevOps 逆転だ!究極の継続的デリバリー」の話なんてまさにそうでした。 どういう文化を作っていくかということを考えるときに、どういうツールがあるかを知っていると実現性に現実味が増します。 とはいえ、文化を作っていくのは試験に合格するなんかより相当難しいですね。

S3をマウントするgoofysを試してみた

S3をEC2からマウントするgoofysを試してみた。 昔s3fsを試したことがあるんだけど、パフォーマンスが問題になったりしたことがありました。 巷では爆速と噂のgoofysですが、とりあえずパフォーマンスは置いておいて、できないことが何かを見ておきました。

何ができないのか

公式にもPOSIXは二の次ということで、できないことを書いてくれています。 group,modeとかは固定,simlinkは動かないそうです。 後、atime,mtime,ctimeが全部同じになります。

インストール

とはいえ使い心地を見ときたかったので、インストールして見ました。 ansibleで環境を作って見ました。 fuseとgoが必要です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
---
- hosts: tag_Name_gside_goofys
  remote_user: gentoo
  become: true
  tasks:
    - name: install sys-fs/fuse
      portage: >
        package=sys-fs/fuse
        state=present        
    - name: install dev-lang/go
      portage: >
        package=dev-lang/go
        state=present        
    - name: goofys Download
      get_url: url="https://github.com/kahing/goofys/releases/download/v0.0.10/goofys" sha256sum="78baba6f9c3d8cb06a55a872f0380bc8b37af649a0a7d6961d0789a3bdcd62d4" dest="/usr/local/bin" mode="744"

実はmountの設定も書いていたのですが、IAM RoleでEC2に権限を与えて動作させようとした場合、fstabの設定ではマウントしてくれませんでした。 Credentialを置きたくない・置けないポリシーの場合はネックになりそうですね。

検証

IAM Role + fstabは動作しなかったので、コマンドでマウントします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ goofys gside-goofys /mnt/s3/

$ df -h
ファイルシス   サイズ  使用  残り 使用% マウント位置
udev              10M     0   10M    0% /dev
/dev/xvda2       8.6G  2.3G  5.9G   28% /
tmpfs             49M  240K   49M    1% /run
shm              242M     0  242M    0% /dev/shm
cgroup_root       10M     0   10M    0% /sys/fs/cgroup
gside-goofys     1.0P     0  1.0P    0% /mnt/s3

ファイルを作ってみました。

1
2
3
$ touch /mnt/s3/hoge
$ ls -la /mnt/s3/hoge
-rw-r--r-- 1 root root 0  2月 19 21:09 /mnt/s3/hoge

ヘルプにもありますが、fileのモードは644,uid,gidは0がデフォルトで固定です。 これらの固定値はオプションで違う値に変更は可能ですが、固定値であることは変わりません。

1
2
$ ln -sf hige /mnt/s3/foo
ln: シンボリックリンク '/mnt/s3/foo' の作成に失敗しました: 関数は実装されていません

シンボリックリンクは作れません。

まとめ

この割り切りが受け入れれるかというところでしょうね。 それでも爆速という点を重視して、制限を受け入れた上での使い道はいくらでもあると思います。 が、IAM Role+fstabの部分は対応を切望したいところです。

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 の情報は消えないので、復旧することができます。

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

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