NetBSD/amd64-currentをAmazon Web Service EC2 c5インスタンスで動かしてみる

この記事は、 NetBSD Advent Calendar 2018の23日目の記事です。

はじめに

もう1年以上前の話だと思うのですが、Amazon Web Service (AWS) EC2にc5という Linux KVMをAmazonが独自拡張したと言うインスタンスのタイプが追加されました。 その後、同じような仕組みのm5インスタンスと言うもの追加されているようです。 c5インスタンスでは、Elastic Network Adapter (ENA)と言うEthernetアダプター を利用できることが必須になっているようです。 NetBSD/aarch64では、a1インスタンスでena(4)がFreeBSDから移植されていて 無事に動いていますが、 c5インスタンスでのNetBSD/amd64の動作確認結果は聞いたことはありませんでした。

そもそもc5インスタンスで起動できるAMIの作り方も良く分かりませんでした。 今回は、カーネルパニックでena(4)は動かせるまで至りませんでしたが、 c5インスタンス用のAMIの作成をまとめておくことは意味があるかもしれません。

AMIファイルの作り方を調べてみる

AWS EC2のAMIは、直接ダウンロードしてみることはできないようです。 裏にはスナップショットと言うものがあるようですが、Amazonが公開している Amazon LinuxのAMI用のスナップショットを見ることはできないようです。

今回は、FreeBSD/amd64 12のAMIからc5インスタンスを作成し、そのディスクの 構造を見てみました。それを見ると、NetBSDで言うと、GPTパーティションからの BIOSブート(UEFIブートではない)であることが分かりました。 かつて、UEFIブートができないことにGPTを使っていたやり方を思い出せば良さそうです。

ここで、カーネルは、

ena*    at pci? dev ? function ?        # Amazon Elastic Network Adapter
の行をGENERIC設定ファイルに追加した追加したGENERIC_ENA設定ファイルでビルドします。
; 3GBのディスクイメージファイルを作成します
$ dd if=/dev/zero of=./netbsd-c5-gpt-bios-boot.img bs=1g count=3
; vnd(4)を使ってブロックデバイスとして扱えるようにします。
# vndconfig vnd0 netbsd-c5-gpt-bios-boot.img
; GPTパーティションを作る準備をします
# gpt create vnd0
; 2GBのルートパーティションを作成します。私の場合には/dev/dk5として扱えるようになります。
# gpt add -s 2g -t ffs -l AWSROOT vnd0
; 1GBのスワップパーティションを作成します。私の場合には/dev/dk6として扱えるようになります。
# gpt add -t swap -l AWSSWAP vnd0
; ルートパーティションからBIOSブートするように設定します。
# gpt biosboot -A -i 1 vnd0
; ルートパーティションをFFSv2でフォーマットします。
# newfs -O2 /dev/rdk5
; FFSv2で起動できるようにブートローダーを配置します。
# installboot -v /dev/rdk5 /usr/mdec/bootxx_ffsv2
; ユーザーランドをインストールするために/mntにマウントします。
# mount /dev/dk5 /mnt
# cd /usr/src ; 以下でユーザーランドをビルドします。
# ./build.sh -U -O /usr/world/8.99/amd64/obj -T /usr/world/8.99/amd64/tools -D /usr/world/8.99/amd64/destdir -R /usr/world/8.99/amd64/release -u -j 8 -m amd64 tools
# ./build.sh -U -O /usr/world/8.99/amd64/obj -T /usr/world/8.99/amd64/tools -D /usr/world/8.99/amd64/destdir -R /usr/world/8.99/amd64/release -u -j 8 -m amd64 kernel=GENERIC_ENA
# ./build.sh -U -O /usr/world/8.99/amd64/obj -T /usr/world/8.99/amd64/tools -D /usr/world/8.99/amd64/destdir -R /usr/world/8.99/amd64/release -u -j 8 -m amd64 distribution
; ユーザーランドを/mntをルートにしてインストールします。
# ./build.sh -U -O /usr/world/8.99/amd64/obj -T /usr/world/8.99/amd64/tools -D /usr/world/8.99/amd64/destdir -R /usr/world/8.99/amd64/release -u -j 8 -m amd64 -V INSTALLSETS="base comp etc games man misc modules tests text" install=/mnt
; ブートローダーをインストールします。
# cp /usr/mdec/boot /mnt
; カーネルをインストールします (ena(4)が有効になっているカーネルをインストールします)
# cp /usr/world/8.99/amd64/obj/sys/arch/amd64/compile/GENERIC_ENA/netbsd /mnt
; AWS EC2の公開鍵の配置のためのスクリプトを追加します。
# vi /mnt/etc/rc.d/ec2_init
/etc/rc.d/ec2_initは、NetBSD Wikiの Build-up your own NetBSD AMIのウェブページにある以下のような内容です。
#!/bin/sh
#
# PROVIDE: ec2_init
# REQUIRE: NETWORKING
# BEFORE:  LOGIN

$_rc_subr_loaded . /etc/rc.subr

name="ec2_init"
rcvar=${name}
start_cmd="ec2_init"
stop_cmd=":"

METADATA_URL="http://169.254.169.254/latest/meta-data/"
SSH_KEY_URL="public-keys/0/openssh-key"
HOSTNAME_URL="hostname"

SSH_KEY_FILE="/root/.ssh/authorized_keys"

ec2_init()
{
        (
        umask 022
        # fetch the key pair from Amazon Web Services
        EC2_SSH_KEY=$(ftp -o - "${METADATA_URL}${SSH_KEY_URL}")

        if [ -n "$EC2_SSH_KEY" ]; then
                # A key pair is associated with this instance, add it
                # to root 'authorized_keys' file
                mkdir -p $(dirname "$SSH_KEY_FILE")
                touch "$SSH_KEY_FILE"
                cd $(dirname "$SSH_KEY_FILE")

                grep -q "$EC2_SSH_KEY" "$SSH_KEY_FILE"
                if [ $? -ne 0 ]; then
                        echo "Setting EC2 SSH key pair: ${EC2_SSH_KEY##* }"
                        echo "$EC2_SSH_KEY" >> "$SSH_KEY_FILE"
                fi
        fi

        # set hostname
        HOSTNAME=$(ftp -o - "${METADATA_URL}${HOSTNAME_URL}")
        echo "Setting EC2 hostname: ${HOSTNAME}"
        echo "$HOSTNAME" > /etc/myname
        hostname "$HOSTNAME"
        )
}

load_rc_config $name
run_rc_command "$1"
; 実行可能に設定します。
# chmod 555 /mnt/etc/rc.d/ec2_init
; 起動時の設定をします。
# vi /mnt/etc/rc.conf
rc_configured=YES
ec2_init=YES
sshd=YES # for remote shell access to instance
; rootユーザーでログインできるようにします。
# vi /mnt/etc/ssh/sshd_config
PermitRootLogin without-password
; 以下でファイルシステムの設定をします。
# mkdir /mnt/proc /mnt/kern
# vi /mnt/etc/ifconfig.ena0
dhcp
# vi /mnt/etc/fstab
NAME=AWSROOT    /               ffs     rw,log  1 1
NAME=AWSSWAP    none            swap    sw,dp   0 0
kernfs          /kern           kernfs  rw
ptyfs           /dev/pts        ptyfs   rw
procfs          /proc           procfs  rw
tmpfs           /var/shm        tmpfs   rw,-m1777,-sram%25
; /dev以下のノードを作成します。
# cd /mnt/dev
# ./MAKEDEV all
; vnd0を開放します。
# cd ~
# umount /mnt
# vndconfig -u vnd0
これで、ディスクイメージファイルは完成です。 以下で、AMIファイルを作成して行きます。

AMIファイルの作成は、Elastic Block Store (EBS)でディスクを割り当てし、 そのディスクにローカルで作成したディスクイメージを書き込み、 そのスナップショットをとってAMIを作成します。 操作は、Pythonで書かれたawsコマンドを使います。

; pkgsrcからawsコマンドをインストールします。
# cd /usr/pkgsrc/net/py-awscli
# make install

; AWSの認証のための情報と、使用するリージョンの情報、実行結果の表示方法を設定します、
$ aws configure
AWS Access Key ID [None]: XXX
AWS Secret Access Key [None]: XXX
Default region name [None]: us-east-1
Default output format [None]: text

; 既にあるsshの鍵ペアを使って、Amazon Linux 2のHVMのAMIを使ってc5.largeインスタンスを起動させます、
$ aws ec2 run-instances --image-id ami-009d6802948d06e52 --instance-type c5.large --key-name c5-20181220
619017845909    r-0dab8fafc6dbc2a6c
INSTANCES       0       x86_64          False   xen     ami-009d6802948d06e52  i-01dfee86f4d0d109d      c5.large        c5-20181220     2018-12-21T13:41:14.000Z
        ip-172-31-38-245.ec2.internal   172.31.38.245           /dev/xvda      ebs      True            subnet-73de462f hvm     vpc-d459f1ae
CPUOPTIONS      1       2
MONITORING      disabled
NETWORKINTERFACES               0e:de:7c:89:d3:a2       eni-0a38d352461629255  619017845909     ip-172-31-38-245.ec2.internal   172.31.38.245   True    in-use subnet-73de462f  vpc-d459f1ae
ATTACHMENT      2018-12-21T13:41:14.000Z        eni-attach-09acc70fb71f4bd95   True     0       attaching
GROUPS  sg-1d45925e     default
PRIVATEIPADDRESSES      True    ip-172-31-38-245.ec2.internal   172.31.38.245
PLACEMENT       us-east-1d              default
SECURITYGROUPS  sg-1d45925e     default
STATE   0       pending
STATEREASON     pending pending
; これで、i-01dfee86f4d0d109dというインスタンスIDのc5.largeインスタンスが起動されました、

; 起動完了してrunningステータスになっているか確認します。
$ aws ec2 describe-instances --instance-ids i-01dfee86f4d0d109d
ESERVATIONS    619017845909    r-0dab8fafc6dbc2a6c
INSTANCES       0       x86_64          False   True    xen     ami-009d6802948d06e52   i-01dfee86f4d0d109d     c5.large        c5-20181220     2018-12-21T13:41:14.000Z        ip-172-31-38-245.ec2.internal   172.31.38.245   ec2-34-229-210-170.compute-1.amazonaws.com      34.229.210.170  /dev/xvda       ebs     True   subnet-73de462f  hvm     vpc-d459f1ae
BLOCKDEVICEMAPPINGS     /dev/xvda
EBS     2018-12-21T13:41:15.000Z        True    attached        vol-029d14d5198ee2174
CPUOPTIONS      1       2
HIBERNATIONOPTIONS      False
MONITORING      disabled
NETWORKINTERFACES               0e:de:7c:89:d3:a2       eni-0a38d352461629255  619017845909     ip-172-31-38-245.ec2.internal   172.31.38.245   True    in-use subnet-73de462f  vpc-d459f1ae
ASSOCIATION     amazon  ec2-34-229-210-170.compute-1.amazonaws.com      34.229.210.170
ATTACHMENT      2018-12-21T13:41:14.000Z        eni-attach-09acc70fb71f4bd95   True     0       attached
GROUPS  sg-1d45925e     default
PRIVATEIPADDRESSES      True    ip-172-31-38-245.ec2.internal   172.31.38.245
ASSOCIATION     amazon  ec2-34-229-210-170.compute-1.amazonaws.com      34.229.210.170
PLACEMENT       us-east-1d              default
SECURITYGROUPS  sg-1d45925e     default
STATE   16      running
; runningステータスになっていることを確認して次に進みます。

; 3GBのstandardタイプ(磁気ハードディスクドライブ)のEBSボリュームを作成します、
$ aws ec2 create-volume --availability-zone us-east-1d --volume-type standard --size 3

; 作成したEBSボリュームの内容を確認します、
$ aws ec2 describe-volumes --volume-ids vol-076f8c399f56e6753
VOLUMES us-east-1d      2018-12-21T13:44:05.665Z        False   3              available        vol-076f8c399f56e6753   standard

; Amazon Linux 2のインスタンスに作成したEBSボリュームを接続します。
$ aws ec2 attach-volume --instance-id i-01dfee86f4d0d109d --volume-id vol-076f8c399f56e6753 --device "/dev/sdf"
2018-12-21T13:46:15.709Z        /dev/sdf        i-01dfee86f4d0d109d     attaching       vol-076f8c399f56e6753

; 接続できたことを確認します。
$ aws ec2 describe-volumes --volume-ids vol-076f8c399f56e6753
VOLUMES us-east-1d      2018-12-21T13:44:05.665Z        False   3              in-use   vol-076f8c399f56e6753   standard
ATTACHMENTS     2018-12-21T13:46:15.000Z        False   /dev/sdf        i-01dfee86f4d0d109d     attached        vol-076f8c399f56e6753

; もし、送信側セキュリティー設定(ポートごとの通過できる通信の設定)を実施します。
$ aws ec2 authorize-security-group-egress --group-id sg-1d45925e --port 22 --protocol all

; 受信側のセキュリティー設定を実施します。
$ aws ec2 authorize-security-group-ingress --group-id sg-1d45925e --port 22 --protocol all --cidr 0.0.0.0/0

; Amazon Linux 2のディスク領域にディスクイメージファイルを転送します。
$ scp -i c5-20181220.pem netbsd-c5-gpt-bios-boot.img ec2-user@ec2-34-229-210-170.compute-1.amazonaws.com:~/

; sshでAmazon Linux 2にログインします。
$ ssh -i c5-20181220.pem ec2-user@ec2-34-229-210-170.compute-1.amazonaws.com

; 接続したEBSボリュームにディスクイメージファイルを書き込みます。これがスナップショットになり、AMIになります。
[ec2-user@ip-172-31-38-245 ~]$ sudo dd if=netbsd-c5-gpt-bios-boot.img of=/dev/sdf bs=64k

; /dev/sdfに接続したEBSボリュームを取り外します。
$ aws ec2 detach-volume --volume-id vol-076f8c399f56e6753
2018-12-21T13:46:15.000Z        /dev/sdf        i-01dfee86f4d0d109d     detaching       vol-076f8c399f56e6753

; 取り外したEBSボリュームのスナップショットを取得します。これにはしばらく時間がかかります。
$ aws ec2 create-snapshot --volume-id vol-076f8c399f56e6753
        False   619017845909            snap-04eb837b14f764a00  2018-12-21T14:06:20.000Z        pending vol-076f8c399f56e6753   3

; Amazon Linux 2のインスタンスを消します。
$ aws ec2 terminate-instances --instance-ids i-01dfee86f4d0d109d
TERMINATINGINSTANCES    i-01dfee86f4d0d109d
CURRENTSTATE    32      shutting-down
PREVIOUSSTATE   16      running

; スナップショットを使ってAMIを作成します。
$ aws ec2 register-image --architecture x86_64 --name "NetBSD/amd64 8.99.28 with ena" --ena-support --virtualization-type hvm --block-device-mappings 'DeviceName=/dev/sda1,Ebs={SnapshotId=snap-04eb837b14f764a00}' --root-device-name "/dev/sda1"
ami-088a6d6fc2dccd87b
; これで、ami-088a6d6fc2dccd87bというIDのAMIが作成されました。ENAが有効で、c5.largeインスタンスに使えるように仮想化タイプもhvmにしました。
このAMIを使ってc5.largeインスタンスを起動させてみます。

NetBSD/amd64-currentの起動

ami-088a6d6fc2dccd87bを使って、c5.largeインスタンスを作成することで、 NetBSD/amd64-currentを起動させることができます。 起動したら、AWS ConsoleからInstanceを選び、起動させたインスタンスのInstance Settings よりGet Instance Screenshotを選びます。 残念ながらMSI-X割り込みの関係でエラーになってカーネルパニックしてしまっています。

AWS EC2は、sshでログインできないと何もできませんので、 ディスクイメージファイルのカーネルファイル/netbsdを差し替えて アップロードしてEBSボリュームに書き込むのを繰り返してデバッグするしかなさそうです。

Comments

Popular posts from this blog

PostgreSQLのOracle Foreign Data WrapperをWindowsで使う

Oracle OLEDB Provider Version 12.2.0.1.0 for Windows x86をインストールする際のエラー