Tunaclo API Connect をさわってみた

#1. はじめに

皆さん、こんにちは。
[FUJITSU Advent Calendar 2020](https://qiita.com/advent-calendar/2020/fujitsu) の記事として、[Tunaclo API Connect](https://support.tunaclo.jp.fujitsu.com/) をさわってみたレポートを書きます。どうぞよろしくお願いします。

#2. Tunaclo API Connectとは？

Tunaclo API Connect は、2020/02/12にGA(一般公開)された、新しいサービスです。
クラウド間を簡単に「つなぐ」というコンセプトのサービスだと思います。
VPNやBGP等の知識は不要。サービスをインターネットに公開することも不要で、
AWSやGCPで動くK8s podと、Azureで動くコンテナ間を、さくっとつなぐ　といったことや、Webベースのものを色々と簡単につなぐ事ができます。(説明雑？)

Tunaclo API Connectの詳しい説明や、開発秘話といった中の人のお話は、
[CloudNative Days Tokyo 2020 アーカイブ](https://event.cloudnativedays.jp/cndt2020/talks?) で聞くことができます。

- [とある少人数のサービス開発チームのクラウドネイティブへの船出の話](https://speakerdeck.com/hiro_kamezawa/toarushao-ren-shu-timufalsecloudnativehefalsechuan-chu-falsehua)
- [Tunaclo API Connectで実現する次世代のクラウド間アクセス](https://event.cloudnativedays.jp/cndt2020/talks/49)

なお、Tunaclo API Connectは、Tunaclo ACと略します。
ところで私は中の人ではなく、中の人と技術コミュニティでご一緒させて頂いているものです。

※以下、Tunaclo ACのスライドによく登場するマスコットキャラクターでよいのかな？TUNACLOくん？

![tunaclo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48782/08dab9aa-7db7-bdf6-5f46-c8f124d87cb8.png)

#3. やってみたレポート

では、さっそく手を動かしていきます。
[Tunaclo AC GUIを使ったクイックスタート](https://support.tunaclo.jp.fujitsu.com/documents/quick-start/gui/)読んでみました。
このチュートリアルでは、LinuxでWebサービスとクライアントを、お互いに別々のネットワークで構築し、Tunaclo ACで接続するというシンプルな構成例です。

```
　クラウドA：Webサービス(Nginx Dockerコンテナ) ※インターネット公開していない
　クラウドB：クライアント(curlコマンド)

　クラウドB --- Tunaclo AC --- クラウドA
```
という感じです。

そのままチュートリアルに沿って実施しても良いのですが、今回は少し構成を変更してみようと思います。
以下のように[Azure コンテナインスタンス](https://docs.microsoft.com/ja-jp/azure/container-instances/container-instances-overview)、[Mattermost](https://mattermost.com/)、[AWS Workspaces](https://aws.amazon.com/jp/workspaces/)という素材を組み合わせて、コンセプトどおりに、**Tunaclo AC でクラウド間をつないでみます。**

```
　Azure：コンテナインスタンス Mattermostコンテナ ※インターネット公開していない
　AWS：Workspaces(Windows10) Webブラウザ

　AWS --- Tunaclo AC --- Azure
```

以下作業の流れです。
まず最初にTunaclo ACでルートを作成します。
次に、Azure コンテナインスタンス上に、Mattermostのコンテナと、Tunaclo ACのBack Agentコンテナを作成します。
そして、AWS Workspaces上でTunaclo ACのFront Agentアプリケーションを動作させます。
最後に、AWS Workspaces上のWebブラウザを使用し、インターネット公開していないMattermostに対して、Tunaclo ACを経由してアクセスしたいと思います。

##3.1. Tunaclo ACでルートを作成する

チュートリアルを参考に、Tunaclo ACのポータルにログインして、ルートを作成してみます。
以下コンポーネントと用語の説明([ユーザーズガイド](https://support.tunaclo.jp.fujitsu.com/documents/guides/)から引用)

|コンポーネント名|説明|
|---|---|
|Tunaclo AC ポータル|ユーザー用ポータルです、GUI を提供します。|
|CLI ツール|ユーザー用コマンドラインツールです、CLI を提供します。|
|Tunaclo AC コントローラー|サービス全般の各種管理機能を提供し、Tunaclo AC 提供元で管理しています。|
|Tunaclo AC ルーター|Tunaclo AC コントローラーの設定に基づいて、API 通信をルーティングします。Tunaclo AC 提供元で管理しています。|
|Front Agent|Web API 呼び出し側のデータセンター（または拠点）内に設置する軽量の Agent ソフトウェアです。Web サービスとして動作しユーザーからのリクエストを Tunaclo AC ルーターに転送します。|
|Back Agent|Web API 提供側のデータセンター（または拠点）内に設置する軽量の Agent ソフトウェアです。Tunaclo AC ルーターから受信したリクエストを Web API を提供しているサーバーに転送します。|

|用語|説明|
|---|---|
|サービス|Tunaclo AC における Web API を提供する側の管理単位です。複数の Web API を束ねて 1 つのサービスとして管理することも可能です。ユーザーは Tunaclo AC ポータルからサービスを作成することで、Back Agent が Tunaclo AC ルーターとの間でセキュアーコネクションを確立できるようになります。|
|クライアント|Tunaclo AC における Web API にアクセスする側の管理単位です。ユーザーは Tunaclo AC ポータルからクライアントを作成することで、Front Agent が Tunaclo AC ルーターとの間でセキュアーコネクションを確立できるようになります。|
|ルート|Tunaclo AC における、サービスとクライアント間の通信許可です。ユーザーは Tunaclo AC ポータルからルートを作成することで、Front Agent 経由でリモートの Web API を呼び出すことが可能となります。|
|Service URL|サービスの属性の 1 つで、実際にアクセスされる Web API のURL です。1 つのサービスには複数のService URL をまとめて紐づけることが可能です。|
|Virtual URL|サービスの属性の 1 つで、リモート側で Web API を呼び出すための仮想的な URL です。なお、Service URL とは１対１の対応関係を持ちます。|
|通信先 ID|Tunaclo AC のライセンスの管理単位です。Tunaclo AC 上で作成されたサービスおよびクライアント単位に通信先 ID が付与されます。なお、利用可能な通信先 ID の合計数はご契約の内容に応じて変わります。|

Tunaclo AC ポータルにログインしました。
シンプルなUIで分かりやすいです。「New route」をクリックします。

![tunaclo1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48782/d6e4f4f0-4402-ec74-c7df-068245b4ca35.png)

ClientとServiceを作成します。それぞれボタンを押していきます。

![tunaclo2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48782/ba8cfecb-9d1c-a0a0-0d47-a59995c2ff6f.png)

ClientがAWS Workspaces側です。名前を入力するだけです。

ServiceがAzure コンテナインスタンスのMattermost側です。名前、Virtual URL、Service URLを入力します。

Service URLがMattermostのURLです。
Mattermostはこれから作成するので、まだIPアドレスが決まっていません。ですので適当なプライベートIPアドレスで入力しておけば良いです。あとで変更します。※画面の http\://10.0.2.4:8065 は変更後の設定値です。

Virtual URLがAWS Workspacesから、Mattermostに接続する際に使用するURLです。
ここでは http\://127.0.0.1:30000 を入力しています。client側であるAWS Workspacesには、Front Agentをインストールします。
Front AgentがTCPポート30000で待ち受け、通信をTunaclo AC ルーターにルーティングするという仕組みだと思います。

「Create route」をクリックしてルート作成を完了させます。

```
AWS Workspaces --- Front Agent --- Tunaclo AC ルーター --- Back Agent --- Mattermost
```

![tunaclo3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48782/772f64f2-3a9e-290c-a0c8-46d209ff3c01.png)

ルートができました。
ClientとServiceで0/1となっているのは、未接続を表しているという事。

![tunaclo4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48782/662cd2cf-5711-77bd-a9eb-0ac907954ac2.png)

##3.2. AzureのコンテナインスタンスでMattermostとBack Agentを起動する

では、Service側を作っていきます。
AzureのAzure Container Instancesに、コンテナグループを使用して、MattermostコンテナとBack Agentコンテナを作成します。

先程のTunaclo AC ポータルに、DockerでBack Agentを起動させる為のコマンドライン例が表示されているので、参考にします。
各パラメータはすべてTunaclo AC ポータルで確認できます。

```
docker run -d --restart=unless-stopped --log-opt max-size=20m --log-opt max-file=5 --name サービス名 tunacloac/backagent:v1.2.1 \
  back_agent \
  -controller https://Tunaclo ACのAPIエンドポイント \
  -projectID プロジェクトID \
  -agentID サービスID \
  -agentKey サービスキー
```

Azure Container Instancesでは、コンテナグループを使用して、複数のコンテナを1つのホストにデプロイできます。
しかし、コンテナグループはAzure Portalでの作成をサポートしておらず、CLI操作が必要です。以下リンクを参考にしながら、ARMテンプレートを作成し、デプロイしました。

- [チュートリアル:Resource Manager テンプレートを使用してマルチコンテナー グループをデプロイする](https://docs.microsoft.com/ja-jp/azure/container-instances/container-instances-multi-container-group)
- [Microsoft.ContainerInstance containerGroups template reference](https://docs.microsoft.com/ja-jp/azure/templates/microsoft.containerinstance/containergroups)

また、データ永続化目的で、Azureストレージアカウントにmattermostのデータを保存できるようにしました。

- [Azure Container InstancesにAzureファイル共有をマウントする](https://docs.microsoft.com/ja-jp/azure/container-instances/container-instances-volume-azure-files)

DockerでBack Agentを起動させる為のコマンドライン例を参考に、
Azure Container InstancesのARMテンプレートでの定義に変換しました。
以下のARMテンプレートで作成します。

```azuredeploy.json
{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "containerGroupName": {
      "type": "string",
      "defaultValue": "myContainerGroup",
      "metadata": {
        "description": "myContainerGroup"
      }
    }
  },
  "variables": {
    "container1name": "mattermost-preview",
    "container1image": "mattermost/mattermost-preview",
    "container2name": "myservice-agent",
    "container2image": "tunacloac/backagent:v1.2.1",
  },
  "resources": [
    {
      "name": "[parameters('containerGroupName')]",
      "type": "Microsoft.ContainerInstance/containerGroups",
      "apiVersion": "2019-12-01",
      "location": "[resourceGroup().location]",
      "properties": {
        "containers": [
          {
            "name": "[variables('container1name')]",
            "properties": {
              "image": "[variables('container1image')]",
              "resources": {
                "requests": {
                  "cpu": 1,
                  "memoryInGb": 2
                }
              },
              "ports": [
                {
                  "port": 8065
                }
              ],
              "volumeMounts": [
                {
                  "name": "filesharevolume1",
                  "mountPath": "/mm/mattermost/mattermost-data"
                },
                {
                  "name": "filesharevolume2",
                  "mountPath": "/var/lib/mysql"
                }
              ]
            }
          },
          {
            "name": "[variables('container2name')]",
            "properties": {
              "image": "[variables('container2image')]",
              "resources": {
                "requests": {
                  "cpu": 1,
                  "memoryInGb": 1
                }
              },
              "command": [
                  "back_agent",
                  "-controller",
                  "https://Tunaclo ACのAPIエンドポイント",
                  "-projectID",
                  "プロジェクトID",
                  "-agentID",
                  "サービスID",
                  "-agentKey",
                  "サービスキー"
              ],
            }
          },
        ],
        "osType": "Linux",
        "imageRegistryCredentials": [
          {
            "server": "index.docker.io",
            "username": "コンテナレジストリ ユーザID",
            "password": "コンテナレジストリ パスワード"
          }
        ],
        "restartPolicy": "Always",
        "ipAddress": {
          "type": "private",
          "ports": [
            {
              "protocol": "tcp",
              "port": 8065
            }
          ]
        },
        "networkProfile": {
            "id": "ネットワークプロファイルID"
        },
        "diagnostics": {
          "logAnalytics": {
            "workspaceId": "ワークスペースID",
            "workspaceKey": "ワークスペースキー",
          }
        },
        "volumes": [
          {
            "name": "filesharevolume1",
            "azureFile": {
                "shareName": "ストレージアカウント ファル共有名",
                "storageAccountName": "ストレージアカウント名",
                "storageAccountKey": "ストレージアカウント アクセスキー"
            }
          },
          {
            "name": "filesharevolume2",
            "azureFile": {
                "shareName": "ストレージアカウント ファル共有名",
                "storageAccountName": "ストレージアカウント名",
                "storageAccountKey": "ストレージアカウント アクセスキー"
            }
          }
        ]
      }
    }
  ],
  "outputs": {
    "containerIPv4Address": {
      "type": "string",
      "value": "[reference(resourceId('Microsoft.ContainerInstance/containerGroups/', parameters('containerGroupName'))).ipAddress.ip]"
    }
  }
}
```

Tunaclo AC提供のDockerコマンド例を、Azure Container Instancesに置き換える際のポイントは以下のとおりでした。

- コンテナ名は、大文字不可です。大文字が含まれている場合、デプロイ時にエラーとなります。小文字にしましょう。

```
Deployment failed. Correlation ID: ***********. {
  "error": {
    "code": "InvalidContainerName",
    "message": "The container name 'MyService-agent' in container group 'myContainerGroup' is invalid. The container name must contain no more than 63 characters and must match the regex '[a-z0-9]([-a-z0-9]*[a-z0-9])?' (e.g. 'my-name')."
  }
}
```

- Azure Container InstancesのARMテンプレートではコマンド実行は以下のように記述します。

```
              "command": [
                  "back_agent",
                  "-controller",
                  "https://Tunaclo ACのAPIエンドポイント",
                  "-projectID",
                  "プロジェクトID",
                  "-agentID",
                  "サービスID",
                  "-agentKey",
                  "サービスキー"
              ],
```

- Back AgentのコンテナイメージはDocker Hubから取得しますが、認証が必要です。以下のように記述します。

```
         "imageRegistryCredentials": [
          {
            "server": "index.docker.io",
            "username": "コンテナレジストリ ユーザID",
            "password": "コンテナレジストリ パスワード"
          }
        ],
```

- コンテナインスタンスが所属するサブネットの指定方法は以下になります。

```
        "networkProfile": {
            "id": "ネットワークプロファイルID"
        },
```

ネットワークプロファイルIDは以下コマンドで取得できます。※[コンテナー インスタンスを Azure 仮想ネットワークにデプロイする](https://docs.microsoft.com/ja-jp/azure/container-instances/container-instances-vnet)

```
az network profile list --resource-group myrg --query [0].id --output tsv
```

- コンテナの再起動ポリシーはunless-stoppedは設定できなかったので、Alwaysで代用しました。※[コンテナー再起動ポリシー](https://docs.microsoft.com/ja-jp/azure/container-instances/container-instances-restart-policy)

```
        "restartPolicy": "Always",
```

- ログ出力の定義(--log-opt max-size=20m --log-opt max-file=5)は設定できなかったので、Log Analytics ワークスペースへの出力で代用しました。※[Azure Monitor ログによるコンテナー グループおよびインスタンスのログ記録](https://docs.microsoft.com/ja-jp/azure/container-instances/container-instances-log-analytics)

```
        "diagnostics": {
          "logAnalytics": {
            "workspaceId": "ワークスペースID",
            "workspaceKey": "ワークスペースキー",
          }
        },
```


作成したARMテンプレートを使用して、Azure CloudShellからデプロイ実行しました。

```
$ az deployment group create --resource-group myrg --template-file azuredeploy.json

 (省略)
    "outputs": {
      "containerIPv4Address": {
        "type": "String",
        "value": "10.0.2.4"
      }
    },
 (省略)

```

無事コンテナが立ち上がりました。
プライベートIPアドレスは、10.0.2.4です。
繰り返しになりますが、グローバルIPアドレスを付与してINトラフィックのファイアウォール開放するといった事は不要です。

Azure Portal Container Instances 画面:
![tunaclo5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48782/4d09c430-5d8c-c748-f63d-5bd0cf185761.png)

Tunaclo AC ポータルのルート状態を見てみると、Serviceの表示色が灰色から緑色に変わり、0/1から1/1になりました。

![tunaclo8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48782/eb5eb6c4-cfdb-fc18-1bd9-1ba1b55ca888.png)


##3.3. AWS WorkSpaces(Windows10)でFront Agentを起動する

AWSでWorkSpacesを作成します。次にFront Agentをインストールして起動します。
WorkSpacesは、Standard with Windows 10 (Japanese) PCoIPを使用しました。

![tunaclo7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48782/0c592bfb-db90-9bbd-4260-eae3c10b13c1.png)

WorkSpacesの作成が完了しました。

![tunaclo9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48782/6e90d3b6-4fe7-e762-f701-e479246a740c.png)

この後、AWSからWorkSpacesクライアントアプリケーションのダウンロードやログイン方法が記載されたEメールが到着します。メールの内容に従って、WorkSpacesに接続します。
以下のように、色々なOS向けのクライアントアプリがあるようです。

![tunaclo10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48782/50999cd2-1c6b-d4df-4b14-8819843de35c.png)

WorkSpacesにログインできました。

![tunaclo12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48782/aa2f9bda-2c5c-4045-c042-897728071a14.png)

ではFront Agent (Windows版)をインストールします。※Front Agentは、コンテナ版とWindows版があります。

Front Agent (Windows版)は、Tunaclo AC ポータルからダウンロードできます。
Front Agent (tunaclo-connect-client) を起動し、設定ファイルを読み込みます。

![tunaclo13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48782/47cb1934-609c-9991-e747-15193d3b3c9b.png)

設定ファイルの雛形は、tunaclo-connect-client\template\agent_config_template.yamlにあります。

```agent_config_template.yaml　※コメント文省略
projectID: プロジェクトID
agentName: クライアント名
agentID: クライアントID
agentKey: クライアントキー
agentMode: "frontAgent"
httpservers:
  - "127.0.0.1:30000"
httpsservers:
  - "127.0.0.1:30001"
```

設定ファイルを読み込ませ、起動ボタンをクリックすると、Front Agentが起動します。

![tunaclo14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48782/a3b4f35a-1c28-d5c5-188a-0380ea58fb48.png)

Tunaclo AC ポータルのルート状態を見てみると、Clientも表示色が灰色から緑色に変わり、0/1から1/1になりました。

![tunaclo15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48782/3cc0b4c5-8b2e-0f8c-290b-4ab76bfc110c.png)

##3.4. TunacloAC経由でMattermostに接続する

では、AWS WorkSpacesから、Tunaclo AC経由で、Azure上のMattermostにアクセスしてみます。
WebブラウザのURL欄に **http\://127.0.0.1:30000** と入力します。

**無事にアクセス成功です。ログイン画面が表示できました！**

![tunaclo16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48782/7dfd7984-a81e-3356-934b-0f0489f1f501.png)

書き込みも問題なくできています。
AWS Workspaces上のWebブラウザから、インターネット公開していないMattermostに対して、Tunaclo ACを経由してアクセスできました。

　**hello world!**

![tunaclo18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48782/33b495f8-5d13-6952-f8dd-2678e77bc0a8.png)

#4. おわりに

今回、Tunaclo AC さわってみたレポートとして、AWSとAzureをTunaclo ACでつないでみました。IPsecVPNもBGPも、ファイアウォールの開放も不要でした。
本レポートでは、Azure コンテナンスタンスや、AWS WorkSpacesの説明も、いっしょにしていたので、話が長くなりましたが、
**Tunaclo AC自体の構築は、非常に簡単で短手番なものでした。**
Tunaclo ACポータルにログインして云々という事も省きたい場合は、ちゃんと[CLI](https://support.tunaclo.jp.fujitsu.com/documents/guides/cli/)も用意されています。Tunaclo ACについては、まったくの初心者だったのですが、UIもマニュアルも大変分かりやすかったです。
インターネット公開していないサービスに、Tunaclo ACで接続できた時には、不思議な感動を味わう事ができました。ぜひ、皆さんにも接続を体験してもらえると嬉しいです。

ところで、Tunaclo ACのFront Agnetはちゃんとコンテナ版もあるので(むしろWindowsアプリ版が後発とのこと)、異なるK8sクラスタ間の接続も、同じように可能ということでした。
**つなげる**ということにフォーカスするなら、サービスメッシュやレイヤ3トンネリングのような、ちょっと小難しい事を考える必要もないのかな？と思います。
なお、[Kubernetesで動作させる際のManifestサンプル（コンテナ版）](https://support.tunaclo.jp.fujitsu.com/documents/resource/tips/k8s-manifest-sample/)も公開されていますので、こちらもご参考まで。
やってみた感想として、Tunaclo ACはとても簡単で、学習コストがものすごく低かったです。
本当に、簡単にクラウドがつながりました。

読んで頂き、どうもありがとうございました！

以上です。



#5. おまけ(追記)

## 5.1 Tunaclo ACの耐障害性(冗長化)について

Tunaclo ACの冗長化ってどうなってるの？とコメントいただきまして
調べたところ、Tunaclo ACサポートページのFAQに記事がありました。
　[FAQ：Tunaclo ACルーターの冗長化構成について教えてほしい。](https://support.tunaclo.jp.fujitsu.com/documents/faq/disasterrecovery/)
ルータ2台構成かな？と思っていたのですが、なんと4台構成でした...
東日本に2台、西日本に2台あり、データプレーンが多重化されているとのこと。
リージョンの冗長化もしているんですね。頼もしい...

> Tunaclo AC では Pro基本サービス、および Enterprise基本サービスご契約のプロジェクトに対して、Tunaclo AC ルーターを冗長化構成でご提供しています。
　(省略)
> Tunaclo AC では１つのプロジェクトに４つのルーターインスタンスが提供されます。これらルーターインスタンスは異なるハードウェア上で稼働するよう構成されます。
　(省略)
> Agent がデータ通信に使用しているルーターインスタンスに障害が発生した場合、あるいはルーターインスタンスとの通信経路に障害が発生した場合、同じデータセンター内のルーターインスタンスにデータ通信チャネルが片寄せされます
　(省略)
> 東日本データセンターの全てのルーターインスタンスに障害が発生した場合、あるいは全てのルーターインスタンスとの通信経路に障害が発生した場合、西日本データセンター内のルーターインスタンスにデータ通信チャネルがフェイルオーバーされます。これらの障害発生時の動作は Agent ソフトウェア、およびルーター間で自動的に検知・実行されます。

以上です。