#02 再現性のあるデプロイ | Game Server Services(GS2)

https://www.youtube.com/watch?v=XAZHmJrTC9k

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/702675bb-561c-186a-389e-12ae06695115.png)

第二回は再現性のあるデプロイについて説明します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/68c7ef08-030f-e56f-c73d-b2ebe8fa4f3e.png)

再現性のあるデプロイを実現する GS2 の機能が GS2-Deploy です。
GS2-Deploy を中心に説明したいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/3052104b-1dc2-d047-7480-28cde389d44b.png)

そもそも、再現性とはなんでしょうか？

名前の通り、繰り返し実行しても同じ状況が作れることを再現性と呼んでいます。
ゲームサーバーでは、開発環境・検証環境・製品環境 のように複数の環境を用意することが一般的です。
このとき、再現性がないと、環境を作るのが大変になってしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/71997881-7fdc-8514-7bbd-0a9f90bebd7b.png)

サーバーインフラの世界には Infrastructure as a Code という言葉があります。

以前はサーバーをセットアップする際に、都度コマンドを打ちながらミドルウェアなどをインストールしていました。
しかし、これでは再現性がないため、100台のサーバーをセットアップしようとおもうと途方もなく時間がかかってしまいます。
さらに、設定漏れなどによってちゃんとアプリケーションが動かないサーバーができてしまうかもしれません。

このような問題をなくすために生まれたのが Infrastructure as a Code です。
プログラミングのようにインフラストラクチャのセットアップをコードで行おう。という考え方です。
最初はコマンドを記録したレシピをサーバーに適用していくようなものでしたが、それも時間を追うごとに変化していきました。

一番大きな変化が「冪等性」という考え方です。
冪等性というのはくりかえし適用してもエラーや不正な状態にならず、同じ状態になる特性のことです。
つまり、アプリケーションをインストールする場合、すでにインストールされていた場合はインストールせずに成功とします。
こうすることで、最初にサーバーをセットアップするときだけでなく、更新する時にも使用できるようになります。

しかも、1ヶ月間更新していないサーバーに対して更新する場合も、昨日更新したサーバーに対して更新する場合も、同じ設定ファイルを使用してデプロイすれば、どちらも最新の状態になります。

このような設定ファイルはインストールのためのコマンドを羅列するというよりは、インストールされていて欲しいアプリケーションの種類やバージョンの一覧を記述したものになります。
このような設定ファイルを宣言的定義ファイルといいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/920ca8c2-41ca-71b2-3e86-9beb7330dd9b.png)

GS2-Deploy の宣言的設定ファイルはテンプレートという名前です。
テンプレートを記述し、GS2-Deploy にアップロードすると環境が出来上がります。

テンプレートファイルは宣言的にGS2で必要なリソースを定義します。
アカウント管理するネームスペースの種類や、アイテムを管理するネームスペースの種類、さらにアイテムにはどのような種類があり、所持数量の上限はいくつか。というようなマスターデータもここに含みます。

GS2-Deploy のテンプレートは更新にも対応します。
更新時には前回アップロードされたテンプレートとの差分を検出し、追加があれば作成・更新があれば更新・減っているものがあれば削除を行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/785d2f59-8451-fdcf-048d-60949629d452.png)

テンプレートファイルのサンプルを見てみましょう。

これは GS2-Identifier のユーザーを作成して、ApplicationAccess ポリシーを割り当てて、クレデンシャルを発行するテンプレートファイルです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/8ad71330-8740-db43-cf81-f0373d818f0d.png)

このテンプレートの中で一番重要なのは Resources セクションです。
ここで GS2-Deploy に対して作成して欲しいリソースを宣言します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/87eb436c-e1d1-dde4-fd6a-dc3f619d3aeb.png)

このテンプレートファイルでは3つのリソースを宣言しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/fc22d03f-b355-6fbe-a279-e78b62588b66.png)

最初にリソース名です。
IdentifierApplicationUser というのがリソース名で、ここには自由にリソースの名前をつけることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/0fb87398-b3a6-641f-01c0-6dfd622e7bb4.png)

Type には作成するリソースの種類を指定します。
ここでは GS2-Identifier のユーザーを作成することを指定しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/e994afc6-1e5b-c08f-9dca-a69be00060bb.png)

プロパティにはユーザーを作成するために必要となるパラメーターを設定します。
パラメーターについて掘り下げてみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/b038a410-bd54-1acc-775f-1b8a00f14eb1.png)

ユーザーの名前を指定しています。
今回は “User” という名前を指定しています。

これで、User という名前の GS2-Identifier のユーザーを作成して欲しい という設定になります。
前回のセッションで手動でマネージメントコンソールを操作して作成した内容を、まるでプログラミングのようにコードで記述できました。
これで GS2-Deploy が Infrastructure as a Code を使用した再現性のあるデプロイを実現しているということになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/26c67efc-9dfd-555c-5d2b-00e613fb7825.png)

次に、作成したユーザーにセキュリティポリシーを割り当てるリソース宣言です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/123ec89e-22d3-1882-cbec-7704afe9e22a.png)

新しい要素が出現しました。DependsOn です。
リソースが他のリソースに依存していることを宣言しています。

ユーザーにセキュリティポリシーを割り当てる前に、ユーザーを作成しておく必要がありますので、このようにユーザーのリソースに依存していることを、リソースの名前を指定して宣言します。
この宣言があると、GS2-Deploy はユーザーの作成が終わるまで、セキュリティーポリシーの割り当てのリソース作成を遅延させます。

この宣言がないと、場合によってはユーザーの作成より先にセキュリティポリシーの割り当てをしようとして、「ユーザーが存在しないため割り当てに失敗した」という理由でデプロイが停止してしまう可能性があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/f1844cfa-e297-4f63-0ea4-16a0d6d1ed52.png)

セキュリティポリシーの割り当てのパラメーターは、セキュリティーポリシーを割り当てる対象のユーザー名と、割り当てるセキュリティーポリシーのIDです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/c7e6817d-871d-78ca-5c2a-7d5f9b014159.png)

最後に、ユーザーのクレデンシャルを発行するリソース宣言です。
特に新しい要素はありませんね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/56065bfb-1c97-2de7-3fc4-e871b28e02fe.png)

最後に、Output セクションです。

ここでは、デプロイ処理の結果を記録することができます。
クレデンシャルのクライアントシークレットは発行時にしかわからないため、ここで記録しておかなければ確認する手段がなくなってしまいます。

!GetAttr という記述がありますが、これは GS2-Deploy で使用できる GetAttr 関数の呼び出しです。
スペースに続けて情報を取得したい リソース名 を記述し、リソースの作成APIの戻り値のなかで取得したいプロパティを指定しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/c668426b-7ebe-d41d-532e-f13fe430e649.png)

この時参考になるのがドキュメントページで確認できる createIdentifier API の Result の定義です。
クライアントシークレットは結果のルート階層にあり、クライアントID は Identifier型の item プロパティ のなかにあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/a30809aa-85a6-06bd-404a-7fbac65a64c5.png)

そのため、クライアントIDの記録部分は リソース名.Item.ClientId となっており

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/7b9becb0-b226-0989-62c5-5c49e9a20305.png)

クライアントシークレットの記録部分は リソース名.ClientSecret となっています

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/bd79bf73-92f0-0dd2-2226-84e191bac57a.png)

これで GS2 における継続的デプロイの座学は終了です。

それでは、ここからは前回のセッションで作成したリソースの作成内容を、GS2-Deploy のテンプレートを記述して作成してみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/f7ede028-dbd7-3b04-f599-449ff4447bd3.png)

まずは テンプレートファイル を作成します。
GS2ドキュメントに記載されているクレデンシャルを作成するテンプレートを雛形として作業を開始しましょう。
作成するユーザー名は前回のセッションに合わせて “User” にしておきます。

最初に GS2-Account の設定をしてみましょう。
GS2-Account のネームスペースを Account という名前で作成します。

次に、GS2-Key の暗号鍵を設定してみましょう。
GS2-Key のネームスペースを Key という名前で作成します。
続けて、AuthenticationKey という名前で暗号鍵を作成します。
この時に気をつけるのは、暗号鍵の作成は ネームスペースの作成 より後に実行する必要がありますので、DependsOn でネームスペースを設定する必要があることです。

```yaml
GS2TemplateFormatVersion: "2019-05-01"
Description: GS2 SDK identifier template Version 2019-07-10

Resources:
  AccountNamespace:
    Type: GS2::Account::Namespace
    Properties:
      Name: Account
  
  KeyNamespace:
    Type: GS2::Key::Namespace
    Properties:
      Name: Key
  
  Key:
    Type: GS2::Key::Key
    Properties:
      NamespaceName: Key
      Name: AuthenticationKey
    DependsOn:
      - KeyNamespace
  
  IdentifierApplicationUser:
    Type: GS2::Identifier::User
    Properties:
      Name: User

  IdentifierApplicationUserAttachPolicy:
    Type: GS2::Identifier::AttachSecurityPolicy
    Properties:
      UserName: User
      SecurityPolicyId: grn:gs2::system:identifier:securityPolicy:ApplicationAccess
    DependsOn:
      - IdentifierApplicationUser

  IdentifierApplicationIdentifier:
    Type: GS2::Identifier::Identifier
    Properties:
      UserName: User
    DependsOn:
      - IdentifierApplicationUser

Outputs:
  ApplicationClientId: !GetAttr IdentifierApplicationIdentifier.Item.ClientId
  ApplicationClientSecret: !GetAttr IdentifierApplicationIdentifier.ClientSecret
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/582192ed-c2ef-e0b6-b8fd-2f4d642ebf81.png)

それでは、マネージメントコンソールからテンプレートをアップロードして環境をセットアップしてみましょう。
前回手動で作成したリソースはすべて削除してあります。

サイドメニューから Deploy > Stacks を選択します。
スタックの新規作成を選択します。
スタックの名前に App を指定して、テンプレートファイルをアップロードします。

イベント一覧を見ていると、作成が進行していることが確認できます。

念の為にちゃんとリソースが作成されているかを確認します。
GS2-Account で “Account“ という名前のネームスペースが作成されていることを確認できました。
続けて、GS2-Key で “Key“ という名前のネームスペースが作成されており、AuthenticationKey という暗号鍵も作成されていることを確認できました。
最後に、GS2-Identifier でユーザーと、クレデンシャル、ポリシーの割り当てが終わっていることが確認できたら、確認は完了です。

スタックの詳細ページに戻り、アウトプットタブを開くと、Outputs セクションで設定したクライアントIDとクライアントシークレットが記録されています。
このクライアントIDとクライアントシークレットを使って、前回作成したプログラムが動作することを確認します。

前回手動で作成した GS2-Account のネームスペースで作成したアカウント情報が残っていますので、PlayerPrefs を削除して実行します。
ちゃんと動作しました。
GS2-Account でアカウントが作成されていることを確認して、すべての確認作業は終了です。

前回、手動でセットアップした環境構築を自動化できました。
これで、同じ GS2 の設定を他のアカウントやプロジェクトに用意するのも簡単に行えるようになりました。

テンプレートのアップロードはマネージメントコンソールを通さなくても、GS2-SDK を使用して実行することもできます。
これをうまく利用すると、ソースコードバージョン管理システムでテンプレートを管理し、develop ブランチで自動テストが通ったら、開発環境に自動的に反映するような設定も可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/ec701fc1-1a12-17e1-9696-c1febb09d474.png)

これまでの説明で GetAttr という関数があることがわかりましたが、他にも便利な関数があるのでしょうか

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/7ffff4f4-e511-1589-620c-4d30df38f6f0.png)

一つ目が エイリアス機能 です。

今回作成したテンプレートを振り返ってみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/b9ce3df6-0dca-d9f5-f771-f7422d567792.png)

ユーザー名の宣言が3箇所にあって、メンテナンス性が悪そうですね。
このような時に変数のように、値に別名をつけて利用できるようにするのが Alias です。

このテンプレートに Alias を適用するとこのようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/12d7631c-2f51-8f3c-9788-b2adae0eaead.png)

Globals セクションに Alias 宣言を追加します。
その下に、エイリアス名と値を宣言します。

あとは、エイリアスを使用したい部分で エイリアス名 を指定して記述することで使用することができます。
これでユーザー名を変更したい時変更する箇所を1箇所にすることができました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/2f31722b-fe19-60a1-cfae-a86e2f49f63b.png)

GetAttr 関数はリソースの作成結果の値を参照する以外にもできることがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/f47c49e1-da50-7115-2785-c0256e38e370.png)

1つめは、実行中の GS2 リージョンからリージョン名を取得すること
2つめは、実行中の 「GS2 アカウント + プロジェクト名」 で構成されるオーナーIDを取得することができます。

テンプレート内に GRN を埋め込む必要がある時には、この関数で取得した値を使用することでテンプレートのポータビリティをあげることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/d8d5456f-c496-62ca-d180-e8709d5b3201.png)

最後に Join 関数です。
Join 関数は文字列を結合することができる関数です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/f076e377-5a94-b26b-2dae-60b6459dc7f2.png)

Join 関数は1つの配列パラメータを受け取ります。

配列は2要素で構成されている必要があります。
1要素目には文字列を結合する際に結合部に追加する文字列を指定します。
2要素目には結合する文字列の配列を指定します。
この例では、GS2-Log のネームスペースGRN を Join 関数を使って組み立てて指定しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/63a79c6f-59b7-cd4e-598e-a2c73acaf430.png)

次回予告！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100723/a1b476bf-5888-b010-aa4c-59693de3f0e1.png)

せっかくログインするプログラムを作れたんだから、小難しいデプロイの話より、もっとゲームで使える機能の説明をして欲しかったよ。
そんなあなた。お待たせしました。次回はサーバーでアイテムの所持状況を管理する方法について解説します。

次回もお楽しみに。