AWS EC2 でオレオレクラウドOSのイメージを作る手順 (AWS-CLI対応)

本稿は，http://www.monaka.org/blog/2014/02/04/how-to-build-ebs-image/ を要約したものです．

# まくら

AWS EC2 は，プラットフォームとして Xen を採用しているので，Xen の mini-os を Amazon EC2 で動作させることができる．
これは，オレオレOSをクラウドOSとして運用するという，俺得的満足感が得られる，ということを意味する．

Amazon が提供していないカーネルを独自に EC2 で動作させるためには，どうやら EBS ボリュームを作らねばならないらしい．
私は，AWS の単なるユーザで，細かいところはあまり詳しくない．
よって，EBS ボリューム以外での起動方法もあるのかもしれないが…．

手順は本家ヘルプページに割と細かく説明されている．
解説ブログも，ググれば山盛り．
さすがは，みんな大好きAWS．

だがしかし，最近になって，AWS は，管理ツールを AWS-CLI というものに統合しようとしている一方，本家ヘルプページは，AWS-CLI への対応が十分にできていない．

そこで，本稿では，AWS-CLI で mini-os をブートさせるための手順を記す．

# 作業

## 概要

独自のカーネルをEC2上で動作させるためのイメージ(以下，オレオレイメージ)は，EBS のスナップショットから作るようになっている．
Xen ではおなじみの PV-GRUB が，オレオレイメージ中にある boot/grub/menu.lst を読み，
kernel (本稿の場合は mini-os)をロードしブートする．
手元環境でEBSを作ってアップロードすることもできるのかもしれないが(知らない)，ここでは EC2 上で t1.micro を立ち上げて作業する．
一連の作業時間は，1時間もかからない．t1.micro なら10円にも満たないような額だろう．

本稿では，ビルドは手元で行うことを想定している．ビルド環境さえもEC2上に立てるということも，もちろんできる．
その際の作業の読み替え箇所は，いちいち言及するまでも無いだろう．

## 手順0: ~/.aws/config

こんな感じ．

```
[default]
aws_access_key_id=ないしょ
aws_secret_access_key=ないしょ
region=ap-northeast-1
output=text
```

region が違うと，下記例示の image-id やらなにやら変更が要るかもしれない．

## 手順1: EBSボリュームへのアクセスを行う EC2 インスタンスの生成

EC2のインスタンスを立ち上げる．

```shell-session
$ aws ec2 run-instances --image-id ami-dcfa4edd --instance-type t1.micro --security-group-ids quick-start-1 --key-name monaka
```

--security-groups-ids や --key-name は，ご自分の環境に合わせて．
--image-id も，好みの環境があるなら，それで．
でも，本稿の例だと複雑なことはしないので，amiの選択に凝るのは時間の無駄かも．

結果はこんな感じ．

```
578606849602	r-351e1831
GROUPS	sg-e242dbe3	quick-start-1
INSTANCES	0	i386	None	False	xen	ami-dcfa4edd	i-a3bec9a4	t1.micro	aki-ec5df7ed	monaka	2014-02-01T11:04:33.000Z	None	None	/dev/sda1	ebs	None	paravirtual
MONITORING	disabled
PLACEMENT	ap-northeast-1b	None	default
SECURITYGROUPS	sg-e242dbe3	quick-start-1
STATE	0	pending
STATEREASON	pending	pending
```

## 手順2: 諸々のファイルを入れるEBSボリュームの生成

```shell-session
$ aws ec2 create-volume --size 1 --availability-zone ap-northeast-1b
```
mini-os のサイズは1MB以下なのだが，EBSボリュームの最低サイズは1GB．無駄だがやむなし．

結果はこんな感じ．

```
ap-northeast-1b	2014-02-01T10:46:19.012Z	1	None	creating	vol-1cbb4b16	standard
```

## 手順3: EBSボリュームのEC2インスタンスへのアタッチ

```shell-session
$ aws ec2 attach-volume --volume-id vol-1cbb4b16 --instance-id i-a3bec9a4 --device /dev/sdh1
```
vol-1cbb4b16 は，手順2の結果で得られたもの．i-a3bec9a4 は，手順1の結果で得られたもの．

結果はこんな感じ．

```
2014-02-01T11:05:25.613Z	/dev/sdh1	i-a3bec9a4	attaching	vol-1cbb4b16
```

## 手順4: 作業用 EC2 インスタンスへの ssh ログイン

手順1で，インスタンスを立ち上げた直後は，サーバのFQDNが判らない．
そろそろインスタンスのプロビジョニングも終わっているはずなので，確認．

```shell-session
$ aws ec2 describe-instances --instance-ids i-a3bec9a4
```

結果はこんな感じ

```
RESERVATIONS	578606849602	r-351e1831
GROUPS	sg-e242dbe3	quick-start-1
INSTANCES	0	i386	None	False	xen	ami-dcfa4edd	i-a3bec9a4	t1.micro	aki-ec5df7ed	monaka	2014-02-01T11:04:33.000Z	ip-10-132-154-11.ap-northeast-1.compute.internal	10.132.154.11	ec2-54-199-18-76.ap-northeast-1.compute.amazonaws.com	54.199.18.76	/dev/sda1	ebs	None	paravirtual
BLOCKDEVICEMAPPINGS	/dev/sda1
EBS	2014-02-01T11:04:36.000Z	True	attached	vol-69bc4c63
MONITORING	disabled
PLACEMENT	ap-northeast-1b	None	default
SECURITYGROUPS	sg-e242dbe3	quick-start-1
STATE	16	running
```
compute.amazonaws.com で終わっているのが，外向きのFQDN．
今回の場合は，ec2-54-199-18-76.ap-northeast-1.compute.amazonaws.com
なので，おもむろに ssh．

Amazon Linux の場合は，ログインユーザは ec2-user となる．

```shell-session
$ ssh ec2-user@ec2-54-199-18-76.ap-northeast-1.compute.amazonaws.com
```

サーバの公開鍵を受け入れるかどうかなど聞かれる．
結果は，こんな感じ．

```
The authenticity of host 'ec2-54-199-18-76.ap-northeast-1.compute.amazonaws.com (54.199.18.76)' can't be established.
RSA key fingerprint is e8:10:70:59:ce:4b:7b:59:97:92:35:d8:35:a7:3a:92.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'ec2-54-199-18-76.ap-northeast-1.compute.amazonaws.com,54.199.18.76' (RSA) to the list of known hosts.

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

See /usr/share/doc/system-release/ for latest release notes.
No packages needed for security; 170 packages available
Amazon Linux version 2013.09 is available.
[ec2-user@ip-10-132-154-11 ~]$ 
```

## 手順5: EBSボリュームのマウント

手順3では，EBSボリュームはアタッチしかしていない．
ここでファイルシステムを作成して，マウントする．

ファイルシステムの生成は，こんな感じ．

```shell-session
[ec2-user@ip-10-132-154-11 ~]$ sudo mkfs.ext2 /dev/sdh1
```

結果は，こんな感じ．

```
mke2fs 1.41.12 (17-May-2010)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
65536 inodes, 262144 blocks
13107 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=268435456
8 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks: 
	32768, 98304, 163840, 229376

Writing inode tables: done                            
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 24 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.
```

ファイルシステムはできたので，早速マウント．

```shell-session
[ec2-user@ip-10-132-154-11 ~]$ sudo mount /dev/sdh1 /mnt
```

特にメッセージの出力など無く，コマンドプロンプトに戻ってくる．

## 手順6: menu.lst の生成

PV-GRUB が読む menu.lst を，EBSボリューム(の中にあるファイルシステム)に置く．
エディタ使ってもいいけれど，この程度なら猫で十分．

```shell-session
[root@ip-10-132-154-11 ec2-user]# sudo -s
[root@ip-10-132-154-11 ec2-user]# cat > /mnt/boot/grub/menu.lst
default 0

title MiniOS test
        root (hd0)
        kernel /mini-os
[root@ip-10-132-154-11 ec2-user]# exit
```

sudo -s を使ったので，最後には exit で，ec2-user に戻しておいた．

## 手順7: mini-os のコピー

何らかの方法で行う．
ふつうは scp を使うと思う．
そして，EC2 インスタンス上の /mnt/mini-os に配置する．
ここでmenu.lst の記述に引っ張られて，うっかり，/mini-os に置いたりとかしないように．

## 手順8: スナップショットの生成

手順7までで，EC2インスタンスは用済みとなる．
だから，stop-insrance なり terminate-instance なりで落としてもよい．
けれども，最初の動作確認ができるまでは，立ち上げっぱなしのほうがよいかもしれない．
EC2の課金は1時間単位だけれども，1時間以内にn回立ち上げ直すと，n時間分の料金になる．

EC2のインスタンスにアタッチしたままでも，スナップショットは取れる．
そうでないと，スナップショットの意味が無い．

操作は，こんな感じ．

```shell-session
$ aws ec2 create-snapshot --volume-id vol-1cbb4b16
```

```
結果は，こんな感じ．
None	578606849602	None	snap-940d6c7a	2014-02-01T11:24:16.000Z	pending	vol-1cbb4b16	1
```

## 手順9: スナップショットからオレオレイメージの生成

いよいよ佳境．スナップショットからオレオレイメージを生成する．
正直言うと，よく調べがついていないのだけれど，イメージの概要を示すjsonファイルが必要らしい．
短いものなので，これもテキストエディタを持ち出すまでもないはず．

```shell-session
$ cat > blockdevice.json
[
        {"DeviceName":"/dev/xvda","Ebs":{"VolumeType":"standard","DeleteOnTermination":true,"VolumeSize":1,"SnapshotId":"snap-940d6c7a"}}
]
```

VolumeSize は，最初に 1GB で作ったから．SnapshotId は，手順8の出力と合わせる．

そして，イメージの登録を行う．

```shell-session
$ aws ec2 register-image --root-device-name /dev/xvda --name "Mini-os test" --block-device-mappings file://blockdevice.json --architecture x86_64
```

結果は，こんな感じ．
```
ami-ef650eee
```

## 手順10: オレオレイメージの起動

そして感動のフィナーレ．オレオレイメージの起動．

```shell-session
$ aws ec2 run-instances --image-id ami-ef650eee --instance-type t1.micro --security-group-ids quick-start-1 --key-name monaka
```

結果は，こんな感じ

```
578606849602	r-f17d65f5
GROUPS	sg-e242dbe3	quick-start-1
INSTANCES	0	x86_64	None	False	xen	ami-ef650eee	i-b38630b4	t1.micro	monaka	2014-02-01T11:46:28.000Z	None	None	/dev/xvda	ebs	None	paravirtual
MONITORING	disabled
PLACEMENT	ap-northeast-1b	None	default
SECURITYGROUPS	sg-e242dbe3	quick-start-1
STATE	0	pending
STATEREASON	pending	pending
```

これだけだと，本当に立ち上がったのか判らない．

ログの取得は，こんな感じで行う．

```
$ aws ec2 get-console-output --instance-id i-b38630b4
```

i-b38630b4 は，オレオレイメージの run-instance の結果から引っ張ってくる．

mini-os 自身は小さいものの，mini-os の実行環境のプロビジョニングには，そこそこの時間がかかる．
遅い時は5分以上かかるので，気長に待つ．
どうせ1時間までは同じ料金だから．