2014年11月2日日曜日

AWSにCentOS6をクリーンインストール

AWS で Rescue モードを使ってみます。


SI を仕事でやっていると、いろいろな制約に出くわします。
インターネットにつながっていれば簡単なことでも、そうでない環境で作業することになると、途端に難しくなることがあります。ファイルの持ち込みは CD-R に焼いてウィルスチェックをしてから、という手順を踏まなければならない、ということもよくあります。

今回は、AWS で Community AMIs を使ってはいけない状況で、固定バージョンの CentOS が必要になったというところから作業が始まりました。
これから説明する手順は、CentOS6 だけではなく、RHEL6 や Oracle Linux 6 でも、基本的には同じ手順で問題ないはずです。ライセンスは別途調達する前提です。


まずは、CentOS の公式サイトで情報を集めます。
http://wiki.centos.org/Cloud/AWS

欲しいものがズバリあれば、それを利用したいところです。
AWS では、Linux の仮想化タイプが PV から HVM に移行中で、今後のことを考えた場合、PV はやめた方がよいです。お客様の要望も HVM タイプでということでした。
以下のものが、今回の要件に一番近いようでした。


CentOS Version: CentOS-6 x86_64
Includes Updates: Yes
Virtualization Type: HVM
URL: https://aws.amazon.com/marketplace/pp/B00NQAYLWO


リンクをたどり、内容を確認したところ、Community AMIs にある AMI でした。残念です。
東京リージョンでは、以下のものに該当します。


CentOS 6 x86_64 (2014_09_29) EBS HVM-74e73035-3435-48d6-88e0-89cc02ad83ee-ami-a8a117c0.2 - ami-13614b12
Root device type: ebs Virtualization type: hvm


AWS Marketplace に同じようなものがないか探してみましたがありませんでした。
以下のものが一番近いようですが、残念ながら仮想化タイプが PV でした。


CentOS 6.5 (x86_64) - Release Media
CentOS-6.5-GA-03.3 on EBS x86_64 20140204:2336
Root Device Type: ebs Virtualization type: paravirtual


作るしかないという結果となりました。
どのようにして作るかですが、VMware vSphere 等で作って VM Import で AWS に移行する、という案が思いつきます。
この案は、今回要件を満たせませんでした。CloudTrail が S3 の操作ログを記録しないため利用が禁じられており(特別に許可をとるのもかなり面倒なので)、S3 を利用する VM Import も使用できませんでした。お客様要件による制約と AWS が抱える制約の両方を満たすのは大変です。

今回は、Amazon Linux を利用して CentOS をクリーンインストールすることにしました。
Amazon Linux 上で CentOS のイメージを作り、イメージを入れ換えます。
無料で試せる範囲のリソースで可能な操作です。
Amazon Linux を t2.micro タイプで用意します。EBS のサイズはデフォルトサイズ (8GB) で作ります。今回作成する OS イメージは 620MB ほどのサイズなので、手順をうまくやれば 1GB の EBS サイズに対応する AMI 作成も可能と思われますが、RHEL6 の最小要件がたしか 4GB だったと記憶しているので、チャレンジもほどほどにということで。OS 領域用の EBS サイズを可能な限り小さくするのは、バックアップにかかる費用を考えると理にかなっているとは思います。

※ 2014/11/7 追記
初期パーティションサイズを 1024MB で作成するように変更しました。
1GB の EBS サイズに対応する AMI の作成方法も追記しました。

まず、CentOS のリポジトリが必要となります。
内部ネットワーク内に専用リポジトリを作る手順はいろいろなところで紹介されていると思われるので構築手順は省略します。
とりあえず代替として、http://ftp.iij.ad.jp/pub/linux/centos/ を使って説明を続けます。

/srv/ ディレクトリにイメージを作ることにします。Debian であれば、debootstrap コマンドで簡単に構築できるのですが、CentOS にはそのようなコマンドがないようなので、手作業で構築します。

最初に、/srv/ ディレクトリに rpm のデータベースを作成します。


sudo rm -rf /srv
sudo mkdir /srv
sudo rpm --root=/srv --rebuilddb


centos-release パッケージを /srv/ ディレクトリにインストールします。OS のバージョン、種類にあわせ読み替えてください。


curl -O http://ftp.iij.ad.jp/pub/linux/centos/6.6/os/x86_64/Packages/centos-release-6-6.el6.centos.12.2.x86_64.rpm
sudo rpm --root=/srv --nodeps -ivh centos-release-*.x86_64.rpm
rm centos-release-*.x86_64.rpm


yum が使える環境を整え、/srv/ ディレクトリに yum をインストールします。URL、バージョン番号等は適宜書き換えてください。


cat << 'EOF' | sudo tee /srv/etc/yum.repos.d/tmp.repo
[tmp-base]
name=CentOS-6 - Base
baseurl=http://ftp.iij.ad.jp/pub/linux/centos/6.6/os/x86_64/
gpgcheck=1
gpgkey=http://ftp.iij.ad.jp/pub/linux/centos/RPM-GPG-KEY-CentOS-6
enabled=0
EOF
sudo yum -y --disablerepo=\* --enablerepo=tmp-base --installroot /srv install yum


後の作業で DNS サーバを参照する必要がある場合には、/etc/resolv.conf/srv/ ディレクトリにコピーしておきます。


sudo cp /etc/resolv.conf /srv/etc/


ここからの作業は、母体 (Amazon Linux) の yum ではなく、上でインストールした yum を利用して構築作業を進めます。
chroot します。


sudo chroot /srv


rpm のデータベースを再作成します。そのまま利用しようとするとエラーが発生してしまいます。修復するよりも、作り直す方がお手軽だと思います。先ほどインストールしたパッケージをもう一度インストールすれば齟齬もありません。


rm /var/lib/rpm/*
rm -rf /var/cache/yum
rpm --initdb


kernel パッケージをインストールする前に /etc/fstab を作成しておく必要があります。
ファイルシステムの UUID は適宜変更してかまいません。変更しなくても問題ありません。全部で3か所登場します。同じ値であればよいです。


cat << 'EOF' | tee /etc/fstab
UUID=73947a77-ddbe-4dc7-bd8f-3fe0bc840778 /     ext4    defaults        1 1
tmpfs                   /dev/shm                tmpfs   defaults        0 0
devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
sysfs                   /sys                    sysfs   defaults        0 0
proc                    /proc                   proc    defaults        0 0
EOF


必要なパッケージをインストールします。以下の例では、さきの「ami-13614b12」と同じ構成となるようにパッケージを選択しています。
あまり増やすと、後で OS イメージを入れ換える際にメモリが足りなくなることが想定されるので、ほどほどに。


yum install -y --disablerepo=\* --enablerepo=tmp-base yum centos-release \
 acl \
 acpid \
 attr \
 audit \
 authconfig \
 b43-openfwwf \
 cronie \
 dhclient \
 e2fsprogs \
 efibootmgr \
 fipscheck \
 grub \
 iptables-ipv6 \
 kernel \
 kernel-firmware \
 man \
 openssh-clients \
 openssh-server \
 passwd \
 pciutils \
 postfix \
 rootfiles \
 rsync \
 selinux-policy-targeted \
 sudo \
 system-config-firewall-tui \
 yum-presto
rpm -e gpg-pubkey
yum clean all


yum リポジトリの設定を変更します。
ここでは、「ami-13614b12」と同じ構成となる実行例を示します。


rm /etc/yum.repos.d/tmp.repo




パッケージに所属していない、anaconda インストーラが作成しているファイルを作っていきます。

OS 起動設定は以下の通りです。SELinux は無効化します。カーネルのバージョンに気を付けてください。全部で6か所に登場します。6.6 の最初のカーネルバージョンで記載しています。


cat << 'EOF' | tee /boot/grub/grub.conf
default=0
timeout=1
serial --unit=0 --speed=115200
terminal --timeout=1 serial console
title CentOS (2.6.32-504.el6.x86_64)
        root (hd0,0)
        kernel /boot/vmlinuz-2.6.32-504.el6.x86_64 ro root=UUID=73947a77-ddbe-4dc7-bd8f-3fe0bc840778 rd_NO_LUKS rd_NO_LVM rd_NO_MD rd_NO_DM crashkernel=auto SYSFONT=latarcyrheb-sun16 LANG=en_US.UTF-8 KEYBOARDTYPE=pc KEYTABLE=us console=ttyS0,115200 selinux=0
        initrd /boot/initramfs-2.6.32-504.el6.x86_64.img
EOF
ln -s grub.conf /boot/grub/menu.lst
ln -s /boot/grub/grub.conf /etc/grub.conf
cat << 'EOF' | tee /etc/sysconfig/grub
boot=/dev/xvda
forcelba=0
EOF
sed -i -e 's/^SELINUX=.*$/SELINUX=disabled/' /etc/sysconfig/selinux
cat << 'EOF' | tee /etc/sysconfig/kernel
UPDATEDEFAULT=yes
DEFAULTKERNEL=kernel
EOF


ネットワーク設定は以下の通りです。


cat << 'EOF' | tee /etc/dhcp/dhclient-eth0.conf
send vendor-class-identifier "anaconda-Linux 2.6.32-504.el6.x86_64 x86_64";
timeout 45;
EOF
cat << 'EOF' | tee /etc/dhcp/dhclient.conf
timeout 300
retry 60
EOF
cat << 'EOF' | tee /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
PEERDNS=yes
PERSISTENT_DHCLIENT=yes
NM_CONTROLLED=no
EOF
cat << 'EOF' | tee /etc/sysconfig/network
NETWORKING=yes
HOSTNAME=localhost.localdomain
NOZEROCONF=yes
NETWORKING_IPV6=no
IPV6INIT=no
IPV6_ROUTER=no
IPV6_AUTOCONF=no
IPV6FORWARDING=no
IPV6TO4INIT=no
IPV6_CONTROL_RADVD=no
IPV4_FAILURE_FATAL=yes
EOF


IPv6 は無効化しておきます。カーネルパラメータで無効化する方法 (http://wiki.centos.org/FAQ/CentOS6#head-d47139912868bcb9d754441ecb6a8a10d41781df) だと無効化できないケースがあるようなので、旧来通り ipv6 カーネルモジュールを読み込む際に無効化します。


chkconfig --del ip6tables
cat << 'EOF' | tee /etc/modprobe.d/disable-ipv6.conf
options ipv6 disable=1
EOF
#cat << 'EOF' | tee -a /etc/sysctl.conf
#
# Disable IPv6
#net.ipv6.conf.all.disable_ipv6 = 1
#net.ipv6.conf.default.disable_ipv6 = 1
#EOF
sed -i -e 's/^#AddressFamily .*$/AddressFamily inet/' /etc/ssh/sshd_config
sed -i -e 's/^inet_interfaces .*$/inet_interfaces = 127.0.0.1/' /etc/postfix/main.cf
sed -i -e '/^::1/d' /etc/hosts
#sed -i -e 's/^udp6/#udp6/' -e 's/^tcp6/#tcp6/' /etc/netconfig


root アカウントに ssh 公開鍵を登録します。EBS が大きく指定された場合の対応も入れておきます。
AWS に特化した設定です。


touch /root/firstrun
cat << 'EOF' | tee /etc/rc.d/rc.local
#!/bin/sh
#
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don't
# want to do the full Sys V style init stuff.

touch /var/lock/subsys/local

# set a random pass on first boot
if [ -f /root/firstrun ]; then
  dd if=/dev/urandom count=50|md5sum|passwd --stdin root
  passwd -l root

  fdisk -H 64 -S 32 /dev/xvda << 'EOF_'
d
n
p
1


p
w
EOF_

  rm /root/firstrun
  touch /root/firstrun2
  reboot
  exit
fi
if [ -f /root/firstrun2 ]; then
  resize2fs /dev/xvda1
  rm /root/firstrun2
fi

if [ ! -d /root/.ssh ]; then
  mkdir -m 0700 -p /root/.ssh
#  restorecon /root/.ssh
fi
# Get the root ssh key setup
ReTry=0
while [ ! -f /root/.ssh/authorized_keys ] && [ $ReTry -lt 10 ]; do
  sleep 2
  curl -f http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key > /root/.ssh/pubkey
  if [ $? -eq 0 ]; then
    mv /root/.ssh/pubkey /root/.ssh/authorized_keys
  fi
  ReTry=$[Retry+1]
done
rm -f /root/.ssh/pubkey
chmod 600 /root/.ssh/authorized_keys # && restorecon /root/.ssh/authorized_keys
EOF


ssh サーバの設定を変更します。root アカウントでパスワードによるログインを禁止します。
また、パスワード認証によるログインも禁止しておきます。


sed -i -e 's/^#PermitRootLogin .*$/PermitRootLogin without-password/' /etc/ssh/sshd_config
sed -i -e 's/^PasswordAuthentication .*$/PasswordAuthentication no/' /etc/ssh/sshd_config


ファイアウォールの設定を行います。ssh のみ通信を許可します。


cat << 'EOF' | tee /etc/sysconfig/system-config-firewall
# Configuration file for system-config-firewall
--enabled
--service=ssh
EOF
cat << 'EOF' | tee /etc/sysconfig/iptables
# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
EOF
cat << 'EOF' | tee /etc/sysconfig/ip6tables
# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p ipv6-icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp6-adm-prohibited
-A FORWARD -j REJECT --reject-with icmp6-adm-prohibited
COMMIT
EOF


AWS ではコンソールが利用できないので、起動する端末を1つにしておきます。firstboot サービスも起動しないように変更します。


sed -i -e 's/^ACTIVE_CONSOLES=.*$/ACTIVE_CONSOLES=/dev/tty1/' /etc/sysconfig/init
cat << 'EOF' | tee /etc/sysconfig/firstboot
RUN_FIRSTBOOT=NO
EOF


ロケール設定を行います。適宜読み替えてください。


cat << 'EOF' | tee /etc/sysconfig/i18n
LANG="en_US.UTF-8"
SYSFONT="latarcyrheb-sun16"
EOF
#cat << 'EOF' | tee /etc/sysconfig/i18n
#LANG="C"
#SYSFONT="latarcyrheb-sun16"
#EOF
#cat << 'EOF' | tee /etc/sysconfig/i18n
#LANG="ja_JP.UTF-8"
#SYSFONT="latarcyrheb-sun16"
#EOF

cat << 'EOF' | tee /etc/sysconfig/clock
ZONE="UTC"
EOF
rm -f /etc/localtime
cp -a /usr/share/zoneinfo/UTC /etc/localtime
#cat << 'EOF' | tee /etc/sysconfig/clock
#ZONE="Asia/Tokyo"
#EOF
#rm -f /etc/localtime
#cp -a /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

cat << 'EOF' | tee /etc/sysconfig/keyboard
KEYTABLE="us"
MODEL="pc105+inet"
LAYOUT="us"
KEYBOARDTYPE="pc"
EOF
#cat << 'EOF' | tee /etc/sysconfig/keyboard
#KEYTABLE="jp106"
#MODEL="jp106"
#LAYOUT="jp"
#KEYBOARDTYPE="pc"
#EOF


システム認証に必要なすべての構成ファイルを更新します。


authconfig --enableshadow --passalgo=sha512 --updateall


これで OS イメージが完成しました。
chroot から抜け出します。


exit


次に、Rescue モードでの起動を準備します。ここからは母体 (Amazon Linux) での操作となります。
AWS にはコンソールがないですが、anacondaRescue モードでは ssh サーバを起動することができます。
Rescue モードでログインできれば、OS を入れ換えるのは難しくありません。


sudo curl -o /boot/vmlinuz http://ftp.iij.ad.jp/pub/linux/centos/6.6/os/x86_64/isolinux/vmlinuz
sudo curl -o /boot/initrd.img http://ftp.iij.ad.jp/pub/linux/centos/6.6/os/x86_64/isolinux/initrd.img

cat << 'EOF' | sudo tee /boot/grub/grub.conf
default=0
timeout=1
hiddenmenu
serial --unit=0 --speed=115200
terminal --timeout=1 serial console
title Rescue
        root (hd0,0)
        kernel /boot/vmlinuz rescue repo=http://ftp.iij.ad.jp/pub/linux/centos/6.6/os/x86_64/ nomount ksdevice=eth0 ip=dhcp sshd=1 lang=en_US keymap=us console=ttyS0,115200 selinux=0
        initrd /boot/initrd.img
EOF


再起動して、root アカウントでログインします。パスワードなしでログインできます。


sudo reboot

ssh root@<server ip address>


root アカウントでパスワードなしでログイン可能な状態は危険なので、ssh デーモンを停止します。


kill -KILL $(ps -ef | grep [/]sbin/sshd | awk '{print $2}')


上で作成した OS イメージを /tmp/ に保存します。/tmp/ はメモリ上に領域が確保されています。


mkdir /mnt/sysimage
mount /dev/xvda1 /mnt/sysimage
cd /mnt/sysimage/srv
tar czvf /tmp/centos.tgz *
cd /
umount /mnt/sysimage


仮想 HDD を初期化し、上で保存した OS イメージを展開します。

※ 2014/11/7追記
初期パーティションサイズを 1024MB にしました。
必要に応じて拡大するか「1024」を空行に置き換える必要があります。


dd if=/dev/zero of=/dev/xvda bs=1M
fdisk -H 64 -S 32 /dev/xvda << 'EOF'
o
n
p
1

1024
p
w
EOF
mkfs.ext4 -L / -U 73947a77-ddbe-4dc7-bd8f-3fe0bc840778 /dev/xvda1
tune2fs -c 0 -i 0 /dev/xvda1
mount /dev/xvda1 /mnt/sysimage
cd /mnt/sysimage
tar xzvf /tmp/centos.tgz


grub を仮想 HDD にインストールします。


mount -t proc /proc /mnt/sysimage/proc
mount -t sysfs /sys /mnt/sysimage/sys
mount --bind /dev /mnt/sysimage/dev
chroot /mnt/sysimage

\cp /proc/mounts /etc/mtab

cat << 'EOF' | tee /boot/grub/device.map
(hd0)     /dev/xvda
EOF

grub-install /dev/xvda || :
expr: non-numeric argument
expr: non-numeric argument
The file /boot/grub/stage1 not read correctly.


途中で失敗します。Xen には対応していないようです。失敗した部分のみやり直します。


grub
Probing devices to guess BIOS drives. This may take a long time.


    GNU GRUB  version 0.97  (640K lower / 3072K upper memory)

 [ Minimal BASH-like line editing is supported.  For the first word, TAB
   lists possible command completions.  Anywhere else TAB lists the possible
   completions of a device/filename.]
grub> device (hd0) /dev/xvda
device (hd0) /dev/xvda
grub> root (hd0,0)
root (hd0,0)
 Filesystem type is ext2fs, partition type 0x83
grub> setup (hd0)
setup (hd0)
 Checking if "/boot/grub/stage1" exists... yes
 Checking if "/boot/grub/stage2" exists... yes
 Checking if "/boot/grub/e2fs_stage1_5" exists... yes
quit
 Running "embed /boot/grub/e2fs_stage1_5 (hd0)"...  27 sectors are embedded.
succeeded
 Running "install /boot/grub/stage1 (hd0) (hd0)1+27 p (hd0,0)/boot/grub/stage2 /boot/grub/grub.conf"... succeeded
Done.
grub> quit


念のため初期 RAM ディスクを作り直しておきます。


cd /boot
mkinitrd --force initramfs-2.6.32-504.el6.x86_64.img 2.6.32-504.el6.x86_64


chroot を抜け、仮想 HDD をアンマウントします。


exit

umount /mnt/sysimage/dev
umount /mnt/sysimage/sys
umount /mnt/sysimage/proc
cd /
umount /mnt/sysimage


AWS の管理コンソールから、インスタンスを停止し、AMI を作成します。

※ 2014/11/7 追記
インスタンスを停止する前に、1GB のボリュームを追加し、アタッチし、先頭1GB分をビットコピーし、スナップショットを作成し、AMI 化すれば、1GB の EBS でも、1TB の EBS でも対応可能となります。
①1GB の EBS ボリュームを作成します。
②このインスタンスに①のボリュームを /dev/sdf としてアタッチします。
③「fdisk -l」を実行し、追加したボリュームが /dev/xvdf として認識されていることを確認します。
④「dd if=/dev/xvda of=/dev/xvdf bs=1M; sync」を実行し、ビットコピーします。
⑤スナップショットを作成します。
⑥AMI を作成します。[Virtualization type] を「Hardware-assisted virtualization」に、[Root device name] を「/dev/xvda」に変更します。

自分専用のクリーンな CentOS6 が完成しました。

インスタンスを起動し、動作確認を行ってください。
この AMI を使って、元の大きさより大きい EBS を割り当てたインスタンスを作成しても全領域が使えることを確認してください。

0 件のコメント:

コメントを投稿