Hank Lin

A new blog

Creating EBS-backed AMIs From Running Instances

| Comments

因為有許多免費的public AMIs, 像是alestic上就有很多好用的Ubuntu AMIs. 所以說不用精通AMI的製作方法, 也能快樂的使用EC2. 不過如果要把EC2這個技能再練一級的話, 自製的AMI是必備的. 2009年底時, AWS推出 可以用EBS-backed AMI. New Amazon EC2 Feature: Boot from Elastic Block Store. 但是之前已經有一堆在run 的instances , 完全享受不到EBS-backed 的好處啊! 這次的課題就是要把目前正在running 的instances, 作成EBS-backed AMI, 方便日後使用.

以前S3-backed AMI, 是存在S3上, launch instances時EC2會去S3把image抓下來再run. 現在EBS-backed AMI則是存在EBS snapshots上. 在功能性上有很大的進步. 首先就是開機的速度比較快, 用EBS-backed AMI 開機時, EBS用那個snapshot 建立root partition, 比從S3 copy 過來還要快. 再來就是S3-backed AMI的root partition最大只能到10GB, EBS-backed AMI可以到1TB. 然後因為是用EBS, 所以root partition上的東西不會在instances死掉的時候就消失了, 這大概是最大的好處. 另外, EBS-backed AMI還支援stop/start instance. 也就是可以先把instances 暫停, 等一下再run, 在stop的期間是不算EC2的錢的. 這麼好康, 當然要轉換咩! 好吧, 但是作AMI的方法真多啊! 有用dd的:

$ dd if=/dev/sda1 of=/dev/sdf

有用ec2-bundle-vol的:

$ ec2-bundle-vol -c $EC2_CERT -k $EC2_PRIVATE_KEY -u $AMAZON_USER_ID -e /vol -d /mnt

有用vmbuilder的, 還有ec2-download-bundlemountec2-unbundle的. 還有rsync的 (我後來用這種):

$ rsync -av / $IMAGE_DIR

方法那麼多, 實在不知道優缺點在哪裡. 我參考了很多人的作法, 使用我覺得比較適合我的, 現在就介紹我的步驟.

先確定有最新的EC2 API tools:

$ ec2-version
1.3-46266 2009-11-30

確定一下要轉換的instance id, 以及它在哪個availability zone, 可以用API tools 的describe instances:

$ ec2-describe-instances

然後用IP去找到instance id和availability zone, 不過這有點不好找, 如果instances多的話可能會看到眼睛抽筋. 所以可以在要轉換的那一台上面看它的metadata:

$ curl http://169.254.169.254/latest/meta-data/instance-id && echo
$ curl http://169.254.169.254/latest/meta-data/placement/availability-zone/ && echo

就可以看到我的instance id 是i-e734e58e, availability zone 是us-east-1a. 再來就是create 一個EBS volume, 然後attached到那一個instance上面. 因為volume不能跨availability zone, 所以一定要和instance 相同. 另外, 如果你的instances不是在預設的region: us-east-1上的話, 記得設定EC2_URL= 環境變數, 或是每次明確的給--region , 或-U 參數, 我先作一個10G的volume:

$ ec2-create-volume -s 10 -z us-east-1a
VOLUME  vol-75dc7c1c    10              us-east-1a      creating        2010-03-29T08:41:58+0000

然後看看create好了沒:

$ ec2-describe-volumes vol-75dc7c1c
VOLUME  vol-75dc7c1c    10              us-east-1a      available       2010-03-29T08:41:58+0000

好了就attach到instance上:

$ ec2-attach-volume vol-75dc7c1c -i i-e734e58e -d /dev/sdf
ATTACHMENT      vol-75dc7c1c    i-e734e58e      /dev/sdf        attaching       2010-03-29T09:04:57+0000

看看attach好了沒:

$ ec2-describe-volumes vol-75dc7c1c
VOLUME  vol-75dc7c1c    10              us-east-1a      in-use  2010-03-29T08:41:58+0000
ATTACHMENT      vol-75dc7c1c    i-e734e58e      /dev/sdf        attached        2010-03-29T09:04:57+0000

OK! 現在連到那一台instance:

$ EBS_DEVICE=/dev/sdf
$ IMAGE_DIR=/mnt/image
$ EBS_MOUNT_POINT=/mnt/ebs
$ mkdir -p $EBS_MOUNT_POINT
$ mkfs.ext3 $EBS_DEVICE
$ mount  $EBS_DEVICE $EBS_MOUNT_POINT
$ mkdir -p $IMAGE_DIR
$ rsync --stats -av --exclude /root/.bash_history --exclude /etc/ssh/ssh_host_* --exclude=/mnt/* --exclude=/proc/* --exclude=/tmp/* / $IMAGE_DIR
$ cd $IMAGE_DIR
$ tar -cSf - -C ./ . | tar xvf - -C $EBS_MOUNT_POINT
$ umount $EBS_MOUNT_POINT

看起來是做了不少事. 其實只是:

  • 把EBS volume mount上來.
  • 把現在的系統作一份image. 在這裡是用rsync, 還有之前提到的多種作法.
  • 把作好的image copy 到EBS volume上. 在這裡是用很花俏的tar, (根據資料來源的說法是image比較小), 也可以用rsync.

現在可以回到EC2 API tools了, 把剛剛那個volume detach掉:

$ ec2-detach-volume vol-75dc7c1c
ATTACHMENT      vol-75dc7c1c    i-e734e58e      /dev/sdf        detaching       2010-03-29T09:04:57+0000

然後對那個volume作snapshot:

$ ec2-create-snapshot vol-75dc7c1c -d "Ubuntu 8.04 20100329"
SNAPSHOT        snap-7856b410   vol-75dc7c1c    pending 2010-03-29T09:30:42+0000                107357113328    10      EBS Ubuntu 8.04

看一下snapshot完成了沒:

$ ec2-describe-snapshots snap-7856b410
SNAPSHOT        snap-7856b410   vol-75dc7c1c    completed       2010-03-29T09:30:42+0000        100%    107357113328    10  EBS Ubuntu 8.04

最後把這個snapshot註冊為AMI:

$ ec2-register -s snap-7856b410 -a i386 -n "ebs-ubuntu-8.04-i386-20100329" -d "EBS Ubuntu 8.04 i386 20100329" -b /dev/sda2=ephemeral0 --root-device-name /dev/sda1
IMAGE   ami-bd50bfd4

好了! 現在來開個instance來看看有沒有OK!

$ ec2-run-instances ami-bd50bfd4 -k mykeypair -g default -z us-east-1a -t m1.small --instance-initiated-shutdown-behavior stop
RESERVATION     r-d0dfe8b8      107357113328    default
INSTANCE        i-33bc3b58      ami-bd50bfd4    ec2-174-129-157-197.compute-1.amazonaws.com     domU-12-31-38-00-AE-05.compute-1.internal       running mykeypair 0               m1.small        2010-03-29T10:03:27+0000    us-east-1a  aki-5f15f636
ari-0915f660            monitoring-disabled     174.129.157.197 10.252.177.239                  ebs
BLOCKDEVICE     /dev/sda1       vol-cba606a2    2010-03-29T10:03:37.000Z

等到instance status 是running 就可以連進去看看了:

$ ec2-describe-instances i-33bc3b58

最後, 本來的volume可以砍掉了:

$ ec2-delete-volume vol-75dc7c1c
VOLUME  vol-75dc7c1c

因為做AMI的方法很多(參考Resources), 也許你用某些方法會做出不能work的AMI, 這時候就得花時間來排除問題, 我也是試了幾次才成功. 有一些地方可以注意一下:

  • service最好都先關掉
  • /etc/fstab 和network interfaces 最好不要亂改, 可能會連不進去
  • 如果有一些symlink, 依據你作image的方式的不同, 可能會造成沒有檔案. 這時候就把symlink消掉, 把檔案copy一份咩.
  • ec2-register的時候, --kernel, --ramdisk 不要亂給. 在Resources裡有一些例子有給這些參數, 害我出現Segmentation fault. kernel module 和ramdisk module現在都是只有Amazon才可以作的. 而且有關kernel module 的相容性、性能的說明文件幾乎沒有, 有的資訊只有依據它的名字得知的版本而已. 所以這個進階功能還是以後有空再來試咩.

Resources