🐩

Dapr + k8s + AlphaZero でオセロ

2022/04/27に公開

現在カミナシというSaas企業でインターンとしてお世話になっているのですが、その研修として個人開発する機会があったのでDapr使ってオセロを開発しました!

制作物

  • コンピュータと対戦できるオセロ
  • 先攻/後攻、コンピュータのレベル(1〜3)まで選べる
  • 2人での対人対戦はできない

言語等

  • Dapr
  • Kubernetes
  • gRPC
  • React
  • Go
  • Python

Daprとは

マイクロサービスとしてアプリケーションを簡単に構築できるようにするソフトウェアです。Istioなどの(ネットワーク)サービスメッシュと同じような機能もあると思いますが、公式によるとサービスメッシュとは違うみたいです。色々便利な機能があるのですが、今回の開発ではサービス間の通信がDaprの主な役割となっております。

概要

サービスの全体像は以下の図の通りです。

  • Front (React)
    • User/CP の切り替わりなどゲーム進行
    • 先攻・後攻や CP のレベルなどのゲーム設定
  • CP (Python)
    • コンピュータ
  • Board (Go)
    • 盤面の更新(リバースや石を置ける場所の算出)
  • Kubernetes上でDaprや各APIが動作

一応目的としてはDaprを使用して何か制作することでしたので、今回はDaprに関連することについて共有させていただきます。最後におまけとしてコンピュータの部分についても軽く触れたいと思います。

Daprを使用したサービス間の通信

API間で通信するときは、サイドカーとしてDaprを通じて通信します。例えばFrontからCPにリクエストを送信する際は、

  1. Frontから同じPod内にいるDaprサイドカーへ
  2. (Front)サイドカーから(CP)サイドカーへ
  3. (CP)サイドカーからCPへ

という流れになりレスポンスも同じようにサイドカー経由で通信されます。クライアントはサーバのapp-idを指定してサイドカーにリクエストを送るだけで、後はDaprが諸々やってくれます。

Dapr on Kubernetes

app-idはKubernetesのマニフェストに記述します。例としてCPのマニフェストは以下のようになっております。

apiVersion: apps/v1
kind: Deployment
metadata:
~~~
spec:
  ~~~
  template:
    metadata:
      labels:
        app: cp
      annotations:
        dapr.io/enabled: "true"
        dapr.io/app-id: "cpapi"
        dapr.io/app-port: "5000"
        dapr.io/app-protocol: "grpc"
        dapr.io/config: "appconfig"
    spec:
      ~~~

dapr.io/app-idの部分がapp-idとして設定されます。つまり、CPと通信したい場合はcpapiを指定すればOKです。

app-id

HTTPの場合は

http://localhost:{DAPR-PORT}/v1.0/invoke/{APP-ID}/method

の形でリクエストを送ります。ですのでCPにリクエストを送りたい場合は、

http://localhost:3500/v1.0/invoke/cpapi/method

となります。
gRPCの場合はapp-idを指定したmetadataを送信します。例としてNode.jsの場合は以下のようにmetadataを付与できます。

const metadata = new grpc.Metadata();
metadata.add('dapr-app-id', 'server');
client.sayHello({ name: "Darth Malgus" }, metadata)

tracing

分散トレーシングシステムとしてzipkinを使用しました。Kubernetesマニフェスト中のdapr.io/configに指定されているappconfigの中にzipkinの設定を以下のように書き、zipkinのマニフェストを作成すれば簡単に導入できます。

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: appconfig
spec:
  tracing:
    samplingRate: "1"
    zipkin:
      endpointAddress: "http://zipkin.default.svc.cluster.local:9411/api/v2/spans"

コンピュータ

コンピュータは複雑なロジックを考えるのが大変だったのでシンプルなものにしました。Lv1~3まで以下のようになっています。

  1. ランダムに選択
  2. 貪欲に選択
  3. 学習済みAlphaZero

Lv1はランダムで置く場所を決め、Lv2は点数が最も高くなる場所に置きます。Lv3はAlphaZeroの学習済みモデルがこちらで公開されていたので使用させていただくことに...扱い方はこちらのブログを参考にさせていただきました。
今回はサーバ部分を自分で書きましたが、TensorFlow Servingのようなものを使用すれば楽にできたかもしれないです

おまけ


自分は真剣にやっても負けるときあります笑
(スペック次第ですが)CPUで全然動くのでよかったらやってみてください!
https://github.com/chiru1221/dapr-othello

Discussion