left4dead2サーバー用のDockerイメージを作り、GCE上で動かしてみた #2(コンテナ作成過程で得た知見)


 前回、#1(使い方)でl4d2サーバーの立て方を記事にしましたが、今回はdockerfile等の内容や、作成を通じての反省と知見を残しておきます。

作成したデータについて

1. Dockerfile

 サーバー用のdockerfileとサーバー設定ファイル一式はそれぞれ以下に保存しています。

 まず、dockerfileの中身です(環境変数の設定や必要なパッケージ類の追加部分は省略します)。
linux用のsteamCMDを実行し、サーバーインストール用のフォルダを作成、インストール(10分くらい)をしています。
「222860」がl4d2のdedicated serverとなります。

wget -qO- 'https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz' | tar xvzf - -C \"${STEAMCMDDIR}\" \
./${STEAMCMDDIR}/steamcmd.sh +login anonymous +force_install_dir /home/steam/l4d2server +app_update 222860 +quit \

 インストールが終わったらsteamCMDを閉じて、サーバー設定用のファイルをコピーしています。
前述の通りこのファイルはgithubのリポジトリにある訳ですが、既存のフォルダに統合することとなるので、git cloneは使えません(多分)。
 なので、https://github.com/ekarunian/l4d2-server-data/archive/main.tar.gzでいったんtar.gzにしてから解凍し、それをrsyncで既存のフォルダに統合しています。
 このあたり結構悩んだのですが、もっと賢い方法があるのでしょうか……。
(どうでもいいですが、githubで自動生成されるブランチがいつの間にかmasterからmainになっていたことに気づかずハマっていました。)

wget -qO- 'https://github.com/ekarunian/l4d2-server-data/archive/main.tar.gz' | tar xvzf - -C \"${L4D2SERVER}\" \
rsync -a \"${L4D2SERVER}/l4d2-server-data-main/addons\" \"${L4D2SERVER}/l4d2-server-data-main/cfg\" \"${L4D2SERVER}/l4d2-server-data-main/motd.txt\" \"${L4D2SERVER}\" \
rm -r \"${L4D2SERVER}/l4d2-server-data-main\" \

2. サーバー設定用ファイル(server.cfgなど)

 l4d2-server-data/cfg/server.cfgにサーバー設定を記述しております。
 前文の詳細は#1記事に示したサイトに記載されております。

hostname "ekarunti"  //ホスト名
sv_allow_lobby_connect_only 0  //ロビー接続を許可しない(1にするとコンソールで入れなくなります)
rcon_password "ekarunian"  //管理者パスワード(特に意味はなさそうです)
z_difficulty Normal  //ゲーム難易度
sv_alltalk 0  //対戦時のvc設定(味方のみ)
sv_password "" //パスワード設定(設定しても効果はなさそうです)
sv_lan 0  //0がインターネット、1がLANになるようです
sv_region 4  //4はアジア
sv_search_key "ekaru2an"  //これを設定しておくとサーバーに入られにくくなります
motdfile "motd.txt"  //サーバーの説明
hostfile "host.txt"  //サーバーのバナー設定
...

 また、その他tankの挙動や武器の仕様を変えるカスタムプラグインをサーバーに導入しております。
 本来はdockerfile中でそれぞれのダウンロードリンクから直接wgetするなりが正解だと思うのですが、一部のプラグインはaddons/metamod/binに入っている共有ライブラリ(server.so)を機械的にコピーすると正常に動作しなくなる(レジスタサイズが違うと怒られてしまいます……。)ので、addonsとcfgフォルダはひとまとめにしてリポジトリに保存することにしました。
 つまり、サーバー設定を弄る時はこれらを書き換えてgit pushして、再度docker buildをします(後述しますが、これが残念な結果になりました。)。

反省点・知見

1. 既存のDockerfileは弄らずに、これをベースマウントにしてl4d2用のDockerfileを作っても良かった。

 今回、既存のdockerイメージをベースにdockerfileを作成しましたが、steamCMDのdockerイメージをベースマウントして新しいdockerfileを書いても良かったと思いました。
 実装上も修正作業上も特に問題はなかったのですが、管理者の問題が生じてくると思いました。
 元のdockerfileは別に管理者がいるため、仮にそちらがアップデートした際に今回作成したdockerfileもそちらに引っ張ってもらうことが出来ることはメリットかと思いました(一方、不変な環境ではなくなるのでそこはケースバイケースでしょうか……。)。

2. 良く弄るサーバーデータはDockerFile内に書くべきではなかった。

 これは強く反省した点です。
 前述した通り、今回はdockerfile内でgithubのリポジトリをwgetしたわけですが、これは最悪でした。
 何故かといいますと、今回dockerfile内に直接githubのアドレスを書いたため、どうやら「サーバー設定を変更したから差分をbuildし直そう!」となった時に、差分を認識せず変更が反映されませんでした。
 当然ですが、Docker HubのAutomated Buildがまともに機能せず、毎回docker build -t hoge:v1 . --no-cacheするかimageを消してから再度buildしていました。
 実は、l4d2のdedicated serverは10GB程度あります。つまり、サーバー設定を変更する度に激重なコンテナをbuildする必要があり、その度に20分程度時間を持て余すことになりました。  

まとめ

 この反省を踏まえて、今後は以下のような構成に直してみたいと思います。

  • DockerfileはsteamCMDをベースマウントにして書き直す(steamCMDとl4d2 dedicated serverを分離)
  • サーバー設定用フォルダをDockerfileのCOPY(COPY addons/ \"${L4D2SERVER}\"など)でビルド時に直接コンテナ内部に置くようにする
    • 変更が見えるのでAutomated Buildも機能するはず
    • (20/12/20追記:上記のやり方だとやはりサーバー設定を変える度にDockerfileをビルドする必要があるため、頻繁に変更する可能性があるサーバー設定ファイルはdocker-compose.ymlでコンテナ稼働時にコピーする方が現実的かと思いましたので、補足します。)

 サーバー設定ファイルのgithubリポジトリをwgetしてrsyncでフォルダ統合するなどという回りくどいことをせず、直接コピーすればいいじゃんという当たり前のことに気づかなかったのは、知識がこなれていない証拠だと思いました。
 今回も最後まで読んでいただきありがとうございます。