オリジナルLinux AMIの作成

AWS 東京リージョンで、既存のAMIに頼らずに自前のLinux AMIを作成する方法のメモ。

目的はAWS以外で利用する物理サーバとAWSのインスタンスの内容を極力合わせること。 そのために最小構成でOSのインストールを行い、それをベースにして必要なパッケージを追加してゆくことにする。

また、PVGRUBを利用することでkernelも自分で選択できるようにする。 今回は32bit版のScientific Linux 6.1のAMIを作成してみるが、CentOSなどの他のディストリビューションや、バージョン、アーキテクチャが異なっても同様の手順で作業ができるはず。

準備

次の2つを用意する。

  • AMI作成用のインスタンス
  • OSイメージを置くEBSボリューム

AMI作成用のインスタンスは、ec2-ami-toolsとec2-api-toolsが利用できれば何でもよい。 ただし、作成したいAMIとアーキテクチャは合わせておくこと。

今回は32bit版のBasic 32-bit Amazon Linux AMI 2011.09 (ami-0644f007)を利用する。 Instance Storeのインスタンスでも作業はできるが、作業の中断、再開が容易なのでEBSインスタンスを利用した方がよいと思う。 これを普通に立ち上げておく。

合わせて、OSのイメージを保存するためのEBSボリュームを作成する。 最小構成でインストールをするのでサイズは小さくても構わないが、今回は10GBにしておく。

作成したら、AMI作成用のインスタンスにアタッチしておくこと。

OSのインストール

アタッチ済みのEBSボリュームを初期化し、マウントする。 /dev/xvdhの部分はアタッチ時の設定に応じて適宜読み替えること。

# mkfs.ext4 /dev/xvdh
# mkdir /ebs-root
# mount /dev/xvdh /ebs-root

ここにOSをインストールしてゆく。

次の内容で、sl6.repoを作成する。[sl6]の部分は任意の名前でよいが、作業用のインスタンスのリポジトリ、対象OSのインストール直後のリポジトリのどの名前ともバッティングしないようにしておくとよい。次の手順で示すが、インストール時に既存のリポジトリをすべて無効化した上で、この設定ファイルのリポジトリを有効化する必要があることがその理由。

[sl6]
name=Scientific Linux 6 - $basearch
baseurl=http://ftp.riken.jp/Linux/scientific/6/$basearch/os/
enabled=1
gpgcheck=0

[sl6-security]
name=Scientific Linux 6 - $basearch - security updates
baseurl=http://ftp.riken.jp/Linux/scientific/6/$basearch/updates/security/
enabled=1
gpgcheck=0

準備ができたらOSのインストールを行う。AMI作成用インスタンスのリポジトリの設定に邪魔されるので、すべてのリポジトリを無効化し、必要なリポジトリを有効化するという方法を採る。

# yum -c sl6.repo --disablerepo=* --enablerepo=sl6* --installroot=/ebs-root -y groupinstall core

次にkernelのインストールを行う。fstabを先に作成しておくとよい。 /ebs-root/etc/fstabを次の内容で作成する。

/dev/xvde1 /         ext4    defaults        1 1
/dev/xvde2 /mnt      ext4    defaults        0 0
/dev/xvde3 swap      swap    defaults        0 0
none       /proc     proc    defaults        0 0
none       /sys      sysfs   defaults        0 0
none       /dev/pts  devpts  gid=5,mode=620  0 0
none       /dev/shm  tmpfs   defaults        0 0

準備ができたら、kernelをyumでインストールする。 すべてのリポジトリを無効化して、必要なリポジトリを有効化するという引数は先ほどの手順と変わらないのだが、今度は/ebs-root以下にインストール済みのyumの設定情報を無効化して必要なリポジトリを有効化することになる。

# yum -c sl6.repo --disablerepo=* --enablerepo=sl6* --installroot=/ebs-root -y install kernel

AMIとして稼動させるための準備

AMIとして利用できるようにするために、いくつかのファイルを修正もしくは作成する。

/ebs-root/boot/grub/menu.lst の作成

次の内容でブート時の設定ファイルを作成する。kernelのバージョンはインストールしたものと揃えること。 また、rootデバイスは/dev/sda1や/dev/xvda1ではなく、/dev/xvde1になってしまうことに注意。選択するkernelによって挙動が違ってくるようなので、うまく起動できないときはManagement Consoleなどから起動に失敗したインスタンスのSystem Logを取得して利用されるデバイスの確認をするとよい。

default=0
timeout=0
hiddenmenu
title Scientific Linux 6
        root (hd0)
        kernel /boot/vmlinuz-2.6.32-131.21.1.el6.i686 ro root=/dev/xvde1 4
        initrd /boot/initramfs-2.6.32-131.21.1.el6.i686.img

/ebs-root/etc/selinux/configの修正

SELinuxを無効化しておく。変更部分だけを抜粋。

# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
SELINUX=disabled

/ebs-root/etc/sysconfig/networkの作成

次の内容で作成する。

NETWORKING=yes

/ebs-root/etc/sysconfig/network-scripts/ifcfg-eth0の作成

次の内容で作成する。

DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes

/ebs-root/etc/sysconfig/i18nの作成

デフォルトの言語設定のために次の内容で作成しておく。

LANG="ja_JP.UTF-8"

/ebs-root/etc/localtimeの修正

システムのタイムゾーンを設定しておく。JSTに合わせるために、日本の情報をコピーしておく。

# cp /ebs-root/usr/share/zoneinfo/Japan /ebs-root/etc/localtime

/ebs-root/etc/init.d/getsshkeyの作成

次の内容でファイルを作成しておく。 RightScaleのCentOS 5のAMIに含まれていたものに、少し手を加えてある。

#!/bin/bash
# chkconfig: 4 11 11
# description: Get SSH keys from meta-data to create root's authorized_keys file


start() {
  if [ ! -d /root/.ssh ]; then
    echo "Create /root/.ssh directory."
    mkdir -p /root/.ssh
  fi
  chmod 700 /root/.ssh

  if [ ! -e /root/.ssh/authorized_keys ]; then
    echo "Create the empty authorized_keys."
    touch /root/.ssh/authorized_keys
  fi
  chmod 600 /root/.ssh/authorized_keys

  while true; do
    echo "Get public keys"
    key_list=`curl -s -L -f http://169.254.169.254/latest/meta-data/public-keys/`
    code=$?
    if [ $code -eq 0 ]; then
      break
    fi
    sleep 1
  done

  while read -r LINE; do
    equal_index=`expr index "$LINE" "="`
    key_index=${LINE:0:$equal_index-1}
    key_name=${LINE:$equal_index}

    append_to_auth_keys "$key_index" "$key_name"
  done <<< $key_list
}

append_to_auth_keys() {
  key_index=$1
  key_name=$2

  while true; do
    code=`curl -s -L -w '%{http_code}' -o "/root/.ssh/${key_name}.pub" "http://169.254.169.254/latest/meta-data/public-keys/${key_index}/openssh-key"`
    if [ $code -lt 500 ]; then
      break
    fi
    sleep 1
  done

  if [ $code -ge 200 -a $code -lt 300 ]; then
    if ! `grep -q -f "/root/.ssh/${key_name}.pub" /root/.ssh/authorized_keys`; then
      cat "/root/.ssh/${key_name}.pub" >> /root/.ssh/authorized_keys
    fi
  fi
}

stop() {
  echo "Nothing to do"
}

case "$1" in
  start)
    start
    ;;
  stop)
    stop
    ;;
  *)
    echo $"Usage: $0 {start|stop}"
    exit 1
esac

exit $?

このスクリプトはランレベル4のときにだけ稼動するようにしておく。 同じイメージを使って、物理サーバで動かすときにはランレベル3で起動させるので、 このスクリプトは動かないことを意図している。

chrootをしてから、chkconfigコマンドを使ってOSの起動時に稼動するように設定しておく。 最後にランレベルの確認もしておくとよい。

# chroot /ebs-root
# chkconfig --add getsshkey
# chkconfig --list getsshkey
getsshkey       0:off   1:off   2:off   3:off   4:on    5:off   6:off

また、実行パーミッションがないと鍵がインストールされずにログインできない困った事態に陥るので、注意が必要。念のため、chmodを実行しておくとよい。

# chmod +x /etc/init.d/getsshkey

AMIの作成

EBSの場合

OSイメージを作成したEBSボリュームを念のため、umountしてからスナップショットを作成しておく。

次のようにAMIの登録を行う。

# ec2-register -a i386 -s snap-xxxxxxxx -n sl6-base32-01 -b '/dev/sda2=ephemeral0' -b '/dev/sda3=ephemeral1' --kernel aki-ec5df7ed -K pk-xxxxx.pem -C cert-xxxxx.pem --region ap-northeast-1

それぞれのオプションの意味は次の通り。

-a       アーキテクチャの指定 今回はi386
-s       作成したEBSボリュームのスナップショットを指定
-n       AMIの名前 適当でよい
-b       インスタンスのローカルに置かれるブロックデバイスの指定 swapと/mntのために指定する
--kernel PVGRUBのAKIのIDを指定 詳細は後述
-K       秘密鍵のファイル名を指定 事前にコピーしておくこと
-C       X.509証明書のファイル名を指定 事前にコピーしておくこと
--region リージョンの指定 今回は東京なのでap-northeast-1

ここでAKIについて説明しておく。hd0とhd00の2種類があり、前者はパーティションを切っていない領域を指定して起動する場合に利用し、後者はパーティションを分割している場合に利用するものであるらしい。

今回のケースではパーティションを切っていないEBSボリュームをそのまま利用するので、hd0の方を選択することになる。対象リージョンで利用できるAKIは次のようにして調べることができる。

# ec2-describe-images -a -F image-type=kernel -K pk-xxxxx.pem -C cert-xxxxx.pem --region ap-northeast-1 | grep hd0

hd0で32bitのもの、かつバージョンの新しいほうを選択すると次のものになる。前述のkernelオプションではこのAKIを指定している。

IMAGE   aki-ec5df7ed    ec2-public-images-ap-northeast-1/pv-grub-hd0_1.02-i386.gz.manifest.xml
amazon      available       public          i386    kernel                          instance-store  paravirtual xen

以上の手順で、EBSインスタンス用のAMIが作成できる。

Instance Storeの場合

EBSインスタンス用に作成したEBSボリュームを利用してInstance StoreのAMIを作成する。

# ec2-bundle-vol -r i386 --kernel aki-ec5df7ed -v /ebs-root -d /mnt -k pk-xxxxx.pem -c cert-xxxxx.pem -u xxxxx -p sl6-base32-01 -B "ami=sda1,root=/dev/sda1,ephemeral0=sda2,swap=sda3"

オプションは次の通り。

-r       アーキテクチャの指定 今回はi386
--kernel PVGRUBのAKIのIDを指定 詳細はEBSのケースを参照
-v       OSイメージのルートディレクトリ
-d       作業用ディレクトリ
-k       秘密鍵のファイル名を指定 事前にコピーしておくこと
-c       X.509証明書のファイル名を指定 事前にコピーしておくこと
-u       AWSのアカウント番号
-p       S3にアップロードするイメージのファイル名 適当でよい
-B       インスタンスのローカルに置かれるブロックデバイスの指定 swapと/mntのために指定する

ブロックデバイスは、今回のケースのようにEBSボリュームをマウントしているケースでは指定しておいた方がよい。 正確にはインスタンスの起動時にEBSをアタッチしているケースになるのだが、次のようにメタデータの中にebsXが含まれていると、AMIをうまく作成できなくなる。

# curl http://169.254.169.254/latest/meta-data/block-device-mapping/
ami
ebs2
root
swap

次にS3にイメージをアップロードする。

# ec2-upload-bundle -b xxxxx -a xxxxx -s xxxxx -m /mnt/sl6-base32-01.manifest.xml

オプションにはS3のバケット名、アクセスキー、シークレットキー、作成したイメージのマニフェストを指定する。

最後にAMIの登録を行う。

# ec2-register xxxxx/sl6-base32-01.manifest.xml -K pk-xxxxx.pem -C cert-xxxxx.pem --region ap-northeast-1

こちらの引数は、S3に置かれたマニフェスト、秘密鍵、X.509証明書、リージョンの指定となっている。

これでInstance Store用のAMIが作成される。

オリジナルLinux AMIの作成」への1件のフィードバック

  1. ピンバック: オリジナルLinux AMIの作成 | Sandbox for Me « ブックマークしてます

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>