まえがき
もりやまです。
今回は、一昨年の 7 月に弊社サイトをリニューアルして、サイトのアクセス数が大分増えるよりも前に書いた EC2 の AMI を作る記事を、CentOS 6.2 ベースでやってみようと思います。
少し長いですが、お付き合いください。
はじめに
公式の手順は「From a Loopback - Amazon Elastic Compute Cloud」にあります。
基本はこの通りなのですが、如何せん Fedora Core 4 を使った例なので、最新の OS で作るにはそのままでは使えませんのでご注意ください。
CentOS 6.2 のベースである RHEL6 は、rpm パッケージのペイロードが xz 形式で圧縮されるようになったため、RHEL5 以前の rpm では展開することができません。
そのため AMI のビルド環境は、xz 形式のペイロードを展開できるバージョンの rpm が使われている OS を使う必要があります。
今回はビルド用の環境に、Momonga Linux (64bit) の trunk 環境を使用しましたが、作成する AMI と同じ OS・アーキテクチャで揃えておくのが安心です。
それでは実際に作っていきたいと思います。
0. 準備
AMI の作成には、EC2 AMI Tools というパッケージを使うので、インストールしておいてください。
ruby で書かれているので、ruby も入っている必要があります。
1. loopback イメージを作成
[cc lang="bash"]
dd if=/dev/zero of=CentOS-6.2-1.kray-i386.img bs=1G count=8
[/cc]
このイメージがそのままインスタンスのルートデバイスになります。今回は 8GB で作成します。
AMI にする際にイメージの空き領域はほとんど圧縮されてしまうので、必要な領域がそれほど多くなくても大きめに作っておいて問題ありません。
ただし、S3-Backed なインスタンスで使えるルートデバイスの最大サイズは 10GB です。
2. loopback イメージにファイルシステムを作成してマウント
[cc lang="bash"]
mkfs.ext4 -F -L _/ CentOS-6.2-1.kray-i386.img
mkdir ami-root
mount -o loop CentOS-6.2-1.kray-i386.img ami-root
cd ami-root
[/cc]
今回はルートデバイスを ext4 でフォーマットします。ルートデバイスで使えるファイルシステムは「Enabling Your Own Linux Kernels - Amazon Elastic Compute Cloud」に記載されています。
以前は AWS 側で用意されている kernel しか使えなかったのですが、2010 年 7 月に、PV-GRUB を使ってインスタンスにインストールされている kernel を起動できるようになりました。
今回はそれを使う AMI を作るので、PV-GRUB が認識できるファイルシステムを使う必要があります。
3. インストールに必要なファイルを作成
[cc lang="bash"]
mkdir etc proc dev
cat > etc/fstab < [cc lang="bash"] [cc lang="bash"] 公式のドキュメントでは「Base」グループでインストールしていますが、ここではさらに少ない「Core」グループでインストールします。 [cc lang="bash"] SELinux や IPv6 は使わないので、関連するパッケージを削除します。 [cc lang="bash"] PV-GRUB で User Provided Kernel による起動をするので、kernel をインストールします。 [cc lang="bash"] ここは必須ではありませんが、あると便利なので入れておきます。 [cc lang="bash"] ちなみに、Amazon Linux AMI を起動すると xvda になるのですが、今回の方法で作った AMI では xvde になってしまいました。 [cc lang="bash"] [cc lang="bash"] 基本は「Sharing AMIs Safely - Amazon Elastic Compute Cloud」に記載されている通りです。 [cc lang="bash"] こちらも上記のドキュメントに記載されているのですが、更にパスワード認証と PAM を無効にしています。 [cc lang="bash"] [cc lang="bash"] EC2 に限らず、Xen 環境で発生する問題のようですが、「4gb seg fixup ...」というようなメッセージが延々と /var/log/messages に出力されてしまうことがあります。 [cc lang="bash"] AMI を作成する前に、yum のキャッシュ等を削除します。 [cc lang="bash"] インストールが済んだ loopback イメージを AMI としてバンドルします。 [cc lang="bash"] 東京リージョンのバケットにアップロードするので、「--location ap-northeast-1」を指定しています。 さて、いよいよアップロードした AMI を登録するのですが、実は登録用のコマンドは EC2 AMI Tools には含まれていません。 あとは起動して動作確認して、問題なければ完成です。 今回 S3-Backed の AMI を作ったので、次回はそれを EBS-Backed の AMI にする方法を紹介したいと思います。
wget -O ../RPM-GPG-KEY-CentOS-6 http://ftp.riken.jp/Linux/centos/RPM-GPG-KEY-CentOS-6
cat > ../repos.conf <
setarch i386 yum -y -c ../repos.conf --installroot=$PWD --disablerepo=* --enablerepo=ami-base,ami-updates groupinstall Core
[/cc]
「setarch i386」は、ビルドに使用するホストが 64bit 環境のため指定しています。
「--disablerepo=* --enablerepo=ami-base,ami-updates」は、ビルドに使用するホストに設定してあるリポジトリまでロードされてしまうため、このように指定しています。
以降 yum を実行する際は、すべてこれらを指定します。6. 不要なパッケージを削除
rpm -e --root $PWD selinux-policy-targeted selinux-policy policycoreutils libselinux-utils libsemanage checkpolicy iptables-ipv6
setarch i386 yum -y --installroot=$PWD remove "*-firmware"
[/cc]
さらに、EC2 で動かすには必要ないファームウェアも削除してしまいます。7. kernel をインストール
setarch i386 yum -y -c ../repos.conf --installroot=$PWD --disablerepo=* --enablerepo=ami-base,ami-updates install kernel
[/cc]
ディストリビューションによっては Xen 用の kernel が別にあるものもありますが、CentOS6 では kernel パッケージで問題ないようです。8. ec2-ami-tools と ec2-metadata をインストール
setarch i386 yum -y -c ../repos.conf --installroot=$PWD --disablerepo=* --enablerepo=ami-base,ami-updates install ruby rsync
rpm -Uvh --root=$PWD http://s3.amazonaws.com/ec2-downloads/ec2-ami-tools.noarch.rpm
wget -O usr/bin/ec2-metadata http://s3.amazonaws.com/ec2metadata/ec2-metadata
chmod +x usr/bin/ec2-metadata
[/cc]9. fstab に /mnt と swap パーティションの設定を追加
cat >> etc/fstab << EOS
/dev/xvde2 /mnt ext4 defaults 1 0
/dev/xvde3 swap swap defaults 0 0
EOS
[/cc]
instance storage をマウントする設定を追加します。デバイス名が xvde2, xvde3 と決め打ちですが、これは t1.micro を除く 32bit のインスタンスで設定されます。
64bit 環境ではまた変わってくるので、詳しくは「Amazon EC2 Instance Storage - Amazon Elastic Compute Cloud」を参照してください。
AWS 公式の RHEL6 の AMI でも xvde になるので、Amazon Linux AMI が特別なのでしょうか。10. ネットワークの設定
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
[/cc]
こちらはほぼ公式のドキュメントの通りです。
11. rc.local に ssh 公開鍵を取得する設定を追加
cat > etc/rc.local << EOS
# Update the Amazon EC2 AMI creation tools
rpm -Uvh http://s3.amazonaws.com/ec2-downloads/ec2-ami-tools.noarch.rpm
# Update ec2-metadata
wget -O /usr/bin/ec2-metadata http://s3.amazonaws.com/ec2metadata/ec2-metadata
chmod 755 /usr/bin/ec2-metadata
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 0700 /root/.ssh
fi
ATTEMPTS=5
FAILED=0
# Fetch public key using HTTP
while [ ! -f /root/.ssh/authorized_keys ]; do
curl -f http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key > /tmp/aws-key 2>/dev/null
if [ $? -eq 0 ]; then
cat /tmp/aws-key >> /root/.ssh/authorized_keys
chmod 0600 /root/.ssh/authorized_keys
rm -f /tmp/aws-key
echo "Successfully retrieved AWS public key from instance metadata"
else
FAILED=$(($FAILED + 1))
if [ $FAILED -ge $ATTEMPTS ]; then
echo "Failed to retrieve AWS public key after $FAILED attempts, quitting"
break
fi
echo "Could not retrieve AWS public key (attempt #$FAILED/$ATTEMPTS), retrying in 5 seconds..."
sleep 5
fi
done
EOS
[/cc]
合わせて ec2-ami-tools と ec2-metadata のアップデートをするようにしています。12. 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
[/cc]13. grub の設定を追加
cat > boot/grub/menu.lst <
echo "hwcap 1 nosegneg" > etc/ld.so.conf.d/libc6-xen.conf
chroot . ldconfig
[/cc]
上記はそれを防ぐための設定です。15. 不要なファイルを削除してイメージをアンマウント
setarch ${ARCH} yum -y -c ../repos.conf --installroot=$PWD --disablerepo=* --enablerepo=ami-base,ami-updates clean all
cd ..
umount ami-root/proc
umount -d ami-root
[/cc]
スクラッチから作る場合には問題ないと思いますが、既存のインスタンスを AMI 化する際には、ssh の公開鍵や sshd のホストキー、.bash_history やログ等、削除すべきファイルが多々あるので注意しましょう。16. loopback イメージをバンドル
mkdir ami-bundle
ec2-bundle-image -i CentOS-6.2-1.kray-i386.img -k ${EC2_PRIVATE_KEY} -c ${EC2_CERT} -u ${AWS_ACCOUNT_NUMBER} -d ./ami-bundle -r i386 --kernel aki-ec5df7ed
[/cc]
ここで PV-GRUB の AKI を指定するのですが、同じ AKI でもリージョンごとに ID が違います。今回は東京リージョン(ap-northeast-1)のものを指定します。
PV-GRUB 用の最新の AKI は、User Provided Kernel のドキュメントに載っています。
ファイル名の pv-grub- の後が、hd0 のものが S3-Backed 用、hd00 のものが EBS-Backed 用のようです。
今回は「東京リージョン」「S3-Backed」「32bit」なので、「aki-ec5df7ed ec2-public-images-ap-northeast-1/pv-grub-hd0_1.02-i386.gz.manifest.xml」を指定します。17. バンドルした AMI を S3 にアップロード
ec2-upload-bundle -b ${S3_BUCKET} -a ${AWS_ACCESS_KEY} -s ${AWS_SECRET_ACCESS_KEY} -m ./ami-bundle/CentOS-6.2-1.kray-i386.img.manifest.xml --retry --location ap-northeast-1
[/cc]
この際、アップロード先のバケット名にドットが含まれていると、証明書の検証に失敗してアップロードに失敗します。
ec2-upload-bundle を使わずに別の方法でアップロードするか、ec2-upload-bundle が内部で curl を使うので、~/.curlrc に「insecure」と書いておくことで回避できます。
後者が簡単ですが、アップロードが完了したら「insecure」を削除することをお忘れなく。18. AMI を登録
登録用のコマンドは EC2 API Tools というパッケージに含まれているのですが、今回はそれを使わずに AWS Management Console から登録してみます。
まとめ
今回の手順をシェルスクリプトにして、コマンド一発で S3 へのアップロードまで済むようにしたものを Gist に上げたので、参考にしてみてください。
このエントリーに対するコメント
- トラックバック
「いいね!」で応援よろしくお願いします!