Tech Racho エンジニアの「?」を「!」に。
  • インフラ

CentOS/RHELの起動スクリプト内ではsudoではなくrunuserを使う

morimorihogeです。
今朝は久々にAWSのus-eastリージョンが障害祭りみたいでどきどきしてます。今のところtokyoリージョンには問題なさそうですが、HerokuとかSlackみたいに内部的にus-eastに依存しているサービスは不安定のようですね。

小ネタです。

サーバ起動時の自動起動スクリプト

インフラ構築をしていて忘れがちですが大事なこと、それは「再起動テスト」です。
今はVPS的なクラウドサービスが主流になったので物理サーバの再起動ということはずいぶん減りましたが、それでもクラウドサービス側のメンテナンスで再起動が不定期に発生することはあります。
この際、再起動時にもきちんと必要なサービスが起動するように設定しておかないと困るわけですね。

LinuxではRedHat系(含むCentOS)もDebian系(含むUbuntu)も昔はsysvinitによる管理がされてきました(Ubuntuは途中upstartを使っていました)が、最近はsystemdを使う方向に統合されてきました。
ただ、systemdを使っていてもサービスの起動/停止用スクリプト自体はこれまで通り使うことも可能なので、その辺りは過去の資産を流用できると思います。
#実際にはsystemd用に書き直した方がシンプルになりそうですが、書き直すと検証も必要になるので互換性はありがたいです

なお、systemdで従来のsysvinit的なスクリプトを使いたい場合は、例えばHow does systemd use /etc/init.d scripts?といった記事が参考になるかと思います。

CentOS/RHEL固有の問題

世の中はsystemdに移行しつつある中とはいえ、レガシなディストリビューションを触る機会も相変わらずあります。
というわけでinit.dなスクリプトを書いていたのですが、Ubuntuでは動いていたスクリプトがCentOS7で動かなくて困りました。
具体的には、スクリプト内で書いていたsudoがrootのシェルからserviceコマンドで使う分には動作するのに、再起動時には起動しないという問題です。

どうやらCentOS/RHELのデフォルト設定では起動時のsudoは許されていない(ttyがないから?)らしく、その他の方法を使う必要があります。

runuserコマンドを使う

そんなときは

sudo -H -u app_user COMMAND

の代わりにrunuserコマンドを使い、

runuser app_user COMMAND

とすればうまいこと起動します。

ただ、runuserはUbuntuにはないパッケージのため、RHEL/CentOSとUbuntuで同じスクリプトを使い回せません。いけてない。この辺は苦し紛れに

SUDO="runuser $USER"

$SUDO COMMAND

的にsudo自体をwrapすることでとりあえず許せる範囲には満足しました。

なお、systemdを使えば

[Service]
User=app_user

するだけでディストリビューション間互換取れるんですよね。ということに後になってから気づきました。でもまあsystemdはまだ慣れてないエンジニアも多いと思うので、古いバッドノウハウを知っておくのも無駄ではないかなと思いました(願望)。

まとめ

久々にCentOSとか触ってハマったのでメモでした。最近社内環境はほとんどDocker化したのでsystemdよりsupervisordを使いこなせるようにならないといけないなーと思いつつ、レガシーな環境も触る機会はなくならないなあと思った日々でした。


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。