こんにちは!インサイトテクノロジーの松尾です。
本投稿では、追加でアタッチした EBS ボリュームをマウントする EC2 Image Builder のコンポーネントについて紹介します。対象OSはRHELです。
背景
EC2 Image Builderを使って自社アプリのイメージを作る際に、複数ボリュームをマウントしたイメージを作りたいケースもあると思います。一方、Nitro System 上に構築されたインスタンスでNVMeブロックデバイスとして公開されるEBS ボリュームは、ブート時のデバイスが応答する順序に基づいてデバイスノードが作成されるため、fstabの作成の自動化が面倒だったりします。
EBS は、シングルルート I/O 仮想化 (SR-IOV) を使用して、 NVMe仕様を使用して Nitro ベースのインスタンスにボリュームアタッチメントを提供します。これらのデバイスは、オペレーティングシステムの標準NVMeドライバーに依存しています。これらのドライバーは、通常、インスタンスのブート時にアタッチ済みのデバイスを検出し、そのデバイスがブロックデバイスマッピングでどのように指定されているかではなく、デバイスが応答する順序に基づいてデバイスノードを作成します。
EC2起動時にはデバイス名として "sdb" などと指定したのにも関わらず、EC2を起動してみたら "nvme1n1" などのデバイス名が割り振られて、しかも順番がバラバラだった、なんて経験をお持ちの方も多いと思います。
マッピングを行うシェルが Classmethod さんのブログに!!
まずデバイスの特定(指定したデバイス名 "sdb" などとNVMEのデバイス名 "nvme1n1" とのマッピング)を行うには、nvme-cli を使用する必要があります。このコマンドを使って確認するわけですが、なんと以下の投稿に、fstab の作成まで行ってくれるシェルが公開されていました。ブログでは解説がとても詳しく書いてあり、シェルで実施している内容も大変よく理解できます。素晴らしい!👏
マッピングの処理にはこちらのスクリプトを使うことにしましょう。
弊社のアプリケーションではOSのストレージに加え、追加のEBSボリュームが3つ必要ですので、以下のように定義します。
# マウントポイントのリストアップ
declare -A mount_points=(
# ["EBSボリュームに指定したデバイス名"]="マウントポイント"
["sdb"]="/mnt/piso-data"
["sdc"]="/mnt/piso-backup"
["sdd"]="/mnt/pg-wal"
)
EC2 Image Builder のコンポーネント
作成するコンポーネントでは以下のような流れで処理をすることになります。
※map-rhel-block-device.sh
は事前に作成してS3にアップロードしておく
- S3 からスクリプト(
map-rhel-block-device.sh
)をダウンロード - スクリプトに実行権限を付与
- スクリプトの実行
- スクリプトファイルの削除 (必要なら)
したがって、コンポーネントの定義としてはこんな感じでできそうなことがわかります。
name: MapRhelBlockDeviceEC2ImageBuilderComponentDocument
description: This is MapRhelBlockDevice EC2ImageBuilder Component document.
schemaVersion: 1.0
phases:
- name: build
steps:
- name: DownloadShell
action: S3Download
maxAttempts: 3
inputs:
- source: s3://my-image-builder-test-bucket/map-rhel-block-device.sh
destination: /tmp/map-rhel-block-device.sh
- name: MapRhelBlockDeviceStep
action: ExecuteBash
inputs:
commands:
- |
sudo dnf install nvme-cli -y
chmod 755 /tmp/map-rhel-block-device.sh
/tmp/map-rhel-block-device.sh
rm -r -f /tmp/map-rhel-block-device.sh
- name: validate
steps:
- name: MapRhelBlockDeviceStep
action: ExecuteBash
inputs:
commands:
- |
df -h
cat /etc/fstab
- name: test
steps:
- name: MapRhelBlockDeviceStep
action: ExecuteBash
inputs:
commands:
- df -h
このコンポーネントの定義を使用して、コンポーネントを登録します。
なお、エラーについては、現時点では何も勘案していないため、例えば、"sdb" などが定義されていなかった場合の挙動を決めて定義する必要があります。
レシピの作成とパイプラインの実行
事前に s3://my-image-builder-test-bucket/map-rhel-block-device.sh
からスクリプトを入手可能に設定します。また、実際のビルドプロセスにおいてS3からファイルダウンロードができるよう EC2InstanceProfileForImageBuilder
ロールにS3の読み取り権限を追加します。
そして定義したコンポーネントを使ってレシピを定義し実行してみましょう。
実行結果としては AMI が作成されますので、AMIからEC2インスタンスを起動して確認すると、期待通りマウントされていることを確認できます。
[ec2-user@ip-172-31-32-120 ~]$ df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 3.7G 0 3.7G 0% /dev
tmpfs 3.7G 0 3.7G 0% /dev/shm
tmpfs 3.7G 17M 3.7G 1% /run
tmpfs 3.7G 0 3.7G 0% /sys/fs/cgroup
/dev/nvme0n1p3 9.8G 2.9G 7.0G 30% /
/dev/nvme3n1 3.0G 54M 3.0G 2% /mnt/pg-wal
/dev/nvme1n1 1014M 40M 975M 4% /mnt/piso-data
/dev/nvme2n1 2.0G 47M 2.0G 3% /mnt/piso-backup
/dev/nvme0n1p2 200M 5.8M 194M 3% /boot/efi
tmpfs 758M 0 758M 0% /run/user/1000
[ec2-user@ip-172-31-32-120 ~]$ cat /etc/fstab
UUID=9fbfebad-ad19-4692-86f0-696c37b6c4ab / xfs defaults 0 0
UUID=7B77-95E7 /boot/efi vfat defaults,uid=0,gid=0,umask=077,shortname=winnt 0 2
UUID=224aac8b-653d-4a33-bdcf-449d799784c2 /mnt/piso-data xfs defaults 0 0
UUID=93cbad8f-b486-455f-9f91-b2e6e124525a /mnt/piso-backup xfs defaults 0 0
UUID=de157a04-99d6-4a47-b498-28e10a1a95ec /mnt/pg-wal xfs defaults 0 0
おわりに
本投稿では、nvmeデバイス名と指定したデバイス名とのマッピングスクリプトをEC2 Image Builderから使用することで、EC2 Image Builderで追加ボリュームがある際のマウントとfstabの追記を行うコンポーネントを紹介しました。
本投稿が何かのヒントになれば幸いです。