【VyOS】LTS ISO作成＆AWSカスタムAMI作成手順


# 概要
## VyOSとは
VyOSはオープンソースで開発されているDebianベースのソフトウェアルータであり、基本的には無償で使用できる。有償版としてLTS版イメージ＆サポートが提供されており商用利用も可能。

## 一般的な話（VMware等での利用）
VyOSは以下からnightlyリリースのISOを無償ダウンロードすることもできるが、安定板のLTSリリースは公式サイトでは無償ダウンロード提供されていない。
参考：[VyOS：Nightly Build](https://vyos.net/get/nightly-builds/)

ただし、VyOSのソースはGithubで公開されており、そのビルド方法も提供されているため、自分でビルドすれば無償でLTSリリースのISOを入手できる。
参考：[GitHub：vyos/vyos-build](https://github.com/vyos/vyos-build)

また、ビルドのための環境としてDocker環境が提供されており、最も簡単にビルド環境を用意することができる。

## AWS利用の話
AWSではそもそもISOからのEC2作成に対応しておらず、AWS独自のAMIからのみEC2を立ち上げられる。
マーケットプレイスにVyOS1.3.0が存在するが、2022年4月現在LTSリリースで最新の1.3.1は存在しない。また、サポート込みの有償版のみ提供されており、AMIとして無償版は存在しない。バージョンが古ければコミュニティAMIも存在するようだが、LTSリリースなのかどうか不明（そもそも信頼性が低い）。

一般に、ISOからのAMI作成方法としてAWS CLIの"vmimport"機能によって.ova形式（VirtualBox）、.vmdk形式（VMware）、raw形式からAMIを作成することができる。
参考：[cocone/engineering/blog：VMware 仮想マシンを Amazon EC2 にインポートした話](https://engineering.cocone.io/2021/01/26/vmware/)

しかし、対応OSが限定されており、VyOS1.3系およびVyOS1.3系のベースとなっているDebian10は2022年4月現在"vmimport"機能の対象外となっている。そのためVyOS1.3系を"vmimport"機能でAMI化することは不可能。
※vmimport時にサポート対象外という旨のエラーで失敗する。これはVMware上でvmimport対応のDebian8などに設定していたとしても変わらず失敗するため、中身を見て判断していると思われる。
参考：[AWS：VM Import/Export の要件](https://docs.aws.amazon.com/ja_jp/vm-import/latest/userguide/vmie_prereqs.html)

VyOSでは公式から"vmimport"を使わないISOからのAMI化のためのAnsible PlaybookをGithub公開しており、今回はそちらを利用した。

# ISO作成手順
## 参考
[インフラエンジニアのメモ帳：VyOS 1.3 LTS ISOイメージ作成手順](https://server-network-note.net/2021/12/vyos-1-3-lts-iso-make/)

## 実行環境
- Ubuntu 20.04
- Docker、gitインストール済みの前提

## 手順
### VyOSビルドスクリプト用意
2022年4月現在の最新LTSリリースは1.3.1のため1.3系の"equuleus"を指定してクローンしてくる。
```bash=
git clone -b equuleus --single-branch https://github.com/vyos/vyos-build
cd vyos-build/
```

### ISOビルド用Docker起動
DocukerHub からコンテナをダウンロード。
```bash
docker pull vyos/vyos-build:equuleus
docker run --rm -it --privileged -v $(pwd):/vyos -w /vyos --sysctl net.ipv6.conf.lo.disable_ipv6=0  -e GOSU_UID=$(id -u) -e GOSU_GID=$(id -g) vyos/vyos-build:equuleus bash
```

### ISOビルド用Dockerでのビルド
バージョン指定を"1.3.1"としてビルドする。なお"1.3.0"とすることもできるが、1.2、1.4等メインバージョンが異なる場合はスクリプトが異なるので不可。
```bash
./configure --architecture amd64 --build-type release --version 1.3.1
sudo make AWS
```
※最後のコマンドは`sudo make iso`とすれば、VMware等用のISOが作成されるが、AWSのオートコンフィギュレーションメカニズム（SSHキーの組み込み、NICへのDHCP設定等＋python boto3）に対応していない。`sudo make AWS`とすると上記メカニズムが組み込まれたISOが作成される（インストーラ起動時にboto3によるAWS VPC内で実行する処理が組み込まれているため、VMware上などオンプレでは起動できない）

実行が完了するとbuildディレクトリにISOが作成されている。 
```bash
build/vyos-1.3.1-amd64.iso
```
docner run 時に-v オプションによりホスト側とマウントしているため、以降はDockerホスト側でこのISOを扱うことができる。

# AMI作成
## 参考
[GitHub:vyos/build-ami](https://github.com/vyos/build-ami)

## Ansible Playbookでの実行内容
ざっくり以下の通り。
※/build-ami/playbooks/roles/<各手順>/tasks/main.ymlより
1. provision-ec2-instance
SSHキーの作成等準備後、AMI作成用EC2インスタンス等AWS環境構築
2. build-disk
ISOからデータ抽出＆空のEBSにコピーすることで起動ディスク作成（インストールと同等）
3. build-vyos-ami
起動ディスクからAMI作成
4. ec2-cleanup
クリーンアップ（AMI作成用AWS環境削除）

なお、AMI作成のためのAWS環境、AMIは「バージニア北部リージョン：us-east-1」に作成されるため注意。
作成後、任意のリージョンにAMIコピーを行う。

## 実行環境
- Ubuntu 20.04
- Python3 & pip3利用可能

※ISO作成時と同じ環境で良い
※build-amiのREADME.mdにはPython3のansibleは記載時点でAnsible公式サポートがないのでpython2.7使用を推奨とのことだがPython3でも問題なかった（むしろなぜか自環境ではPython2.7で失敗した）。

## 手順
### 必要ソフトウェアインストール
boto3, awscli, ansibleのインストールをpipから行う。
```bash
sudo pip3 install boto　botocore boto3
sudo pip3 install awscli
sudo pip3 install ansible
```
※awscli, ansibleに関してはaptから行うこともできるが、相性の問題なのか原因は不明だが手元の環境では後のAMI作成Playbook実行時にエラーが発生した。対処法を調べていたところaptのansibleにはバグがあるような旨の投稿があり、aptでインストールしたものをremove後、pipから再インストールして解消した。awscliは原因不明だが上記作業中にエラーを吐くようになり、同様にpipから再インストールしたところ解消した。

### AWS CLIのセットアップ
デフォルトプロファイルとしてIAMユーザ（アクセスキー - プログラムによるアクセス）を設定しておく。
問題がなければ「AdministratorAccess」ポリシーを持つグループに所属させておくと後々権限周りでの変な引っかかりはないかと思うが、必要に応じて適切にポリシーを用意すること。
```bash
aws configure
```
```
AWS Access Key ID [None]: <アクセスキー>
AWS Secret Access Key [None]: <シークレットアクセスキー>
Default region name [None]: ap-northeast-1
Default output format [None]: json
```

### pythonのシンボリックリンク作成
手元のUbuntu20.04では`/usr/bin/python3`が存在するが`/usr/bin/python`としてのシンボリックリンクは存在しなかった。
Ansible Playbook中にコマンドとして`python`を実行できる必要があるため、シンボリックリンクを作成する。
```bash
ln -s /usr/bin/python3 /usr/bin/python
```

### ISOダウンロードURLの用意
Ansible Playbook中でインストールを行うISOをURL指定する必要があるため準備。
今回は一時的にパブリックなS3バケットを用意して「ISO作成手順」にて作成した`vyos-1.3.1-amd64.iso`を配置、ダウンロード可能な状態とし、AMI化完了後バケットごと削除した。
参考：[てっくTech：AWS S3のアクセスを公開にする](https://tech-tech.blog/aws/s3-public/)
※上記URLにアクセスするのはAMI作成用EC2インスタンスからとなる。動的にパブリックIPが振られるためS3へのIPアドレス制限をかける場合はAWSのIPレンジを調べてかけること。

### AMI作成用Ansible Playbookの用意
Githubからクローンしてくる。
```bash
git clone https://github.com/vyos/build-ami.git
cd build-ami
```
### Ansible Playbookの実行
Ansible Playbookで`sudo`を利用しているらしくパスワードが求められるとエラーになる。
適当に`sudo`を使用して一定期間パスワードが求められないようにしておくことで回避。
```bash
sudo ls
```

以下でPlaybookを実行。最後まで完了すれば「us-east-1」にAMIが登録されている。
```bash
./vyos-build-ami <VyOS ISO URL>
```

__※注意__
Playbookが途中で失敗した場合、「us-east-1」に以下が残ってしまう。

- EC2 t2.microインスタンス
- "vyos-build-ami"という名前のSSHキーペア
- "vyos-build-ami"という名前のセキュリティグループ

再度Playbookを実行するためには上記が削除されている必要があるため、AWSコンソールから手動で削除すること。
（EC2に関しては課金対象なのでうまくいかず途中で諦める場合でも必ず削除してからにすること）

### AMIリージョン間コピー
EC2を作成するリージョンにAMIをコピーして完成。
参考：[AWS：User Guide for Linux Instances - Copy an AMI](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/CopyingAMIs.html#ami-copy-steps)

1. AWSコンソールのAMIから作成したAMIの詳細画面に遷移
2. 「アクション」から「AMIをコピー」を押下
3. 「AMI コピー名」、「AMI コピーの説明」を適当に入力した後、「送信先リージョン」でEC2作成予定のリージョンを選択して「AMIをコピー」を押下
4. 数秒程度でリージョン間AMIコピーが完了

# 【備考】
VyOSでは運良くAMI化の手段が提供されていたのでよかったが、AMI化の手段が提供されていない他のOSの場合はどうなるか気になり調べて見たが、ほとんど情報がない（AWSへのマイグレなどポピュラーな話題だと思っていたので意外。調べ方が悪い？）。
唯一参考になる記事が見つかったため、備考として残す。
参考：[SKYARCH BROADCASTING：RHEL8 Beta AMI を作ってみた](https://www.skyarch.net/blog/?p=15606)

自己解釈&未検証だが簡単に手順のポイントを書き出すと、

1. VMwareやKVM等からVMのイメージをエクスポートする
2. 何かしらの方法でAMI作成用インスタンスに「1.」をコピーする
3. `qemu-img`でraw形式に変換する
4. AMI作成用インスタンスに追加のEBSをアタッチ、マウントする
5. `dd`でraw形式のイメージを追加EBSに書き込む
6. EBSに書き込んだ結果、各パーティションが見えるのでroot, boot, sys, dev, proc等必要な領域をマウント（起動時の構成に合わせてディレクトリ構造を合わせる）
7. `chroot`で「6.」の環境に入る（入獄）
8. `dracut`で初期RAMを再構築⇨ここまででAMI用EBS作成完了
9. `aws ec2 register-image`でEBSをAMI化