Instance Store-Backed なインスタンスから EBS-Backed 向けのAMIをつくる

2016.04.21

こんにちは、ももんが大好きの小山です。きょうは、Instance Store-Backed で起動しているインスタンスから Amazon EBS-Backed なAMIを作成する手順についてご紹介しようと思います。

前提

EC2のインスタンスを起動するとき、2つの方法があります。ハイパーバイザーに内蔵 (*イメージです) されたストレージにAMIの内容をコピーして起動する方法と、ハイパーバイザーとは別に設置されたストレージにAMIの内容をコピーして起動する方法です。前者の方法で起動するインスタンスを Instance Store-Backed インスタンスと呼び、後者の方法で起動するインスタンスを EBS-Backed インスタンスと呼びます。

Instance Store-Backed インスタンスでは、起動ディスクとしてインスタンスストア (Ephemeral Storage) を使います。インスタンスストアの中身は、インスタンスの停止と同時に削除されます。なぜなら、次に起動するとき同じハイパーバイザー (とその内蔵ストレージ) に当たるとは限らないからです。ですから、 Instance Store-Backed なインスタンスでは停止ターミネートがイコールです。

EBS-Backed なインスタンスでは、インスタンスの停止でストレージの内容が失われることはありません。どのハイパーバイザーに当たったとしても、EBSが置かれるのはハイパーバイザーの外だからです。インスタンスストアはハイパーバイザーの内蔵ストレージ、EBSはネットワークストレージのようなものだと考えればわかりやすいのではないでしょうか?

くどいようですが、Instance Store-Backed なインスタンスを停止しておいて後で起動することはできません。これは、ときどきAWS側でスケジュールされるメンテナンスが理由であっても同じことです。もう長いこと動き続けている Instance Store-Backed インスタンスにメンテナンスがスケジュールされて ぎょっ とした方、いらっしゃるんじゃないでしょうか?「そのインスタンス、どうやって設定したか覚えてないんだけど...」

消えて困るものをインスタンスストアに置く使い方を擁護するつもりはありませんが、もうメンテナンスが迫っているのに理想論ばかり並べていたのでは始まりません。そういうことで、とりあえずメンテナンスを乗り越えてアーキテクチャを見直すまでのつなぎとして使える方法をご紹介します。Amazon Linux AMI 限定です。

以下の手順は正式にサポートされるかどうかも定かでなく、作成したAMIから起動するインスタンスも何かの拍子に起動しなくなっておかしくないと考えられるものです。最悪のケースでは起動中の Instance Store-Backed インスタンスがハングしてインスタンスストアの中身を失うことも十分考えられますから、どうかよく考えてから実行してください。また、作業中は元になるインスタンス (Instance Store-Backed) の負荷が非常に高くなります。イメージを暗号化するステップが入るためですが、これを迂回する方法は残念ながら見つけられませんでした。通して1時間もかからない (m1.small、イメージサイズは10GB前後) はずですから、日の出前に起きるなりして乗り越えてください。

準備

元になるインスタンス (Instance Store-Backed) でアップデートを実行します。今回の検証では 東京リージョンのamzn-ami-pv-2013.03.0.x86_64.manifest.xml (ami-153fbf14)を使いましたが、アップデートなしで作成したAMIから起動したインスタンスはカーネルパニックを起こしていました。そういうものなんです。

アップデートできたら、EC2のマネジメントコンソールで新しいボリュームを2つ作成します。1つめは一時ファイル置き場兼バックアップとして使い、2つめは新しいAMIの元になるボリュームとして使います。1つ目のボリュームは gp2 である程度大きく (IOPSを稼いで作業時間を短縮するため)、2つ目は元になるインスタンス (インスタンスストア) の中身が丸々収まる大きさにします。インスタンスストアで使用中の領域が10GBなら1つ目のボリュームは100GB、2つ目は20GBくらい見ておくとよいでしょう。以降では、1つ目をボリューム1、2つ目をボリューム2と呼ぶことにします。ボリュームが作成できたら、それぞれ元になるインスタンス (Instance Store-Backed) へアタッチしましょう

Bildschirmfoto 2016-04-20 um 20.46.29

Bildschirmfoto 2016-04-20 um 20.43.21

ステップ1: コード証明書をつくる

いきなりなんの話をしているのかと思われるかもしれませんが、今回の手順では「実行中の Instance Store-Backed インスタンスから作成したAMIをS3に置く」ための公式ツールを流用して起動ディスクをイメージ化しています。こうすることによって、ただでさえ無茶である「実行中のインスタンスから起動ディスクのイメージを作成する」という目論みをごまかしているわけです。AMIをつくる時にはコード署名が必要になりますから、そのツールを使うにはコード証明書が必要なわけです。とにかく元になるインスタンスにログインしてコード証明書をつくります。

[ec2-user ~]$ openssl genrsa 2048 > /temp/cert/private-key.pem
Generating RSA private key, 2048 bit long modulus
......+++
....+++
e is 65537 (0x10001)

[ec2-user ~]$ chmod 400 /temp/cert/private-key.pem
[ec2-user ~]$ openssl req -new -x509 -nodes -sha256 -days 365 -key private-key.pem -outform PEM > certificate.pem
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:
Email Address []:

[ec2-user ~]$ ls /tmp/cert -l
total 8
-rw-rw-r-- 1 ec2-user ec2-user 1212 20 avr 14:52 certificate.pem
-r-------- 1 ec2-user ec2-user 1675 20 avr 14:51 private-key.pem

できました! 次に進みましょう。

ステップ2: イメージの作成

元になるインスタンスで、起動ディスクのイメージを作成してボリュームに保存します。まずはボリューム1をフォーマットしてマウントしましょう。以下では /dev/xvdf がアタッチしたボリューム1ですが、そうじゃないことの方が多いと思いますからかならずご自身の目で確かめてください!

[ec2-user ~]$ lsblk
NAME  MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
xvdf  202:80   0   100G  0 disk
xvdg  202:96   0    20G  0 disk
xvda1 202:1    0     8G  0 disk /
xvda2 202:2    0 149.1G  0 disk /media/ephemeral0
xvda3 202:3    0   896M  0 disk [SWAP]

[ec2-user ~]$ sudo mkfs -t ext4 /dev/xvdf
mke2fs 1.42.3 (14-May-2012)
Étiquette de système de fichiers=
Type de système d'exploitation : Linux
Taille de bloc=4096 (log=2)
Taille de fragment=4096 (log=2)
« Stride » = 0 blocs, « Stripe width » = 0 blocs
6553600 i-noeuds, 26214400 blocs
1310720 blocs (5.00%) réservés pour le super utilisateur
Premier bloc de données=0
Nombre maximum de blocs du système de fichiers=4294967296
800 groupes de blocs
32768 blocs par groupe, 32768 fragments par groupe
8192 i-noeuds par groupe
Superblocs de secours stockés sur les blocs :
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000, 7962624, 11239424, 20480000, 23887872

Allocation des tables de groupe : complété
Écriture des tables d'i-noeuds : complété
Création du journal (32768 blocs) : complété
Écriture des superblocs et de l'information de comptabilité du système de
fichiers : complété

[ec2-user ~]$ sudo mkdir /mnt/ebs
[ec2-user ~]$ sudo mount /dev/xvdf /mnt/ebs

ボリューム1の用意ができましたので、以下の要領でボリューム1に起動ディスクのイメージを作成しましょう。

[ec2-user ~]$ sudo -E su
[root ec2-user]# $EC2_AMITOOL_HOME/bin/ec2-bundle-vol -k /tmp/cert/private-key.pem -c /tmp/cert/certificate.pem -u 123456789012 -r x86_64 -e /tmp/cert -d /mnt/ebs
Copying / into the image file /mnt/ebs/image...
Excluding:
/proc/sys/fs/binfmt_misc
/dev/pts
/mnt/ebs
/proc
/sys
/
/dev
/media
/mnt
/proc
/sys
/tmp/cert
/mnt/ebs/image
/mnt/img-mnt
1+0 enregistrements lus
1+0 enregistrements écrits
1048576 octets (1.0 MB) copiés, 0.00223099 s, 470 MB/s
mke2fs 1.42.3 (14-May-2012)
Bundling image file...

Splitting /mnt/ebs/image.tar.gz.enc...
Created image.part.56
Generating digests for each part...
Digests generated.
Unable to read instance meta-data for ancestor-ami-ids
Unable to read instance meta-data for ramdisk-id
Unable to read instance meta-data for product-codes
Creating bundle manifest...
ec2-bundle-vol complete.

[root ec2-user]# ls /mnt/ebs -l
total 2375000
-rw-r--r-- 1 root root 10737418240 20 avr 17:43 image
-rw-r--r-- 1 root root       10681 20 avr 17:51 image.manifest.xml
-rw-r--r-- 1 root root    10485760 20 avr 17:50 image.part.00
...
-rw-r--r-- 1 root root     8897872 20 avr 17:50 image.part.56
drwx------ 2 root root       16384 20 avr 17:19 lost+found

[root ec2-user]# exit
[ec2-user ~]$

でかいファイルができていますね! これがお目当てのイメージです。

ステップ3: 書き出し

できあがったイメージをボリューム2へ書き出します。

[ec2-user ~]$ lsblk
NAME  MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
xvdf  202:80   0   100G  0 disk /mnt/ebs
xvdg  202:96   0    20G  0 disk
xvda1 202:1    0     8G  0 disk /
xvda2 202:2    0 149.1G  0 disk /media/ephemeral0
xvda3 202:3    0   896M  0 disk [SWAP]

[ec2-user ~]$ sudo dd if=/mnt/ebs/image of=/dev/xvdg bs=1M
10240+0 enregistrements lus
10240+0 enregistrements écrits
10737418240 octets (11 GB) copiés, 286.77 s, 37.4 MB/s

[ec2-user ~]$ sudo partprobe /dev/sdb
[ec2-user ~]$ sudo umount /dev/ebs

これで起動可能なボリュームができているはずですが、ドキュメントには /etc/fstab にあるインスタンスストアのエントリを削除するように記載がありました。ここでは、強調表示にした最後の2行を消しました。

[ec2-user ~]$ sudo mkdir /mnt/ebs
[ec2-user ~]$ sudo mount /dev/xvdg /mnt/ebs
[ec2-user ~]$ sudo nano /mnt/ebs/etc/fstab
#
LABEL=/     /           ext4    defaults,noatime  1   1
tmpfs       /dev/shm    tmpfs   defaults        0   0
devpts      /dev/pts    devpts  gid=5,mode=620  0   0
sysfs       /sys        sysfs   defaults        0   0
proc        /proc	proc    defaults        0   0
/dev/sda2	/media/ephemeral0	auto    defaults,comment=cloudconfig    0	2
/dev/sda3	none    swap    sw,comment=cloudconfig  0	0

[ec2-user ~]$ sudo unmount /ebs

アンマウントして完成です!

ステップ5: EBS-Backed Instance 用のAMIの作成

ボリューム2からスナップショットを撮って...

Bildschirmfoto 2016-04-20 um 20.31.16

AMIにします。

Bildschirmfoto 2016-04-20 um 20.29.45

もちろん起動するインスタンスは EBS-Backed

Bildschirmfoto 2016-04-20 um 20.34.26

やりました! Bildschirmfoto 2016-04-20 um 20.50.40

おわりに

いかがでしたか? ご紹介した手順はかなり面倒な上、これで起動したインスタンスはちょっと不安ですよね... もう少し真っ当な方法をご存知の方はぜひ教えてください!

Instance Store-Backed Linux AMI の作成 - Amazon Elastic Compute Cloud http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/creating-an-ami-instance-store.html