本記事はResonite Advent Calendarの一部です!
こんにちは、ナボリスクです。
みなさん、Resoniteヘッドレスサーバ建てたことがありますか?
Resonite民なら建てたことある人が何人かいると思います。
今回は、僕が最近KubernetesでResoniteヘッドレスサーバの構築方法を紹介します。
なぜKubernetesが良い
構築方法を紹介する前に、「なぜKubernetesが良いのか」というところから説明しないといけないですね。
最近のアプリデプロイはよくKubernetesでやっているところが多くて、単純にKubernetesを理解したいというところもあるのですが、使ってみた感想もあります。
まずは利便性です。Kubernetesを採用した利便性は、環境が宣言型(Declarative)になって、コンフィグのyamlを確認すれば、環境の現在の状況が知ることができます。インスタンスを立ち上げるときにコンフィグファイルを適用するだけで、簡単にできます。
そして、スケーラビリティです。複数のインスタンスを建てたい場合は少しコンフィグを修正して適用する形で簡単にできます。他のクラスターでインスタンス建てたい場合は、コンフィグファイルを適用するだけでできちゃいます。
Kubernetesクラスターの環境では、yaml形式のコンフィグで管理することで、コンフィグの中にアプリのなってほしい状態を指定するだけでいろんな操作はKubernetesがやってくれます。例えば、以下のyamlをKubernetesクラスターに適用すると「nginxをデプロイして、80ポートを開けといて」とKubernetesに言うような感じです。KubernetesはnginxのイメージをPullして適切なノード(管理されているサーバ機器または仮想マシン)に入れてくれます。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
参考:https://kubernetes.io/docs/tasks/run-application/run-stateless-application-deployment/
コンテナビルドのプロセス
Kubernetesを対応するために、まずはアプリをコンテナ化する必要があります。アプリのコンテナ化は、基本的にDockerfileを書くと良いです。
Resoniteヘッドレスの場合、Dockerfileに加えてResoniteヘッドレスをダウンロードしてくれるbashスクリプトがあると便利です。僕は以下のスクリプトをdownload-headless.sh
として保存し、コンテナビルド時に実行します。
#!/bin/bash
source .env
steamcmd +force_install_dir /Resonite +login ${STEAM_USER} ${STEAM_PASS} +app_update 2519830 -beta headless -betapassword ${BETA_PASSWORD} validate +quit
以上のスクリプトは、steamcmd
コマンドを使って、環境変数からログイン情報とベータのパスワードを取得し、ヘッドレスサーバを含んだResoniteをインストールします。
コンテナビルド時は、以下のDockerfileを使います。
FROM steamcmd/steamcmd:latest as builder
COPY .env ./.env
COPY download-headless.sh ./download-headless.sh
RUN chmod +x ./download-headless.sh
RUN ./download-headless.sh
RUN rm ./.env
FROM mono:6.12.0.182
RUN apt update && apt install -y \
curl lib32gcc1 libc6-dev libopus-dev libopus0 opus-tools
COPY --from=builder /Resonite/Headless /Headless
WORKDIR /Headless
ENTRYPOINT [ "mono", "Resonite.exe" ]
以上のDockerfileはsteamcmdのイメージを使って、download-headless.sh
を実行します。ログイン情報を含めた環境変数を使うため、一時的に.env
ファイルをコンテナにコピーします。download-headless.sh
の実行が終わったら、ヘッドレスに必要なファイルのみをmono
のコンテナにコピーします。こうしてビルドしたイメージは、最低限ヘッドレスサーバが実行できる軽いイメージができます。
メリット
このビルド手法のメリットは、イメージをPullしてからヘッドレスサーバがすでに入っているので、すぐ実行できてインスタンスの立ち上がりが早いです。マニフェストの中に適切なConfig.json
を用意すれば、すぐインスタンスができます。
もう一つのメリットは、ビルドしたイメージには、steamcmdやsteamが入っていないため、使用する容量が少なくなって、Pullするときは少し早くなります。
デメリット
このビルド手法のデメリットとしては、コンテナ自体がヘッドレスサーバの最低限の動かせる環境になるので、steamcmdが入らず、コンテナから更新はできないのである。更新する際には、新しくビルドされたコンテナをプルする必要があります。
もう一つのデメリットとしては、ビルドしたイメージは、ヘッドレスサーバのファイルが入っているので、一般公開するとResonite規約違反になります。現時点ではResoniteのヘッドレスサーバが建てられる人は、ResoniteのPatreonからアクセスコードをもらう必要があります。
注意点
download-headless.sh
を実行するためには、steamのログイン情報が必要です。個人的な管理方法としては、Resoniteヘッドレスサーバ専用のsteamアカウントを作成し、ログイン情報はGitHub Workflowsのシークレットとして管理しています。
マニフェストの例
apiVersion: apps/v1
kind: Deployment
metadata:
name: reso-headless-deployment
labels:
app: reso-headless
spec:
replicas: 1
selector:
matchLabels:
app: reso-headless
template:
metadata:
labels:
app: reso-headless
spec:
containers:
- name: reso-headless
image: [イメージのURL]
tty: true
stdin: true
imagePullPolicy: Always
volumeMounts:
- name: config-vol
mountPath: /Headless/Config/
readOnly: true
volumes:
- name: config-vol
configMap:
name: resonite-config
items:
- key: Config.json
path: Config.json
imagePullSecrets:
- name: [シークレットの名前]
---
apiVersion: v1
kind: ConfigMap
metadata:
name: resonite-config
data:
Config.json: |
[Config.jsonの内容はここに書く]
以上のマニフェストファイルで、正しいイメージのURL、イメージPullシークレットの名前、ヘッドレスサーバのConfig.jsonを指定してKubernetesに適用すると、Resoniteのヘッドレスサーバができちゃいます!
Kubernetesを使ったデメリット
Kubernetesを使ったデメリットは、Kubernetesは分散型システムに向いているが、Resoniteヘッドレスサーバ自体はまだ分散型の方法で構築できないため、冗長性や信頼性などの分散型システムのメリットが無いです。さらに、ゼロからヘッドレスサーバ構築したい場合は、Kubernetesを使おうとすると、複雑な環境構築が必要になって、少し大変だと思います。この手法ではすでに持っているKubernetesの環境でヘッドレスサーバを建てたい人に向いています。
終わりに
KubernetesでResoniteヘッドレスサーバを管理すると、秒でインスタンスの立ち上がりができますので、これからも僕はこの手法を使っていこうと考えています。さらに、今の実装だとストレージ対応していないので、今後の展望としては、ストレージも対応させ、Resoniteのキャッシュが使えるようにするかと考えています。