PhoenixアプリをAgonesで管理する



# はじめに

この記事は「Elixir Advent Calendar 2022」の21日目です。
昨日は@mnishiguchiさんの「OptionParserでElixirスクリプトの引数を解析」でした。

Liveviewチャットアプリのチャットルーム管理を[Agones](https://agones.dev/site/)でをやってみます。


# 目次

1. PhoenixチャットアプリをAgone上でGameServerとして動かす(本記事)
2. AgonesにGameServerFleetを導入数する(後日公開予定)
3. Agonesにfleet autoscalerを導入する(後日公開予定)
4. OpenMatchでチャットルームをマッチングする(後日公開予定)


# 環境

|OS(host) |　Windows11|
|:---|:---:|
|OS(gest)| ubuntu20.04|
|Memory|32GB|
|VitrualBox|6.1|
|vagrant|2.3.4|
|docker|20.10.22|
|minikube|1.28.0|
|elixir|1.14|
|phoenix|1.6|

下記手順で環境構築を行います。
1. vagrantでvirtualbox上にubuntu環境を作成します。
2. docker、minikube、agonesをインストールします。
3. asdfでelixir,erlangをインストールします。
4. phoenixをインストールします。

# Liveviewチャットアプリ作成

## 1 プロジェクト作成

```
mix phx.new phoenix-chat
```

## 2 チャット機能

チャット機能を追加します。

router.exにchatへのルーティングを設定します。
```elixir:lib/phoenix-chat/router.ex
scope "/", PhoenixChatWeb do
    pipe_through :browser

    get "/", PageController, :index

    live "/chat", Chat.Index
end
```

/lib/phoenix_chatWeb/live/chat.exにchat処理を新規追加します。
```elixir:/lib/phoenix_chatWeb/live/chat.ex
defmodule PhoenixChatWeb.Chat.Index do
  #use Phoenix.LiveView
  use PhoenixChatWeb, :live_view
  def mount(_params, _session, socket) do
    if connected?(socket) do
      PhoenixChatWeb.Endpoint.subscribe(topic)
    end
    {:ok, assign(socket, username: username, messages: [])}
  end

  def handle_info(%{event: "message", payload: message}, socket) do
    {:noreply, assign(socket, messages: socket.assigns.messages ++ [message])}
  end

  def handle_event("send", %{"text" => text}, socket) do
    PhoenixChatWeb.Endpoint.broadcast(topic, "message", %{text: text, name: socket.assigns.username})
    {:noreply, socket}
  end

  defp username do
    "User #{:rand.uniform(100)}"
  end

  defp topic do
    "chat"
  end

  def render(assigns) do
    ~L"""
    <div>
      <h1>ChatLive</h1>
      <div class="messages" style="border: 1px solid #eee; height: 400px; overflow: scroll; margin-bottom: 8px;">
        <%= for m <- @messages do %>
          <p style="margin: 2px;"><b><%= m.name %></b>: <%= m.text %></p>
        <% end %>
      </div>
      <form phx-submit="send">
        <input type="text" name="text" />
        <button type="submit">Send</button>
      </form>
    </div>
    """
  end
end

```

## 3 動作確認

```
mix phx.server
```

![chat01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256958/0f90e1de-f2de-1db6-9c9a-fc3a75e17c8d.png)

## 4 コンテナ化

phoenixチャットアプリのコンテナを作成します。

```
docker build -t phoenix-chat:minikube .
```

# Agones上でPhoenixチャットアプリを動かす

phornixチャットアプリをAgones上にデプロイするマニフェストを作成します。
```sh:gameserver.yaml
apiVersion: "agones.dev/v1"
kind: GameServer
metadata:
  generateName: "simple-game-server"
spec:
  ports:
  - name: default
    portPolicy: Dynamic
    containerPort: 4000
    protocol: TCP
  health:    
    initialDelaySeconds: 30
    seconds buffer
    periodSeconds: 25
  template:
    spec:
      containers:
      - name: simple-game-server
        image: phoenix-chat:minikube
        imagePullPolicy: Never
        ports:
        - containerPort: 4000
        resources:
          requests:
            memory: "640Mi"
            cpu: "500m"
          limits:
            memory: "640Mi"
            cpu: "500m"
```

Agonesにチャットアプリをデプロイします。
```
kubectl create -f gameserver.yaml
```

gameserverの状態がReadyになっているのを確認します。
```
kubectl get gs
NAME                      STATE       ADDRESS        PORT   NODE     AGE
simple-game-serversbxhc   Ready   XXX.XXX.XXX.XXX   YYYY   agones   7s
```

ローカル端末からvirtualbox上のubuntuにポートフォワードします。
```
ssh vagrant-agones -L YYYY:XXX.XXX.XXX.XXX:YYYY
```

チャットアプリにアクセスできるのを確認します。

![chat02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256958/e6c27b56-5f9d-a533-c0b8-8ca1f9f4a52e.png)



# まとめ

- ローカル環境でAgonesの開発環境を構築しました。
- phoenixで簡易チャットアプリを作成し、Agones上で動かしました。
- 次回はgameserver fleetを追加予定です。