本記事は 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としています。

要件にまつわる機構

architecture.jpeg

アプローチは色々思いつきますが、上記の構造にしました。
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サーバーを立ち上げられるシンプルさは、 「小さな箱庭で物を組み立てる楽しさ」がありますよね。

今回の記事はアンチパターンではありますが、 あえて踏んで見ると、また違った視点が見られる気がして、自分としては学びがあり面白かったです。