起動後一定時間誰もログインしていないとき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が入ってるかを探す。

ptspseudo-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コンソールへのアクセス権が与えられていない状況などでは、この方法は悪くないやり方のようである。