こんにちは!
コンストラクションソリューション事業部 開発部の藤井です。初投稿となります。
弊社ではAWSを用いた案件が多く、私の所属部署でも、AWS用語が解説無しで普通に飛び交います。
私は昨年9月にエコモットへ入社するまでAWS経験歴は無く、最初のころは正直いって焦りました。ですが、社内勉強会などに誘ってもらい参加したり、業務で実際に使ったりしているうちに慣れ、いまは少し世界が広がったように思います。
この記事では、先日、Nitro なEC2でEBSをマウントする際に起きた小さな小さな問題解決までの流れをまとめます。AWSに振り回される業務風景として眺めていただけると幸いです。
◇きっかけ
先日 Linux のEC2インスタンスを新規構築中に、EBSをマウントしようとしてAWS公式ドキュメントを調べているとき、例示コマンドが2種類あることに気が付きました。
1 |
sudo lsblk -o +UUID |
1 |
sudo nvme id-ctrl -v /dev/nvme1n1 |
今回の構築対象は、 T3a ファミリのインスタンスで、 Ubuntu20.04LTS です。
実際に端末で試してみると、前者の lsblk でも構築時に指定したデバイス名
1 |
/dev/xvda |
ではなく、 /dev/nvme1n1 という見慣れないものが表示されました。なんだこれは……。
◇わかったこと
さらに公式ドキュメント『 Linux インスタンスの Amazon EBS および NVMe 』をたどると、2017年以降の比較的新しい Nitro System (公式動画によると発音はニトロじゃなくてナイトロ)なインスタンスの場合に、
1 |
NVMe デバイス名 ( /dev/nvme[0-26]n1 ) |
になることが判明しました。この記事からリンクされている『Nitro System 上に構築されたインスタンス』にインスタンスタイプ一覧があり、T3aも含まれています。なるほど!
◇検討と解決
ここから、マウントテーブル /etc/fstab に定義を書いて mount -a コマンドでマウントする、というよくあるゴールを目指します。いくつかの方法について仲間と社内チャットで検討しました。
方法1 シンプルなやり方
lsblk などOS側から見えるデバイス名(今回なら /dev/nvme1n1 ) を fstab で直接指定する方法です。
1 2 3 |
# /etc/fstab に以下を追記する? /dev/nvme1n1 /mnt/xvda ext4 defaults,nofail 0 0 |
上記AWS公式ドキュメントでは非推奨として書かれており、今回は見送りになりました。
方法2 UUIDを指定する
上述のきっかけの部分に書いた、公式ドキュメント推奨のコマンドで UUID を先に調べて、それを fstab に追記する方法です。
が、よく考えるとEBS1つならこれで良いのですが、複数あるときは引き当てが面倒です。それによく考えると、上記の
1 |
sudo nvme id-ctrl -v /dev/nvme1n1 |
を使う場合にしても、事前にどれになるか不定なはずの引数( /dev/nvme[0-26]n1 )を指定しているので、ちょっと矛盾しているようにも思います。
/dev をループ処理で調べるしかないのでしょうか。上記の NVMe の解説には、
Amazon Linux はブロックデバイスマッピング (たとえば、/dev/sdf )内のデバイス名から NVMe デバイス名へのシンボリックリンクを作成します
との記載があるのですが、今回は Ubuntu なので自力でやるしかありません。
方法3 車輪を探す
nvme id-ctrl でループして目的のデバイス名を探すスクリプトを作る前に、絶対に誰か既にやってるだろうと検索すると、案の定公開してくださってる方がすでにおられました。
https://github.com/transferwise/ansible-ebs-automatic-nvme-mapping
この ebs-nvme-mapping.sh を流せば、(再起動するまで一時的ですが)Amazon Linux のように NVMe デバイス名へのシンボリックリンクが作られます。
そこからお目当てのデバイスだけ、UUID を wipefs コマンドを使ってデバイス名から一本釣りします。
1 |
wipefs -i /dev/xvda -O UUID |
その結果を /etc/fstab マウントテーブルへ UUID 指定で追記することで、無事ゴールできました。
1 2 3 |
# /etc/fstab 目指す形 UUID="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" /mnt/xvda ext4 defaults,nofail 0 0 |
再起動後でも UUID だけあれば大丈夫です。
おまけ1 EC2 のUser data
参考までに、構築時のUser dataから該当箇所だけ転記します。
※実際は CloudFormation のテンプレートファイルで指定していました。AWS マネジメントコンソールで構築する際は、ユーザーデーター欄に入れてください。この直前で s3 に配置したセットアップスクリプト群をコピーしており、ebs-nvme-mapping.sh もそこに入れて事前に配置していたので下記なのですが、もし S3 など使ってファイルを配置するのが面倒なら、直接 sh の for 以下を埋め込んでください。
※構築後に流す場合はそれぞれコマンドごとに sudo してください。
1 2 3 4 5 |
./ebs-nvme-mapping.sh mkfs.ext4 /dev/xvda mkdir /mnt/xvda echo -e "UUID=$(wipefs -i /dev/xvda -O UUID)\t/mnt/xvda\text4\tdefaults\t0\t0" | tee -a /etc/fstab mount -a |
おまけ2
この件で人生で初めて wipefs を使いました。
上記のスクリプトで欲しいのは UUID だけなので、ヘッダ行省略の noheadings のようなオプションがあるだろうと man wipefs しました。
1 2 3 4 5 6 7 8 9 10 11 |
$ man wipefs | grep -n5 'noheadings' 43- Display help text and exit. 44- 45- -J, --json 46- Use JSON output format. 47- 48: -n, --noheadings 49- Do not print a header line. 50- 51- -O, --output list 52- Specify which output columns to print. Use --help to get a list of all supported columns. |
※ http://manpages.ubuntu.com/manpages/focal/man8/wipefs.8.html (focal は Ubuntu20.04 の開発コードです)の通り、Ubuntu公式サイトでも確認できます。
noheadings で検索して見えたオプションをつけて
1 |
wipefs -n /dev/xvda -O UUID #うまくいかない |
としたのですが、まったくヘッダ行が省略されないため、さらに5分ほど悩みました。だって noheadings の n で違和感ないですし……。
おかしいな、とコマンドラインヘルプ出して気が付きました。まさかの man TYPO です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ wipefs --help Usage: wipefs [options] <device> Wipe signatures from a device. Options: -a, --all wipe all magic strings (BE CAREFUL!) -b, --backup create a signature backup in $HOME -f, --force force erasure -i, --noheadings don't print headings -J, --json use JSON output format -n, --no-act do everything except the actual write() call -o, --offset <num> offset to erase, in bytes |
いま振り返ってこの記事を書いていて思い出したのでバグレポートに報告しようと本家を見に行ったら、既に直っていました。
https://cdn.kernel.org/pub/linux/utils/util-linux/v2.35/v2.35.2-ChangeLog
Ubuntu にも、Ubuntu20.10 で取り込まれてました。ただ Ubuntu 側の ChangeLog にも記載は無く、マージ主は Diff 時に見てはいるでしょうがスルーされており、おそらく誰にも気にもされずひっそりと直っていたようです。
学生時代に読んだ、ヤックシェービングの話[1] を思い出しました。
参考文献
[1] 高林哲さん(日本語の全文検索システムNamazuの原作者さん)のブログ記事