~nabeken/diary/

Gentoo Linux(6年くらい)とFreeBSD(1年くらい)とOpenBSD(新参者)を使う日々。


IHANet BGP peering overview

Amazon Linux上でCentOS 5.xのAMIを作る

Posted on Fri Mar 09 20:01:27 +0900 2012 by nabeken

皆さんAMIの拾い食いはしていませんか?野良AMIにはさまざまなリスクがあります。信頼できる人/組織が作成したAMI以外は基本的に自作したほうがよいと思います。今回はAmazon Linux 2011.09上でCentOS 5.6のリリース版AMIを作成する手順を記します。

Amazon Linuxについて

Amazon Linux はEC2用AMIとしてAmazonがメンテナンスしているディストリビューションです。 最新版はRHEL6互換 + ec2系のツール、cloud-initがセットアップ済みです。

どうしてもCentOSでなければならない理由がなければ、そのままAmazon Linuxを使うのが楽だと思います。 今回はどの環境でも動くことが要件なので、CentOSをベースにする必要がありました。

そんなわけで、Amazon Linux上でCentOS 5、今回は事情により特にCentOS 5.6 (x86_64)のリリース版最小構成でAMIを作成します。 このAMIは今後のカスタマイズの基本AMIとするため、swap領域、cloud-init的なものは一切セットアップしません。 root deviceはinstance store-backedで、ephemeral領域とsshの公開鍵のセットアップのみを施します。

使用するAmazon Linuxは Basic 64-bit Amazon Linux AMI 2011.09 (AMI Id: ami-0a44f00b) です。

作業用インスタンスを起動する

節約のため、作業用インスタンスはスポットインスタンスで起動させます。 また、AMI用のディスクイメージ作成作業用の領域としてEBSはコストがかかるため、ephemeral領域(instance store)にディスクイメージを展開して作業します。

スポットインスタンスにephemeral領域を付けて起動する場合、Management Consoleからはできないため、コマンドから入札します。 コマンドの詳細はヘルプを見てもらうとして、ここで大事なのは -b /dev/sdb=ephemeral0 の部分だけです。

$ ec2-request-spot-instances ami-0a44f00b -b /dev/sdb=ephemeral0 --region ap-northeast-1 \
  -t m1.large -k your-keypair --price your-price --instance-count 1

入札が成功するとインスタンスが起動するはずです。 起動したインスタンスにec2-userでログインします。

ephemeral領域にAMI用のディスクイメージを用意する

ephemeral領域にディスクイメージを作成し、loopbackマウントします。 マウント後、いくつか下ごしらえをします。

$ cd /media/ephemeral0
$ sudo mkdir ami-{bundle,root}
$ sudo dd if=/dev/zero of=CentOS-5.6-x86_64.img bs=1M count=8000
$ sudo /sbin/mkfs.ext4 -F CentOS-5.6-x86_64.img
$ sudo mount -o loop CentOS-5.6-x86_64.img /media/ephemeral0/ami-root
$ sudo mkdir /media/ephemeral0/ami-root/{etc,proc,dev}
$ sudo mount -t proc none /media/ephemeral0/ami-root/proc
$ for i in console null zero; do sudo /sbin/MAKEDEV -d /media/ephemeral0/ami-root/dev -x $i; done

AMI用のfstabは /etc/fstab をコピーし、一部修正します。

$ sudo cp /etc/fstab ami-root/etc/
$ sudo vi ami-root/etc/fstab
ephemeral0の部分は必要ないので削除します。

ディスクイメージの下ごしらえは完了です。

CentOS 5.6 (x86_64)のリリース版yumリポジトリを用意する

今回は基本AMIとして作るため、CentOS 5.6 (x86_64)のリリース版でyumを実行します。作成時点ではアップデートは一切適用しません。 DVDのISOイメージをすでに持っている場合はその中身をどこか適当なWebサーバへ展開します。

持っていない場合はvault.centos.org (アーカイブ)から調達する必要があります。 今回の作成にあたり、私が5.6のi386, x86_64をrsyncしたものを以下で公開しています。 このリポジトリは予告なく公開を終了する場合があります。 (ちなみに、isosをexcludeしても26GBほどあります。updatesとi386もexcludeすればDVD1枚分になりそう…)

yumコマンドでCentOS 5.6 (x86_64)環境を構築する

リポジトリの準備ができたら、次は yum.conf を用意します。updates-releasedリポジトリは無効化しています。 baseurlの部分は適宜読み替えてください。

$ cat /media/ephemeral0/yum.conf
[main]
cachedir=/var/cache/yum
debuglevel=2
logfile=/var/log/yum.log
exclude=*-debuginfo
gpgcheck=0
obsoletes=1
reposdir=/dev/null
[base]
name=CentOS 5.6 - Base
baseurl=https://projects.tsuntsun.net/~nabeken/CentOS/5.6/os/$basearch/
enabled=1
[updates-released]
name=CentOS 5.6 - Released Updates
baseurl=https://projects.tsuntsun.net/~nabeken/CentOS/5.6/updates/$basearch/
enabled=0

groupinstallしたくなりますが、まずは yum コマンドだけ先にインストールします。

実はAmazon Linuxの yum およびrpm実行環境はCentOS 5系からみるとrpmデータベースで使っているデータベース(Berkeley DB)の形式が新しいため、 このままでは作成したAMIで起動しても自分自身の yum コマンド(rpmコマンド)が使えなくなります。そこで、

  1. yum コマンドをインストール
  2. CentOS 5の環境にchrootし、rpmデータベースをクリア
  3. 再度 yum をインストールし、rpmデータベースを再作成

の手順を踏みます。

$ sudo yum -c /media/ephemeral0/yum.conf --installroot=/media/ephemeral0/ami-root install -y yum

chrootした後に必要となるファイルを予めコピーしておきます。

$ sudo cp /etc/resolv.conf /media/ephemeral0/ami-root/etc
$ sudo cp /media/ephemeral0/yum.conf /media/ephemeral0/ami-root/
(このファイルは最後に削除します)

chrootします。

$ sudo chroot /media/ephemeral0/ami-root /bin/bash
# source /etc/profile
# yum
(ここでyumがデータベースのバージョンが新しすぎると文句をいう)
Loaded plugins: fastestmirror
rpmdb: /var/lib/rpm/Packages: unsupported hash version: 9
error: cannot open Packages index using db3 - Invalid argument (22)
error: cannot open Packages database in /var/lib/rpm
Traceback (most recent call last):
File "/usr/bin/yum", line 29, in ?
yummain.user_main(sys.argv[1:], exit_code=True)
File "/usr/share/yum-cli/yummain.py", line 309, in user_main
errcode = main(args)
File "/usr/share/yum-cli/yummain.py", line 157, in main
base.getOptionsConfig(args)
File "/usr/share/yum-cli/cli.py", line 187, in getOptionsConfig
self.conf
File "/usr/lib/python2.4/site-packages/yum/__init__.py", line 665, in <lambda>
conf = property(fget=lambda self: self._getConfig(),
File "/usr/lib/python2.4/site-packages/yum/__init__.py", line 240, in _getConfig
self._conf = config.readMainConfig(startupconf)
File "/usr/lib/python2.4/site-packages/yum/config.py", line 804, in readMainConfig
yumvars['releasever'] = _getsysver(startupconf.installroot, startupconf.distroverpkg)
File "/usr/lib/python2.4/site-packages/yum/config.py", line 877, in _getsysver
idx = ts.dbMatch('provides', distroverpkg)
TypeError: rpmdb open failed
# rm -f /var/lib/rpm/*
# yum -c /yum.conf install -y yum
(もう1度すべてインストールしなおすことでrpmデータベースも再作成)
# ls -l /var/lib/rpm
# yum -c /yum.conf groupinstall -y Core Base

CentOS 5.6リリース版環境の構築が完了しました。

CentOS 5.6 (x86_64)環境の設定

本来インストーラーで行なわれる処理をchroot内で手動にて行ないます。

  1. ネットワーク設定

    # cat /etc/sysconfig/network-scripts/ifcfg-eth0
    DEVICE=eth0
    BOOTPROTO=dhcp
    ONBOOT=yes
    TYPE=Ethernet
    USERCTL=yes
    PEERDNS=yes
    IPV6INIT=no
    
    # cat /etc/sysconfig/network
    NETWORKING=yes
    
    # echo '127.0.0.1 localhost.localdomain localhost' > /etc/hosts
    
  2. sshdの設定

    パスワード認証を無効化し、公開鍵認証のみにします。

    # vi /etc/ssh/sshd_config
    PasswordAuthentication no
    PermitRootLogin without-password
    UsePAM no
    
  3. /etc/shadowの生成

    /etc/shadowが存在していない場合、 passwd コマンドが使用できません。手動で pwconv コマンド を実行し、生成します。

    # pwconv
    
  4. selinuxの無効化

    disabledにします。

    # vi /etc/sysconfig/selinux
    SELINUX=disabled
    
  5. 起動サービスの設定

    必要のないサービスを落とします。

    # chkconfig --list | grep -E '[2345]:on'
    # for i in bluetooth firstboot gpm hidd ip6tables iscsi iscsid \
      kudzu nfslock pcscd portmap rpcgssd rpcidmapd smartd yum-updatesd; do \
      chkconfig --level 2345 $i off; \
      done
    
  6. root用のssh公開鍵の取得処理

    インスタンスの初回起動時にmetadataからkeypairを取得し、rootのssh公開鍵として設定する必要があります。 RHEL6系であれば、Amazon Linuxのcloud-initパッケージを流用できそうですが、今回は [Amazon EC2] AMI をゼロから作る CentOS 6.2 / S3-Backed 版 を参考に /etc/rc.local へ取得処理を追加します。

  7. Xen domU用カーネルのインストール

    CentOS 5系では標準カーネルのままだとXenのdomUとしては起動しないため、別途カーネルをインストールします。

    # yum install -y kernel-xen
    
  8. Xen domU用にinitrdを再生成

    domU用に必要なモジュールを組み込んで再生成します。

    # ls -l /boot
    (el5xenなカーネルを探します。)
    # mkinitrd --with xenblk --with xennet /boot/initrd-2.6.18-274.18.1.el5xen_ec2.img 2.6.18-274.18.1.el5xen
    # ls -l /boot/initrd-2.6.18-274.18.1.el5xen_ec2.img
    (できあがっているのを確認する)
    
  9. grubの設定

    後述しますが、このAMIはpvgrub経由で起動させるため、grubの設定を用意します。 今回はinstance store-backedなのでkernelに渡すrootは sda1 を指定します。

    # cat /boot/grub/menu.lst
    default=0
    timeout=0
    hiddenmenu
    
    title CentOS 5.6 (x86_64)
    root (hd0)
    kernel /boot/vmlinuz-2.6.18-274.18.1.el5xen root=/dev/sda1
    initrd /boot/initrd-2.6.18-274.18.1.el5xen_ec2.img
    
  10. 一時ファイルの削除

    最後にセットアップに使ったファイルを削除します。chrootから抜けて作業します。

    # exit
    (chrootから抜ける)
    $ sudo rm /media/ephemeral0/ami-root/{yum.conf,root/.bash_history}
    

    また、 yum コマンドを再インストールした際のrpmnewファイルを削除します。 (パッケージを入れ直した時、既存ファイルを上書きせずに新しいファイルをファイル名.rpmnewとして保存する仕組みがあります。 今回は初期状態のため、rpmnewファイルは削除しても問題ありません。)

    $ sudo find /media/ephemeral0/ami-root -type f -name *\.rpmnew
    (対象ファイルが問題なさそうなことを確認)
    $ sudo find /media/ephemeral0/ami-root -type f -name *\.rpmnew | sudo xargs rm
    

ディスクイメージのbundleイメージ化

作成したディスクイメージをS3へアップロードする下準備をします。まずはイメージをunmountします。

$ cd /media/ephemeral0
$ sudo umount /media/ephemeral0/ami-root/proc
$ sudo umount /media/ephemeral0/ami-root
$ sudo chown ec2-user:ec2-user -R .
(ec2-*コマンドをec2-userで使いため)

ec2コマンドを作業用インスタンスで行なうための下準備は済んでいるものとします。 (環境変数の設定、証明書のコピーなど。リージョンは環境変数で指定していると仮定。)

下準備ができたら ec2-bundle-image コマンドを実行します。

$ ec2-bundle-image --cert ${EC2_CERT} --privatekey ${EC2_PRIVATE_KEY} --user 1111-2222-3333 \
  -i CentOS-5.6-x86_64.img -r x86_64 -d /media/ephemeral0/ami-bundle/
  (--userの引数に与えるIDはアカウントアクティビティから確認可能)

内部ではディスクイメージをtarしてgzipしてAESで暗号化しているようです。

作成したbundleイメージをS3へアップロードする

bundleイメージ保存用のS3のバケットはすでに作成済みとします。ここでは nabeken-amis とします。

$ ec2-upload-bundle --access-key ${EC2_ACCESS_KEY} --secret-key ${EC2_SECRET_KEY} \
  --bucket nabeken-amis/CentOS/5.6/ -m ./ami-bundle/CentOS-5.6-x86_64.img.manifest.xml
  (外部からS3へアップロードするよりも、EC2、S3間は非常に早い)

pvgrub用のAKIとephemeral領域を設定してAMIを作成する

今回作成するAMIはinstance store-backedなAMIです。

  • instance store-backed (S3-backed)

    インスタンスストレージ(ephemeral領域と同じ種別)上にディスクイメージを展開したものをroot deviceにする。 root deviceになる場合、domUからはsdaとしては見えず、パーティション1(sda 1)として見える。

  • EBS-backed

    EBSは通常のディスク(sdaなど)として見せることも可能。実際には、各インスタンス種別 (m1.{small,large}, t1.microなど)にかかわらず使えるようにする場合は instance store-backedと合せて sda1 を / と構成することをオススメします。

    ただし、LVMルートやRAIDXルートをする場合は /boot を分ける必要があるため、 パーティションを切る必要があるでしょう。

pvgrubを使う場合、この違いが重要になります。

  • Enabling Your Own Linux Kernels

    Several PV-GRUB AKIs are available depending on the type and location of your instance. There are AKIs for 32-bit and 64-bit architecture types, with each having one AKI for partitioned images and another AKI for partitionless images. You must choose an AKI with "hd0" in the name if you want a raw or unpartitioned disk image (most images). Choose an AKI with "hd00" in the name if you want an image that has a partition table.

    インスタンスのロケーション、種類に応じて数種類の PV-GRUB AKI (Amazon Kernel Image)が利用可能です。 32bit, 64bitにそれぞれパーティションテーブルのあるディスクイメージとパーティションテーブルのないディスクイメージに対して1つのAKIがあります。 rawパーティションあるいはパーティションテーブルのないディスクイメージで使いたい場合は "hd0" のAKIを選ばなければなりません。 パーティションテーブルのあるディスクイメージで使いたい場合は "hd00" のAKIを選択してください。

今回は東京リージョン(northeast-1)でinstance store-backedなx86_64のAMIを作るので、 aki-ee5df7ef ec2-public-images-ap-northeast-1/pv-grub-hd0_1.02-x86_64.gz.manifest.xml を選択します。

$ ec2-register --cert ${EC2_CERT} --private-key ${EC2_PRIVATE_KEY} nabeken-amis/CentOS/5.6/CentOS-5.6-x86_64.img.manifest.xml \
  -a x86_64 -n 'CentOS 5.6 (x86_64) instance store/ephemeral0-3' -d 'CentOS 5.6 (x86_64) instance store w/ephemeral[0-3]' \
  -b '/dev/sdc=ephemeral0' -b '/dev/sdd=ephemeral1' -b '/dev/sde=ephemeral2' -b '/dev/sdf=ephemeral3' \
  --kernel aki-ee5df7ef --root-device-name /dev/sda1
IMAGE   ami-XXXXXXXX

作成したAMIで起動してみる

スポットインスタンスで起動してみます。今回はManagement Consoleから作成したAMIで起動します。 起動したら root でログインできるはずです。

$ ssh -l root ec2-XXX-XXX-XXX-XXX.ap-northeast-1.compute.amazonaws.com
# uname -a
Linux ip-XXX-XXX-XXX-XXX 2.6.18-274.18.1.el5xen #1 SMP Thu Feb 9 13:27:02 EST 2012 x86_64 x86_64 x86_64 GNU/Linux
# cat /etc/redhat-release
CentOS release 5.6 (Final)

ec2-get-console-output でコンソールのログを確認できます。 このログはリアルタイムではなく、2分程度のバッチ更新になっているようです。

$ ec2-get-console-output i-XXXXXXX

今後はこのAMIをベースに作り込みを行い、EBS-backedなAMIにしていきます。

更新履歴

  • ストレージ種別の説明を一部修正 (Fri, 9 Mar 2012 20:01:27 +0900)
  • 初稿 (Mon, 5 Mar 2012 01:30:41 +0900)