AMI をゼロから作る このエントリをはてなブックマークに登録

2009年05月22日

もりもりもりもり / , , , ,

一ヶ月ぶりになってしまいました。もりやまです。

今回は Amazon EC2 で使う AMI の作り方です。

以前から EC2 上へのアプリのインストールや設定をしたことはあったんですが、今回始めて自分でインスタンスを作るところからやる機会ができたので、せっかくなので自分で AMI を作るところからやってみました。

基本的には公式のドキュメント通りですが、いくつかハマった点もあったので、最初から説明していきます。

インストールする OS は CentOS 5.3 ですが、yum が使えれば他のディストリビューションでも同じ手順でできると思います。

作業はすべて root で行います。

事前に ec2-ami-tools のインストールと、AMI を公開するアカウントの X.509 証明書と秘密鍵を用意しておいてください。アクセスキーとシークレットアクセスキーも使用します。

イメージ用の loopback ファイルを作成

# dd if=/dev/zero of=centos-5.3.img bs=1G count=10

このファイルがそのままインスタンスの /dev/sda1 になります。

ec2-bundle-image でアップロード用のファイルを作成する時に、イメージの空き領域はほとんど圧縮されてしまうので、必要な領域がそれほど多くなくても大きめに作っておいて問題ありません。

ただし、ami-bundle-image の最大サイズが 10GB なので、それ以上のサイズで作ってしまってもアップロードできません。

(ami-bundle-image のソースを確認したら、MAX_SIZE = 10 * 1024 * 1024 * 1024 となっている箇所があったので、そこ書き換えればもっと大きなイメージは作れそうですが、アップロードして起動できるかまではわかりません)

それと、イメージの作成をやり直す際には、この loopback ファイルの作成からやり直した方がいいようです。一度使ったファイルを mke2fs でフォーマットし直しただけだと、ami-bundle-image であまり圧縮できませんでした(最小で 330MB くらいまで圧縮できていたものが、同じ手順でインストールしているにもかかわらず 1.5GB くらいにしかならない)

loopback ファイルにファイルシステムを作成してマウント

# mke2fs -F -j centos-5.3.img
# mount -o loop centos-5.3.img ami-root
# cd ami-root

ここでは ext3 を使用していますが、他のファイルシステム(Reiser4 / XFS / JFS 等)で作ったものが起動できるかどうかはわかりません。EBS は ext3 以外でも使えるようなので、kernel としては他のファイルシステムもサポートしているようです。

インストールに必要なファイルを作成

# mkdir etc proc dev
# MAKEDEV -d dev -x console
# MAKEDEV -d dev -x null
# MAKEDEV -d dev -x zero
# cat > etc/fstab << EOS
/dev/sda1  /         ext3    defaults        1 1
none       /dev/pts  devpts  gid=5,mode=620  0 0
none       /dev/shm  tmpfs   defaults        0 0
none       /proc     proc    defaults        0 0
none       /sys      sysfs   defaults        0 0
EOS
# mount -t proc none proc

OS をインストール

インストール用の yum.conf を用意します。

[main]
cachedir=/var/cache/yum
keepcache=0
debuglevel=2
logfile=/var/log/yum.log
distroverpkg=redhat-release
tolerant=1
exactarch=1
obsoletes=1
gpgcheck=0

# Note: yum-RHN-plugin doesn't honor this.
metadata_expire=1h

installonly_limit = 5

[base]
name=CentOS-5 - Base
mirrorlist=http://mirrorlist.centos.org/?release=5&arch=i386&repo=os

[updates]
name=CentOS-5 - Updates
mirrorlist=http://mirrorlist.centos.org/?release=5&arch=i386&repo=updates

このファイルはイメージに含める必要はないので、イメージの外に yum-cenos-i386-xen.conf として置いておきます。x86_64 の場合は i386 のところを置き換えてください。

# yum -c ../yum-centos-i386-xen.conf --installroot=$PWD -y groupinstall Core
# chroot . pwconv
# chroot . grpconv
# chroot . chkconfig --add sshd
# chroot . chkconfig --level 345 sshd on
# yum -c ../yum-centos-i386-xen.conf --installroot=$PWD -y install \
        ruby ruby-libs ruby-irb ruby-rdoc ruby-ri ruby-devel \
        curl libidn wget which rsync

最低限のファイルのみインストールするため Core グループを選択していますが、インスタンスの起動に必要なファイルが含まれていないので、ruby や curl 等を追加でインストールします。

pwconv と grpconv でシャドウパスワードを使う設定と、ssh の自動起動を設定します。

何度もやりなおしていてたまに遭遇したんですが、i386 版をインストールするときだけ、pam パッケージの postscript がエラーになる場合があって、それに気付かずにインスタンス起動してみたら ssh ログインできない、ということがありました。

作業していたホスト OS が x86_64 版だからなのかもしれませんが、インストールログをよく確認して、エラーが出ていたら手動で postscript と同じ内容を実行するようにしてみてください。

不要なパッケージの削除

# rpm -e --root $PWD \
        grub redhat-logos audit-libs-python checkpolicy dhcpv6-client \
        kudzu libselinux-utils libsemanage policycoreutils selinux-policy \
        selinux-policy-targeted setools setserial tcl udftools

ここは必須ではないんですが、個人的には不要なパッケージは極力削りたいので、これだけのパッケージを削っています。

上記に加えて、i386 の場合は

# rpm -e --root $PWD gnu-efi nash mkinitrd

を、x86_64 の場合は

# rpm -e --root $PWD nash mkinitrd.i386 mkinitrd.x86_64

を削っています。

ネットワークの設定

# cat > etc/sysconfig/network-scripts/ifcfg-eth0 << EOS
DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
TYPE=Ethernet
USERCTL=yes
PEERDNS=yes
IPV6INIT=no
EOS

# cat > etc/sysconfig/network << EOS
NETWORKING=yes
EOS

# cat > etc/hosts << EOS
127.0.0.1       localhost.localdomain localhost
EOS

公式のマニュアル通りですね。/etc/hosts だけ追加してあります。

fstab に sda1 以外のパーティションの追加

アーキテクチャによって設定が変わります。

i386 の場合は

# cat >> etc/fstab << EOS
/dev/sda2  /mnt      ext3    defaults        0 0
/dev/sda3  swap      swap    defaults        0 0
EOS

x86_64 の場合は

# cat >> etc/fstab << EOS
/dev/sdb   /mnt      ext3    defaults        0 0
EOS

になります。x86_64 の場合はインスタンスが xlarge の場合には sdc 〜 sde も使えるようですが、ここでは最小限にしておきます。

詳細はこちらの Instance Storage の項目を参照してください。

rc.local に EC2 用のコードを追加

# cat >> etc/rc.local << EOS

# Update the Amazon EC2 AMI creation tools
echo " + Updating ec2-ami-tools"
wget http://s3.amazonaws.com/ec2-downloads/ec2-ami-tools.noarch.rpm && \
rpm -Uvh ec2-ami-tools.noarch.rpm && \
echo " + Updated ec2-ami-tools"
rm -f ec2-ami-tools.noarch.rpm

if [ -f "/root/firstrun" ] ; then
  dd if=/dev/urandom count=50|md5sum|passwd --stdin root
  rm -f /root/firstrun
else
  echo "* Firstrun *" && touch /root/firstrun
fi

if [ ! -d /root/.ssh ] ; then
  mkdir -p /root/.ssh
  chmod 700 /root/.ssh
fi
# Fetch public key using HTTP
curl http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key > /tmp/my-key
if [ $? -eq 0 ] ; then
  if [ -z "$(grep "$(cat /tmp/my-key)" /root/.ssh/authorized_keys)" ]; then
    cat /tmp/my-key >> /root/.ssh/authorized_keys
    chmod 600 /root/.ssh/authorized_keys
  fi
  rm /tmp/my-key
fi
EOS

基本的にはマニュアル通りですが、アップデートが済んだ ec2-ami-tools の rpm を削除するのと、ダウンロードした ssh の公開鍵がすでに /root/.ssh/authorized_keys に存在した場合にスキップする処理を追加しています。

sshd の設定変更

# perl -p -i -e 's,^#PermitRootLogin yes,PermitRootLogin without-password,' etc/ssh/sshd_config
# perl -p -i -e 's,^#UseDNS yes,UseDNS no,' etc/ssh/sshd_config
# perl -p -i -e 's,^PasswordAuthentication yes,PasswordAuthentication no,' etc/ssh/sshd_config
# perl -p -i -e 's,^UsePAM yes,UsePAM no,' etc/ssh/sshd_config

マニュアルで推奨されている項目に加えて、パスワード認証と PAM を無効にしています。

selinux の設定変更

# perl -p -i -e 's,^SELINUX=enforcing,SELINUX=disabled,' etc/sysconfig/selinux
# perl -p -i -e 's,^SELINUX=enforcing,SELINUX=disabled,' etc/selinux/config

「不要なファイルの削除」で selinux 関連を削除してしまっているので、基本的には不要ですが、残す場合は disabled にしておかないと ssh でログインできませんでした。

きちんとポリシーを設定すれば enforcing でもログインできるのかもしれませんが、バッサリ切ってしまいます。

カーネルモジュールをインストール

使用する AKI に対応したモジュールをインストールします。ここでは ec2-public-images/ec2-vmlinuz-2.6.21.7-2.fc8xen.i386.manifest.xml を使用するものとします。

上記 AKI に対応したモジュールを、http://s3.amazonaws.com/ec2-downloads/ec2-modules-2.6.21-2952.fc8xen-i686.tgz からダウンロードして、イメージの外に配置してあるものとします。

# tar xfz ../ec2-modules-2.6.21-2952.fc8xen-i686.tgz
# cd lib/modules
# ln -s 2.6.21-2952.fc8xen 2.6.21.7-2.fc8xen
# cd ../../
# chroot . depmod -a 2.6.21.7-2.fc8xen

ldconfig を実行

# chroot . ldconfig

これをしておかないと、"4gb seg fixup ... " というメッセージが /var/log/messages に吐き出され続けてしまうようです。

不要なファイルを削除してイメージをアンマウント

# yum -c ../yum-centos-i386-xen.conf --installroot=$PWD -y clean all
# cd ..
# umount ami-root/proc
# umount -d ami-root

yum のキャッシュを削除します。

バンドルイメージを作成して S3 にアップロード

公開用の AWS のアカウントのアクセスキー / シークレットアクセスキーと、秘密鍵 / X.509証明書が必要です。

AWS のYour Account > Access Identifiers から参照、ダウンロードしておいてください。

AWS_UID は、上記ページの右上に出ている Account Number からハイフンを抜いたものです。

# rm -f ami-bundle/*
# ec2-bundle-image -i centos-5.3.img -k pk-HOGEHOGE.pem -c cert-HOGEHOGE.pem -u AWS_UID -d ./ami-bundle -r i386 --kernel aki-a71cf9ce --ramdisk ari-a51cf9cc
# ec2-upload-bundle -b S3_BUCKET_NAME -m ami-bundle/centos-5.3.img.manifest.xml -a ACCESS_KEY -s SECRET_ACCESS_KEY

EC2 にイメージを登録

# ec2-register -K pk-HOGEHOGE.pem -C cert-HOGEHOGE.pem S3_BUCKET_NAME/centos-5.3.img.manifest.xml

これでインスタンスとして使用する準備ができました。


きちんと動くイメージを作るのに 1 週間近くかかってしまいました。S3 へのアップロードに時間がかかるのがネックですね。

現在はこのイメージに puppet を追加して、インスタンスを追加した際に初期設定を puppet を使ってできるように試行錯誤しています。こちらもある程度まとまったらブログに載せようと思います。

関連記事

クレイについてもっと知りたい方は…

  1. クレイの3つの強みを見てみる。
  2. WEBシステムのことなら何でもご相談ください。

「いいね!」で応援よろしくお願いします!

このエントリーに対するコメント

  1. はじめまして。
    ポストを見て本当に役に立ちました。
    しかし、ひとつ質問がありますが。。

    10GB以上のイメージの生成はどうやってするのでしょうか。
    他のインスタンスを持ち、EC2を作ると/mntのところが100GBもあったりしますが。。
    Fdiskでcheckするとマウントされてますね。

    ^^;;どうかお願いします。

    林ヨングン

    2011年05月25日, 10:01 PM

  2. はじめまして。コメントありがとうございます。

    イメージのサイズについてですが、10GB が上限のようです。
    /mnt はイメージとは別に、インスタンスタイプ毎に割り当てサイズが決まっています。こちらのドキュメントをご参照ください。

    よろしくお願いいたします。

    morimori

    2011年05月27日, 10:24 AM

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


トラックバック
  1. [Amazon EC2] AMI をゼロから作る CentOS 6.2 / S3-Backed 版 | KRAY Inc2012/01/24, 1:03 PM

    […] 社サイトをリニューアルして、サイトのアクセス数が大分増えるよりも前に書いた EC2 の AMI を作る記事を、CentOS 6.2 ベースでやってみようと思います。 少し長いですが、お付き合いくだ […]

we use!!Ruby on RailsAmazon Web Services

このページの先頭へ