起動後一定時間誰もログインしていないときLinuxマシンを自動で落とす
モチベーション
あるお客様にGCP上のGPUマシンを用意していただいたのだが、いつも使うわけではなく、ずっとつけっぱなしだとお金がかかってしまう。
そこで、毎日決まった時間に起動するようにスケジューリングしてもらい、使うときは使い、使い終わったら私の方でシャットダウンする、というようにした。
しかし、この運用だと、日によっては全く使わないときもあり、シャットダウンを忘れてしまう可能性があった。
そこで、ブート後3時間全く使っていなければ、自動でシャットダウンするsystemdサービスを書いてみることにした。
/usr/local/bin/check_login.bash
まず、処理本体のシェルスクリプトを用意する。
#!/bin/bash
# Check whether anyone logged in in 3 hours.
if last -s -3hour | grep -q -E '^.+ pts/'; then
echo "User login detected."
else
echo "No user login detected. Shutting down..."
shutdown -h now
fi
処理の内容としては、last
コマンドを使って最近のログインを一覧で出力し、そのなかにpts
が入ってるかを探す。
pts
はpseudo-terminal slave
(擬似端末スレーブ) の略であり、システムではないユーザーによるログインの判定に使用している。
pts
の入っている行があればログインありと判定し、特に何もしない。なければ、ログインなしと判定して、shutdown
コマンドでマシンを終了する。
sudo chmod 755 /usr/local/bin/check_login.bash
で実行権限をつけておく。
/etc/systemd/system/check_login.service
次にsystemdサービスを作成する。
oneshotで先程のスクリプトを実行するものである。
[Unit]
Description=Check login status and shutdown if no login within 3 hour
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/check_login.bash
/etc/systemd/system/check_login.timer
次にタイマーを作成し、先程のサービスがブート後3時間で実行されるようにする。
[Unit]
Description=Run check_login.service 3 hour after boot
[Timer]
OnBootSec=3h
Unit=check_login.service
[Install]
WantedBy=multi-user.target
サービス有効化
次のコマンドでサービスを有効化しておく。
sudo systemctl daemon-reload
sudo systemctl enable check_login.timer
sudo systemctl start check_login.timer
実用上の問題と注意点
最初この設定は3時間ではなく1時間にしていたのだが、全くログインできない状態になってしまった。
手動で立ち上げていただき、last
コマンドを叩いてみると、実際にシステムがブートしているのはスケジュールされた起動時刻より1時間以上早い時刻であったことがわかった。
これは想像だが、GCP側での最適化の影響と考えられる。 ブート自体は早めに行い、スケジュールされた起動時刻でアクセスが可能になる、というようなことではないかと思う。
そこで、実際にアクセスが可能になる前に、シャットダウンが発生してしまっていたようである。
1時間を3時間にすれば、いったんはこの問題を回避できる。というわけでそのようにしているが、たとえば、タイマーファイルで
OnBootSec=3h
の代わりに、
OnCalendar=*-*-* 10:00:00
とするなどとして、タイマー自体は固定の時刻に起動する、といった方法もあるだろう。
そもそもこんなことしなくても、GCPのマネージドサービスや機能を利用する方法というのもありそうなのだが、 GCPコンソールへのアクセス権が与えられていない状況などでは、この方法は悪くないやり方のようである。