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

　前回、[#1（使い方）](https://qiita.com/ekaru/items/5dd28d74ac7b293642ad)でl4d2サーバーの立て方を記事にしましたが、今回はdockerfile等の内容や、作成を通じての反省と知見を残しておきます。
##作成したデータについて
###1. Dockerfile

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

 - https://github.com/ekarunian/l4d2-server
 - https://github.com/ekarunian/l4d2-server-data

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

```terminal
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になっていたことに気づかずハマっていました。）

```terminal
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記事](https://qiita.com/ekaru/items/5dd28d74ac7b293642ad)に示したサイトに記載されております。

```config
hostname "ekarunti"  //ホスト名
sv_allow_lobby_connect_only 0  //ロビー接続を許可しない（１にするとコンソールで入れなくなります）
rcon_password "ekarunian"  //管理者パスワード（特に意味はなさそうです）
z_difficulty Normal  //ゲーム難易度
sv_alltalk 0  //対戦時のvc設定（味方のみ）
sv_password "" //パスワード設定（設定しても効果はなさそうです）
sv_lan 0  //０がインターネット、１がLANになるようです
sv_region 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イメージ](https://hub.docker.com/r/cm2network/steamcmd)をベースに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でフォルダ統合するなどという回りくどいことをせず、直接コピーすればいいじゃんという当たり前のことに気づかなかったのは、知識がこなれていない証拠だと思いました。
　今回も最後まで読んでいただきありがとうございます。