TabpyをCloud Run(on GKE)で使う

Tabpyに触ったことなかったので、
Cloud Runの勉強も兼ねてTabpyをCloud Run(on GKE)で稼働させてみた時のメモ

**2021/6/17追記**
久々にTabpy調べてみたら、CloudRun（フルマネージド）で動くようになってたり、TableauOnlineでも使えるようになってた。。
Dockerイメージ作って、GCRにプッシュして、あとはCloudRunにデプロイするだけで終わり。
GKEクラスタの設定変えたり、カスタムドメイン設定したり、SSL証明書どうするかとかの考慮が一切不要になった。

#Tabpyとは
TableauとPythonを連携させ、Pythonで統計処理や機械学習した結果をTableauで可視化することができる仕組み
任意のPC、サーバにPythonモジュールをpipでインストールして、Tabpyサービスを起動させて、Tableauの外部サービス接続を使用してTabpyにアクセスする

#Cloud Runとは
https://cloud.google.com/run/?hl=ja
コンテナを動かすためのフルマネージドサービス
リクエスト処理時間に応じて課金
いい感じにオートスケールとかもしてくれるっぽいので、GKEよりさらにインフラの手がかからないが色々と制限ある（制限時間だったり、ポート指定だったり）
個人には何でも動かせるCloud Functions的なイメージ

on GKEとの違い
https://tomokazu-kozuma.com/the-difference-between-cloud-run-and-cloud-run-on-gke/

##なぜCloud Run on GKEなのか
Cloud RunだとTabpyに接続ができなかった。。
Cloud Runで自動で発行されるSSL証明書とTabpyのSSL化で使うSSL証明書との不整合が悪さしているのかもしれないがよくわからない。。。
（Clourd Runで自動発行される証明書は使用不可）

##開発環境
Cloud Shell使う前提

#TabpyをCloud Runにデプロイ
[Dockerfileとか](https://github.com/yakamazu/tabpy-cloudrun-ongke)

##GKEクラスタを作成（サンプル）
以下参考にセットアップ
https://cloud.google.com/run/docs/gke/setup

```shell:サンプルクラスタ作成
gcloud beta container clusters create <クラスタ名> \
   --machine-type=g1-small \
   --preemptible \
   --num-nodes=3 \
   --disk-size=10 \
   --zone=us-central1-a \
   --addons=HorizontalPodAutoscaling,HttpLoadBalancing,Istio,CloudRun \
   --cluster-version=latest \
   --enable-stackdriver-kubernetes \
   --enable-ip-alias \
   --scopes cloud-platform
```

すでに立てているGKEクラスタに対してCloud Runを有効にするには、下のキャプチャの青丸項目を上から順に有効にする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209773/2c726c69-a268-b96b-b62f-f40bd50c3c04.png)



##Dockerfileの作成
インストールするライブラリは必要に応じて追加する
pip installでtabpyインストールして、tabpy起動するだけで基本OKぽい

```dockerfile:Dockerfile
from continuumio/miniconda3:latest

ARG config_dir=/tmp/
ADD file.conf $config_dir

WORKDIR $config_dir

RUN pip install --upgrade pip && \
        pip install numpy pandas scikit-learn scipy textblob nltk vaderSentiment && \
        pip install reverse_geocoder geopy && \
        pip install tabpy==1.0.0

RUN tabpy-user add -u <username> -p <password> -f pwd.txt

ENV PORT 8080
EXPOSE 8080

ENTRYPOINT tabpy --config=file.conf
```

```:file.conf  
#このファイルはDockerfileと同じディレクトリに作る
[TabPy]
TABPY_PORT = 8080
TABPY_PWD_FILE = /tmp/pwd.txt
```

##Dockerイメージの作成
Dockerfileが格納されているディレクトリで以下コマンド実行。
tabpy-sampleというイメージが作成される。

```shell:
docker image build -t asia.gcr.io/<プロジェクトID>/tabpy-sample:latest .
```

##DockerイメージのPUSH
Container RegistryへのPush

```shell:
docker push asia.gcr.io/<プロジェクトID>/tabpy-sample:latest
```

##Cloud Run へのデプロイ

```shell:CloudRunOnGKE
gcloud beta run deploy tabpy-sample \
   --image asia.gcr.io/<プロジェクトID>/tabpy-sample \
   --platform gke \
   --cluster <GKEクラスタ名> \
   --cluster-location <ロケーション>
```

platformのオプションがmanagedになるとCloudRunへのデプロイになる

```shell:(参考)CloudRun
gcloud beta run deploy tabpy-sample \
   --image asia.gcr.io/<プロジェクトID>/tabpy-sample \
   --platform managed \
   --region <リージョン>
```

##カスタムドメインのマッピング
https://cloud.google.com/run/docs/mapping-custom-domains?hl=ja

Cloudrun on GKEにデプロイすると、
デフォルトではcurl経由でヘッダでホストを指定しないとサービスにアクセスできない
Tableauの外部接続サービスではヘッダの指定等できないのでカスタムドメインをマッピングしてアクセスする必要がある

###ドメインの所有権の確認
```shell:
gcloud domains verify [DOMAIN]
```

###サービスにドメインをマッピング
```shell:
gcloud beta run domain-mappings create --service [SERVICE] --domain [DOMAIN]
```

###DNSレコードデータを取得
```shell:
gcloud beta run domain-mappings describe --domain [DOMAIN]
```

###固定IPの予約（Cloudrun on GKEを使用している場合）
```shell:
gcloud compute addresses create [IP-NAME] --addresses [EXTERNAL-IP] --region [REGION]
```

EXTERNAL-IPはDNSレコードデータを取得の手順で取得したAレコードのIPアドレスを指定する


###ドメイン登録事業者で DNS レコードを追加する
https://cloud.google.com/run/docs/mapping-custom-domains?hl=ja#dns_update


##ハマりポイント
###Dockerfile
以下を参考に（丸パクリして）Dockerfile作ったが、少し古かった模様。。
https://github.com/erichannell/TabPy-docker
現在はpip installでtabpyインストール完了らしい。

公式のTabpyドキュメントを参考にDockerfile修正
https://github.com/tableau/TabPy/blob/master/docs/server-install.md#starting-tabpy

###Cloudrunデプロイ時のポート
CloudrunはリッスンPORTを8080に指定しなければならない
https://stackoverflow.com/questions/55662222/container-failed-to-start-failed-to-start-and-then-listen-on-the-port-defined-b
https://cloud.google.com/run/docs/reference/container-contract?hl=ja#port

Tabpyはデフォルトポートが9004なので、configファイル使ってポートを8080指定する必要がある
https://github.com/tableau/TabPy/blob/master/docs/server-config.md


#TableauでCloud Run上のTabpyへアクセス
##TableauDesktopから接続
上部ヘルプメニューから外部サービス接続の管理をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209773/246f022d-0587-dc75-02f6-911ffff49ad7.png)

サーバー：設定したカスタムドメイン
ポート：80
ユーザー名：Dockerfileで設定したユーザー
パスワード：Dockerfileで設定したユーザー


##TableauServerから接続

###Tableau Serverでの外部サービス接続許可
https://help.tableau.com/current/server-linux/ja-jp/config_r_tabpy.htm
https://help.tableau.com/current/server-linux/ja-jp/cli_security_tsm.htm#tsm_security_vizql-extsvc-ssl-enable

TableauServerのコマンドラインで以下を実行

```shell:tableauserverで外部サービスの有効化
tsm security vizql-extsvc-ssl enable --connection-type tabpy --extsvc-host <ホスト名> --extsvc-port <PORT> --extsvc-username <Tabpyユーザー名> --extsvc-password <Tabpyパスワード>

tsm pending-changes apply
```


###現時点（2020年1月）ではTableauOnlineからは使えないようです。。。
orz
https://help.tableau.com/current/pro/desktop/ja-jp/r_connection_manage.htm

>外部サービス スクリプトを含むワークブックは Tableau Online にパブリッシュできません。

#色々と参考にしたページ
[Dockerを使ってコンテナでTabpyを動かそう！](http://lovedata.main.jp/2018/11/20/docker%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6mac%E3%81%A7%E3%82%82tabpy%E3%82%92%E5%8B%95%E3%81%8B%E3%81%9D%E3%81%86%EF%BC%81/)

[Google Cloud Runのポートについて考える](https://qiita.com/shuichiro/items/8e3f3e870481cac9aec9)

[Cloud Run on GKEに覗くKnative](https://qiita.com/toshi0607/items/eeeabe81b1beac343b6b#cloud-run-on-gke%E3%81%AE%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4)