Amazon Linux 2のswapファイル作成にfallocate、ダメ、ゼッタイ
今回、Amazon Linux 2環境でrootボリューム上にswap領域を作る際に、従来のベスト・プラクティスで利用しているfallocate
はswapon
時にエラーが起きてしまうことを確認したのでシェアします。情報としては古い話をひっぱり出していますが、今後、LTS(Long-Term Support)ビルドがリリースされれば、Amazon Linux 2を利用されるユーザーも多くなると思いますのでブログに書いた次第です。
動作確認環境
Amazon Linux 2は現在、RC(Release Candidate)なので、LTSビルドでは動作が変わる可能性もあります。
- AMI ID:ami-c2680fa4(Amazon Linux 2 LTS Candidate AMI 2017.12.0 (HVM), SSD Volume Type)
- Kernel:4.9.76-38.79.amzn2.x86_64
Amazon Linux 2でfallocateを使うと、どうなる?
まず、従来どおりにfallocate
でswapファイルを作成した場合、どんなエラーになるか、あえて踏んでみましょう。
$ sudo fallocate -l 3855176K /swap.img $ sudo mkswap /swap.img スワップ空間バージョン1を設定します、サイズ = 3855172 KiB ラベルはありません, UUID=6dcdf231-55f7-4601-b5f2-b12b9252b366 $ sudo chmod 600 /swap.img $ sudo swapon /swap.img swapon: /swap.img swaponは失敗しました: Invalid argument
と、こうなります。
/var/log/messages
を見るとswapfile has holes
(スパースファイル)と判断されているのが問題のようです。
$ sudo tail /var/log/messages : Jan 27 04:37:46 localhost kernel: swapon: swapfile has holes
du
、filefrag
でスパースの具合を見てみました。
$ du /swap.img 3855176 /swap.img $ filefrag -v /swap.img Filesystem type is: 58465342 File size of /swap.img is 3947700224 (963794 blocks of 4096 bytes) ext: logical_offset: physical_offset: length: expected: flags: 0: 0.. 454752: 69406.. 524158: 454753: unwritten 1: 454753.. 963793: 2096653.. 2605693: 509041: 524159: unwritten,eof
出力結果を見るかぎり、論理的なディスク領域は確保されており、スパースファイルにはなっていないように見えますが、swapon
は有効なファイルとして判断してくれないようです。Bugzillaの情報によれば
the problem with fallocate(1) or truncate(1) is that it uses filesystem ioctls to make the allocation fast and effective, the disadvantage is that it does not physically allocate the space -- but swapon(2) syscall requires a real space.
sawapon
は実スペースを要求するのでfallocate
のように実スペースを持っていないファイルはダメ!ということのようですが、EXT4では作成できていたので、なんで?という疑問は残りますが、これ以上深く掘るのは専門の方におまかせします。。
問題はわかった。じゃぁ、どーすりゃいいのよ?ということですね。
ddでやるっきゃない!
先述のとおりfallocate
はswapファイルとして利用できないため、dd
で対応します。
また、これまでは/etc/rc.local
にて、毎起動時にswapファイルの作成処理を仕込んでいましたが、Amazon Linux 2からsystemd
が採用されたことにより、デフォルトで/etc/rc.local
は起動しなくなっています。解決方法は/etc/rc.d/rc.local
のコメントに書いてました。
#!/bin/bash # THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES # # It is highly advisable to create own systemd services or udev rules # to run scripts during boot instead of using this file. # # In contrast to previous versions due to parallel execution during boot # this script will NOT be run after all other services. # # Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure # that this script will be executed during boot.
下2行を見ると、「/etc/rc.d/rc.localに実行権を付与すれば動くよ」と記載されていますが、それより先に「systemdサービスか、udevルールを作成してrunさせるのがイチ推しっす!」というコメントが目に入ってしまうので、今回は起動時スクリプトをsystemdサービスとして作成します。 起動時に実行する方法として、他にもユーザーデータが考えられますが、並列処理と依存関係が設定できる点でsystemdはなかなか良いと思いました。Amazon Linux 2のLTSビルドがリリースされれば、利用機会も増えることは間違いないので、systemdの仕組みについても、じっくり勉強しておきたいですね。
起動時スクリプトを拝借してdd対応に書き換える
起動時スクリプトは先人の知恵を拝借しまして、以下のようにdd
対応させました。論理的なディスク領域を確保するfallocate
とは違い、物理的なディスク領域を確保するdd
は遅いです。。そのままだと毎起動時にdd
のファイル作成待ちによって起動時間が長くなってしまうので、既にswapファイルがある場合はサイズを比較し、メモリサイズと異なる場合は、インスタンスタイプが変更されたものとして、dd
で新たなメモリサイズに適したサイズでswapファイルを再作成。メモリサイズと同サイズの場合は、dd
処理をスキップするようにしました。今回はインスタンスタイプの変更などにも対応できるように、このような対応をとっていますが、もちろんswapファイルの再作成が不要であれば、/etc/fstab
に書いてしまうのが良いと思います。
#!/bin/bash SWAPFILENAME=/swap.img MEMSIZE=`cat /proc/meminfo | grep MemTotal | awk '{print $2}'` if [ $MEMSIZE -lt 2097152 ]; then SIZE=$((MEMSIZE * 2)) elif [ $MEMSIZE -lt 8388608 ]; then SIZE=${MEMSIZE} elif [ $MEMSIZE -lt 67108864 ]; then SIZE=$((MEMSIZE / 2)) else SIZE=4194304 fi if [ -e $SWAPFILENAME ] ; then SWAPSIZE=`du $SWAPFILENAME | awk '{print $1}'` else SWAPSIZE=0 fi if [ $SIZE -ne $SWAPSIZE ]; then dd if=/dev/zero of=$SWAPFILENAME count=$SIZE bs=1K && chmod 600 $SWAPFILENAME && mkswap $SWAPFILENAME && swapon $SWAPFILENAME else swapon $SWAPFILENAME fi
作成しましたら、実行権を与えておきます。
$ sudo chmod 744 /usr/local/bin/custom_mkswap.sh
起動時スクリプト用のUnitファイルを作成
次に起動時スクリプトをsystemdで管理するため、/etc/systemd/system
以下にServiceタイプでオリジナルのUnitファイルを作成し、さきほどのcustom_mkswap.sh
スクリプトを実行するように設定します。
[Unit] Description=Make swapfile and swapon on boot. After=local-fs.target RequiresMountsFor=/ [Service] RemainAfterExit=true Type=oneshot ExecStart=/usr/local/bin/custom_mkswap.sh [Install] WantedBy=local-fs.target
作成しましたら、systemctl
でcustom_mkswap.service
を有効化します。
$ sudo systemctl enable custom_mkswap.service Created symlink from /etc/systemd/system/local-fs.target.wants/custom_mkswap.service to /etc/systemd/system/custom_mkswap.service. $ systemctl list-unit-files --type=service : custom_mkswap.service enabled :
有効化されたことを確認して、再起動します。
再起動後の確認
再起動後、swapが有効になっていることを確認します。
$ free total used free shared buff/cache available Mem: 3855176 74388 3619320 16624 161468 3604308 Swap: 3855172 0 3855172
systemctl
でsystemd
により実行されたログを見ることができますので、見てみます。
systemctl status custom_mkswap.service -l ● custom_mkswap.service - Make swapfile and swapon on boot. Loaded: loaded (/etc/systemd/system/custom_mkswap.service; enabled; vendor preset: disabled) Active: active (exited) since 土 2018-01-27 14:28:13 UTC; 10min ago Process: 2677 ExecStart=/usr/local/bin/custom_mkswap.sh (code=exited, status=0/SUCCESS) Main PID: 2677 (code=exited, status=0/SUCCESS) CGroup: /system.slice/custom_mkswap.service 1月 27 14:28:13 ip-10-0-0-190.ap-northeast-1.compute.internal systemd[1]: Started Make swapfile and swapon on boot.. 1月 27 14:28:13 ip-10-0-0-190.ap-northeast-1.compute.internal systemd[1]: Starting Make swapfile and swapon on boot....
問題なく動作していることが確認できました!
インスタンスストアの場合、どうすんの?
ちなみに、インスタンスストアにswapファイルを作成する場合は、Amazon Linuxと同じように以下の記事が利用できました。
『Amazon EC2(Linux)のswap自動作成を行うRPMパッケージ ec2-swap を作ってみた』
1点だけ注意しておくポイントは、インスタンスストアのマウントポイントが/media
から/mnt
に変更されていますので、デフォルトのマウントポイントのまま使用する場合は、設定ファイル/etc/sysconfig/ec2-swap
のINSTANCEVOL_MOUNTPOINT
を以下のように変更してください。
$ sudo vi /etc/sysconfig/ec2-swap INSTANCEVOL_VIRTNAME=ephemeral0 INSTANCEVOL_MOUNTPOINT=/mnt/$INSTANCEVOL_VIRTNAME SWAPFILENAME=$INSTANCEVOL_MOUNTPOINT/swap.img
そもそもswap設定いるんか問題
パフォーマンスに大きな影響を与えるため、swapをアテにしたような運用は避けるべきだと思います。十分なメモリサイズを持たせ、swapにこぼれないようなインスタンスサイズを選択するほうが良いでしょう。しかしながら、「一時的な負荷のためにサイズアップはしたくない」「スパイク的なメモリ消費でプロセスを落としたくない」など、swapで対応したいケースはあると思います。
さいごに
今回、fallocateのエラーを調べるなかで、ベストプラクティス記事が大変多くの方に参照いただいてることが判りました。私もDevelopers.IOの一員として、誰かのお役にたてるような記事をバシバシ書けるように、日々精進していきたいと思います!今後とも、よろしくお願いします!
以上、丸毛でした。