本記事は PHP Advent Calendar 2021 - 7日目 の記事になります🙏
はじめに
PHPチームの有澤です。
突然ですが、皆さんはMinecraftをしていますか? 私は時々猛烈にしたくなることがあります。
その際に友人とマルチプレイをすることがあるのですが、 LinuxサーバーにMinecraftのサーバークライアントを稼働させて、そこへアクセスして遊ぶようにしています。
ゲーム自体はとても面白いのですが、プレイしていく際に面倒なことがひとつとあります。
というのも、Minecraftサーバーに自分がログインをした際に、友人に「ログインした」とDiscordでメッセージを送る必要があった
ので、
いちいちメッセージを送るのも急かしているようなニュアンスになってしまい、申し訳ないなと思うことが多々ありました。
そこで、解決策として「Discordにログイン通知チャンネルを作って、そこで自動ログイン通知させよう」
と考えました。
その時に自作のPHPアプリをデプロイして、現在も稼働中なのですが、 あえて普段の業務ではやらないデプロイをしてみたので、ざっと感想を書こうと思います。
使用言語
- PHP 8
早くマルチプレイがしたかったので、慣れているPHPで実装しました。
デプロイ先のサーバー情報
Oracle CloudのComputeで、以下のVMインスタンスを取得しました。
サーバースペック(VMインスタンス)
- サービス:Oracle Cloud (Compute)
- アーキテクチャ:Ampere A1 Compute
- OS:Oracle Linux 8
- OCPU:2コア
- メモリ:12GB
Minecraftサーバーに多くメモリを使うチューニングをしているので、あえて多くメモリを設定しています。
OCPUのコア数は、デプロイ以前は若干心もとないかなと予想していましたが、 試験的にプレイヤー数2〜3人で運用した際に、問題が発生しなかったことからOKとしています。
要件にまつわる機構
アプローチは色々思いつきますが、上記の構造にしました。
WebサーバーはApacheやNginxを使わず、PHPが機能として持っているビルトインWebサーバーを採用しました。
というのも、開発環境だけで使うビルトインWebサーバーを、本番運用した際、どこまで稼働するのか知りたかったため、実験的にこちらを採用しました。
ただ、あくまでLinuxサーバー上のローカルサーバー
として立ち上げるので、外部から意図しないRequestが来るのは想定していません。
あくまでLinuxサーバー内部の通信で使うのを想定しています。
(実はですが、ログイン通知をするのはBashでDiscord APIを叩くだけで実現できちゃいます。 が、今後集計を取ったり特殊なことをする際はやはりPHPを挟んだほうがやりやすいので、あえてPHPアプリを挟むことにしてます)
Linuxサーバー上でビルトインWebサーバーを立ち上げた際の問題点
PHP8系のビルドが完了した前提で話を進めます。
php -S localhost:8000 ./public/index.php
ビルトインWebサーバーを起動する際、普段は上記のコマンドを実行するかと思います。
ですが、ターミナルを終了するとセッションが切れるので、LinuxサーバーにSSHして、↑のコマンドを実行しても途切れてしまいます。
この場合、どうやってコマンドの実行を持続化すればよいのでしょうか?
ビルトインWebサーバーを実行するUnitファイルを作成する
php -S localhost:8000 ./public/index.php
を実行するUnitファイルを作成します。
これにより、ターミナルのセッションが切れても、Unit(サービス)上でコマンドが実行されているので、 コマンドは持続します。
Unitファイルは以下の記事を参考にして作成しました。
https://qiita.com/miyuki_samitani/items/953140bc3c89f0fb606f
自作したUnitをsystemdで実行し、サービスとして起動する
hoge.service
というUnitを作成した場合、以下のコマンドで起動します。
systemctl start hoge.service
普段Apacheやnginxを起動するのと同じコマンドですね。
より詳しいコマンドは、以下で記載されているのでご確認ください。
https://qiita.com/sinsengumi/items/24d726ec6c761fc75cc9
こうして気がつくのは、ビルドインWebサーバーをデプロイするにはUnitを書かないといけないようです。 このような小さな面倒事も、サードパーティのWebサーバーが担ってくれているのと気付かされました。
Q & A
Q. 落ちたりしないんですか?
4ヶ月ほど稼働させていて、落ちることなく稼働し続けています。(凄い) なにかしら障害は発生しそうだと思っていましたが、正常動作していて感動しています。
本番サーバー内のローカルサーバーとして立ち上げていたり、 1日にRequestが10件も来ない使い方だったのも、良かったかもしれませんね。
(今後、問題が発生したらブログネタにしようと思います😇)
Q. 業務で使いたいです
用途に応じるとは思いますが、基本的にオススメしません。
あくまで開発用として使ってください。
実はPHPの公式マニュアルにもそう書いてあります。 https://www.php.net/manual/ja/features.commandline.webserver.php
Q. PHPアプリのソースコードってありますか?
https://github.com/goreboothero/archerfish
↑ GithubにPushしています。 結構急いで書いたので、雑なところはあるので、後々修正します。
Oracle Linux 8(Arm)でPHP8をビルドするのに時間を費やしたので、結構乱雑になってます…😇
Q. デプロイしたログイン/ログアウト通知アプリは便利ですか?
超便利に使ってます。
でも、一つだけ気になったことがあって、
MinecraftサーバーにアクセスするIPを掲示板などに公開していないのに、知らないプレイヤーがログインしてくることが、4ヶ月の内に3回ありました。
いずれのプレイヤーも滞在時間は10秒ほどでしたが、Minecraft用のWeb Botが存在してそうです。
予想ではありますが、接続できるサーバーとしてリストアップされてそうですし、
大量のアクセスが来てワールドを爆破されても困るところなので、どうにかしたいところです。
Q. 実際にビルトインWebサーバーを使ってみて、メリットは感じましたか?
最小限の構成なので、軽量なPHPアプリとしてコンテナ化がしやすいと感じました。
イメージで言うと 1コンテナをPullしただけで起動するPHPアプリ
なんですが、面白い用途が浮かんできそうです。
また、これは予想ではありますが、サードパーティのWebサーバーが普段している処理(HTTPヘッダの解析など)はしていないので、メモリの使用率は低いはずです。
(Webサーバーの変更をした際に、ベンチマークを図ろうと思います)
なので、十分なメモリが無い低スペックなサーバー環境下かつ、Webサーバーにメモリを使わせたくない時は、使うことになりそうですが、
やはり公開ネットワーク上に稼働させるのは避けたいところです。
最後に
サードパーティに依存せず、PHP自身の機能でWebサーバーを立ち上げられるシンプルさは、 「小さな箱庭で物を組み立てる楽しさ」がありますよね。
今回の記事はアンチパターンではありますが、 あえて踏んで見ると、また違った視点が見られる気がして、自分としては学びがあり面白かったです。