この記事は、 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ボリュームに書き込むのを繰り返してデバッグするしかなさそうです。