スプラトゥーン2の戦績をsplatnet2statinkとGKEを使って自動アップロードする
きっかけ
私(kamiya)は任天堂から発売されているスプラトゥーン2を遊んでいます。
そこでスプラトゥーン上での戦績は、スマホアプリから閲覧できるのですがこれが直近の50戦しか閲覧することができません。
そこで非公式ではあるのですが、この戦績を管理するサービスであるstat.inkとアップロードするツールであるsplatnet2statink を使って戦績を管理しています。(※公式の手法ではないため推奨はいたしません、運営サーバに負荷をかけるような使い方はサービス妨害と見なされ戦績公開自体がなくなってしまうかもしれないのでお辞めください)
今回はVPS上で運用しているsplatnet2statinkをGKE(Google Kubernetes Engine)に移行します。*1 既存のpythonアプリケーションをコンテナ化してクラウド運用する手順の紹介、という立ち位置で読んでいただけると幸いです。
手順
大まかには以下の手順を踏んで行います。3.項移行はgcloud sdkを使う方法とGoogle CloudのWebページからでもどちらでも行なえます。ここはGoogleの公式ドキュメントのチュートリアルに詳しく記載されています。
単体で動作確認をする
Dockerコンテナ上で動作できるようする
Google Docker Registry(もしくはDockerHub)にイメージをpushする
Kubernetesクラスタに登録済のコンテナイメージをデプロイする
splatnet2statinkの動作
pythonで書かれた任天堂のサーバから戦績情報を取得するソフトです。コンテナ化する上でも簡単に動作を確認してみます。*2
7~40行目
config.txt
を読み出すか、作成しています。その内容はapi_key, cookie, user_lang, session_token
の4つです。
注目すべきはコンフィグファイルの指定はpython実行時のカレントディレクトリになる点です。
1170行目 name == "main"
pythonで直接実行されているときのみ実行されます。今回ではメインルーチンになっています。
1171行目→228行目 : main()
以下の動作をするようです。
- 224行目 → 194行目 : check_for_update()
どうやらgithubからコードの最新版があるか調べ、gitが実行できる環境ならgit pull
、できなければrequest.get
をしてリソース更新をしているようです。
よく見ると204行目でアップデートを行うかのプロンプトが必ず表示されるようです。
- 237行目~270行目
argparseライブラリを使って、コマンドライン引数の設定・取得を行っています。動作としては-M <更新間隔>
で 一定時間ごとの自動更新と、-r
でアップロードいていない戦績のみを対象にするオプションが使えれば良さそうです。
1175行目→295行目 : monitor_battle()
一定時間ごとに結果を取得してアップしています。
他にもいろいろありますが、以下の3点がコンテナ化する上でのポイントです。
自身のアップデートにrequest及びgitを使用している
設定ファイルは
config.txt
を使うこと実行時は
python splatnet2statink.py -M <秒数> -r
を実行できればよい
単体で動作確認をする
python splatnet2statink.py
で正常に動作できることを確認します。認証などについては詳細は触れません。
Dockerコンテナ上で動作できるようにする
まずは本アプリケーションをコンテナ化します。コンテナ化する上で認証情報などはあとから環境変数などで与えられるようにするのが通例です。
まずはgitを使ったアップデートですが、プロンプトにy
を打ち込ませるのも面倒なのでgit submodule
としてsplatnet2statinkを追加してgitコマンドを叩いてアップロードします。
ですので、実際に実行指定するスクリプトとしてrunner.py
を作成していきます。
$ git submodule add https://github.com/frozenpandaman/splatnet2statink splatnet2statink
pythonからは$ git submodule foreach git pull origin master
を叩ければ良いのでsubprocessモジュールを使って以下のようにします
subprocess.call(["git", "submodule", "foreach", "git", "pull", "origin", "master", ])
次に設定ファイルですが、環境変数を読み出してconfig.txt
を書き換えるようにします。os.getenv
で簡単に取得できるのでこれを利用します。
ファイルの書き込みはjsonモジュールを使うと、dictionaryをそのままjsonテキストにできるのでこれを書きます。
def env_to_config(envs_src): envs = dict([(e, os.getenv(e, "")) for e in envs_src]) envs_available = all(envs.values()) if envs_available: with open('config.txt', 'w') as file: file.write(json.dumps(envs)) print('#update config.txt')
最後にスクリプトの実行ですが、これはgitコマンドの実行と同じです。
args = ["python", "./splatnet2statink/splatnet2statink.py"] flags = os.getenv("run_flags", "-M 14400 -r").split(" ") # monitor per 4hour args.extend(flags) subprocess.call(args)
これらを統合してhttps://github.com/kamiyaowl/splatnet2statink-docker/blob/master/runner.pyとしました。
これをpython runner.py
して問題なく動作することを確認します。
あとはsplatnet2statinkに必要なライブラリをインストールするだけのDockerfileを書きます
FROM python:3.6 COPY . /app WORKDIR /app RUN pip3 install --upgrade -r splatnet2statink/requirements.txt CMD ["python", "-u", "runner.py"]
私は面倒くさがりでコマンドライン引数を大量に書くのが苦手なので、docker-composeファイルも一緒に作成しました。 あくまで動作確認用に作成しましたが、自分で行う場合このファイルの管理は注意してください。
splatnet2-statink: build: ./ # volumes: # - cache:/app # splatnet2statinkのリポジトリ更新キャッシュ用 environment: # Containerサービスの環境変数に設定する - api_key=your_api_key - cookie=your_cookie - session_token=your_session.token - user_lang=en-US
あとは正常に実行できることを確認します。
$ docker-compose up
Google Container Registryに作成したイメージをアップする
Google Cloud SDKのセットアップについては公式ドキュメントなどを参照してください。
// イメージ名を確認 $ docker image ls // タグ付けを行う $ docker tag <イメージ名> gcr.io/<プロジェクト名><イメージ名>:<タグ> // 作成したイメージをGCRにアップする $ gcloud docker -- push gcr.io/<プロジェクト名><イメージ名> // イメージ一覧を確認 $ gcloud container images list
不安なのでWebコンソールでも見てみます。
良さそうです。
Google Kubernetes Engineにアップする
ここからはGUIでもkubectlでもできます。おおまかな説明だけするとまずクラスタを作成します。
構成は任意ですが、動作確認なのでus-central1-a, g1-small, auto-scaling=off, size=1
で作成しました。
次にワークロードを作成します。作成時に先程GCRにアップしたイメージをベースイメージとして指定します。この際の環境変数にdocker-composeで指定していたconfig.txt
の項目を設定します。
この設定はGKEのConfigMapに保存されるのであとから編集できます。
静的IPやLBは外部ネットワークが必要ないので設定せず、あとはクラスタが構成されるまで少し待ちます。
無事に立ち上がった後、stat.inkの結果を見るなりログの内容を閲覧して正常に動作していることを確認できれば完了です。
WebコンソールからStackdriverの起動時のログを見てみましたが、ローカル起動時と同様に出力されており問題なく動作できていることが確認できます。
まとめ
各種サービスをコンテナ化してクラウドサービスに移行していくと、何よりサーバ管理の手間がないので面倒が減るのでかなり楽です。
従量課金の具合などから構成を見直したりする必要はあると思いますが*3、ちょっとした小回りから大掛かりなものまで活用できそうです。
今回作成したものも、githubで公開しておきます。
2018/7/28追記
CronJobで定期実行できるようにしました。
*1:正直Kubernetesが使いたいだけなのでCompute EngineのVMに当てても何ら問題ありません。
*2:2018/07/16現在のコードです
*3:例えばGAEでcronするようなジョブを作ったほうが