Google Cloud FunctionsでPythonを利用してみた(Beta利用)

Googleさんからサーバーレス関連のサービス強化がアナウンス(2018/08/03)されました。
そのなかで、Cloud Functionsも正式提供やBetaで機能強化されています。

サーバーレス コンピューティングの実現に向けて
https://cloudplatform-jp.googleblog.com/2018/08/bringing-the-best-of-serverless-to-you.html

>また、イベント駆動型のコンピュート サービスである Cloud Functions の正式提供も開始しました。Cloud Functions では予測可能なサービスが SLA で保証されるようになり、グローバル ネットワーク フットプリントを利用して提供され、欧州とアジアでリージョンも追加されました。さらに、Python 3.7 と Node.js 8 のサポートや、ネットワーキングとセキュリティの管理など、お客様からの要望が高かった新機能で強化されており、全体的なパフォーマンスも向上しています。Cloud Functions は、BigQuery、Cloud Pub/Sub、機械学習 API、G Suite、Google アシスタント など 20 以上の GCP サービスをシームレスに接続して拡張できます。


というわけで、Cloud FunctionsでPython 3.7が対応(Beta)されたとのことで、早速利用してみました。


## 追記

2019/04/01にPython 3.7がGAされていました。
※本投稿はGA前の2018/08/07時点で利用してみた内容となります。

Your favorite runtimes, now generally available on Cloud Functions | Google Cloud Blog
https://cloud.google.com/blog/products/application-development/your-favorite-runtimes-now-generally-available-on-cloud-functions

>Google Cloud Next ‘19:
>
>- Python 3.7, Go 1.11 and Node.js 8 runtimes are now generally available.
>- Node.js 10 runtime is now in public beta.
>- Go 1.12 and Java 8 runtimes are in private alpha (sign up to test Go 1.12 and Java 8).


## 準備

GCP プロジェクトの選択・作成やAPIの有効化などは実施済みの前提です。
まだの方は下記の「始める前に」をご参考ください。

https://cloud.google.com/functions/docs/tutorials/http?hl=ja


## 管理コンソールから関数を作成する

Cloud Functionsの[関数を作成]ボタンをポチッと。

<img width="697" alt="Cloud_Functions_-_関数を作成.png" src="https://qiita-image-store.s3.amazonaws.com/0/48549/b0a95497-9bfe-5bc8-a279-1dc2c2baf32a.png">

[ランタイム]プルダウンメニューをみると[Python 3.7]が選べます！
ただし[(Beta)]がついてます。Node.js 8もしれっと増えてます。
名前は任意で入力してください。

<img width="477" alt="Cloud_Functions_関数作成.png" src="https://qiita-image-store.s3.amazonaws.com/0/48549/afba9cb0-62e1-5415-6411-0bed91a384c8.png">

今回はトリガーを[HTTP]でサンプルそのままで関数を作成してみます。

<img width="470" alt="Cloud_Functions_関数作成2.png" src="https://qiita-image-store.s3.amazonaws.com/0/48549/6a6d8fe5-afc5-e363-c0b6-b76b8e145035.png">

関数作成中。Stackdriver Loggingでログも確認できます。

<img width="841" alt="Cloud_Functions_関数作成中.png" src="https://qiita-image-store.s3.amazonaws.com/0/48549/c7774cfc-bd9c-b243-10fd-d5e04fe28493.png">

管理コンソールでテストしてみた。動いてますね^^

<img width="554" alt="Cloud_Functions_テスト.png" src="https://qiita-image-store.s3.amazonaws.com/0/48549/a5eb8452-b7b4-4645-8d13-ad6f7e69e7dc.png">

CurlでGETしてみた。
URLは[トリガー]から確認できます。

```sh
> curl https://us-central1-xxx.cloudfunctions.net/cloud-functions-python-test
Hello World!
```

パラメータも受け取ってくれました。

```sh
> curl "https://us-central1-xxx.cloudfunctions.net/cloud-functions-python-test?message=h
oge"
hoge
```

お手軽ですね^^


## gcloudコマンドラインツールから利用してみる

続いてはコマンドラインツールから試してみます。


### Google Cloud SDKのインストール

インストールがまだの方は下記をご参考ください。
```gcloud init```まで完了した前提です。

MacでCloud Machine Learning Engineを利用してみる
https://qiita.com/kai_kou/items/0952c9b28efe19f2f680#google-cloud-sdk%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB

```sh
> gcloud --version

Google Cloud SDK 209.0.0
bq 2.0.34
core 2018.07.16
gsutil 4.33
Updates are available for some Cloud SDK components.  To install them,
please run:
  $ gcloud components update
```

```gcloud```コマンドが利用できるようになったらCloud Functions関連のコマンドをためてしてみます。

```gcloud functions```コマンドは209.0.0 (2018-07-18)でGAとなったようですね。
バージョンが古い方は、各自、自己責任で```gcloud components update```してください^^

Google Cloud SDK - Release Notes
https://cloud.google.com/sdk/docs/release-notes



### チュートリアルに沿ってデプロイまでやってみる

公式ドキュメントを参考にしてデプロイできるところまで進めてみます。
残念ながら、まだ言語はNode.jsだけでした。(2018/08/07現在)

HTTP のチュートリアル
https://cloud.google.com/functions/docs/tutorials/http?hl=ja

※ページの言語設定(ページ左下)を英語に変更するとNode.js8とPythonも追加されています。@uu4k さん情報あざます！(2018/08/20追記)

<img width="730" alt="スクリーンショット 2018-08-20 9.33.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/48549/ec6439b4-ae69-1e21-d5ad-a5cdcd68ab02.png">


#### コードの準備

関数を作成するのにコードを用意します。
実装は上記でも利用した公式のサンプルをそのまま利用します。

今回はサンプルなので、```pip```でライブラリをインストールすることはないですが、念の為、仮想環境を作っておきます。

仮想環境ってなに？という方は下記をご参考。
Pythonもローカル実行しないのであれば、3系で```venv```が利用できたらなんでも。

Macでanyenvをつかってpython環境構築(bash、fish対応)
https://qiita.com/kai_kou/items/f54931991a781b96bb9c


```sh:仮想環境の作成
> mkdir 任意のディレクトリ
> cd 任意のディレクトリ
> python -m venv function-test
> . function-test/bin/activate

# fishの方はこちら
> . function-test/bin/activate.fish
```

```sh
main.pyの作成
> touch main.py
> vi main.py
```

```python:main.py
def hello_world(request):
    """Responds to any HTTP request.
    Args:
        request (flask.Request): HTTP request object.
    Returns:
        The response text or any set of values that can be turned into a
        Response object using
        `make_response <http://flask.pocoo.org/docs/0.12/api/#flask.Flask.make_response>`.
    """
    request_json = request.get_json()
    if request.args and 'message' in request.args:
        return request.args.get('message')
    elif request_json and 'message' in request_json:
        return request_json['message']
    else:
        return f'Hello World!'
```

#### 関数をデプロイする前に

Python 3.7はまだBeta提供なので、```gcloud functions deploy```コマンドでデプロイすることができませんでした。(2018/08/7時点)

```sh
> gcloud functions deploy hello_world --trigger-http

Deploying function (may take a while - up to 2 minutes)...failed.
ERROR: (gcloud.functions.deploy) OperationError: code=3, message=Function load error: File index.js or function.js that is expected to define function doesn't exist in the root directory.
```

なので、```gcloud beta```コマンドが利用できるようにします。

```sh
> gcloud beta
You do not currently have this command group installed.  Using it
requires the installation of components: [beta]


Your current Cloud SDK version is: 210.0.0
Installing components from version: 210.0.0

┌─────────────────────────────────────────────┐
│     These components will be installed.     │
├──────────────────────┬────────────┬─────────┤
│         Name         │  Version   │   Size  │
├──────────────────────┼────────────┼─────────┤
│ gcloud Beta Commands │ 2018.07.16 │ < 1 MiB │
└──────────────────────┴────────────┴─────────┘

For the latest full release notes, please visit:
  https://cloud.google.com/sdk/release_notes

Do you want to continue (Y/n)?
(略)
For detailed information on this command and its flags, run:
  gcloud beta --help
```

インストールできたらコマンドが利用できるか確認します。

```sh
> gcloud --version

Google Cloud SDK 210.0.0
beta 2018.07.16
bq 2.0.34
core 2018.07.27
gsutil 4.3
```

#### 関数をデプロイする

```gcloud beta```コマンドが利用できるようになったら、[HTTP]トリガーでデプロイしてみます。
```gcloud beta functions deploy```コマンドのパラメータは```--help```か下記をご参考。
```--runtime```オプションがありました^^

gcloud beta functions deploy
https://cloud.google.com/sdk/gcloud/reference/beta/functions/deploy?authuser=19&hl=ja

ではデプロイしてみます。

```sh
> gcloud beta functions deploy hello_world --trigger-http --runtime=python37

Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
entryPoint: hello_world
httpsTrigger:
  url: https://us-central1-xxx.cloudfunctions.net/hello_world
labels:
  deployment-tool: cli-gcloud
name: projects/xxx/locations/us-central1/functions/hello_world
runtime: python37
(略)
status: ACTIVE
timeout: 60s
updateTime: '2018-08-07T03:07:17Z'
versionId: '3'
```

デプロイが完了しましたので、HTTPアクセスしています。

```sh
> curl https://us-central1-xxx.cloudfunctions.net/hello_world
Hello World!

> curl "https://us-central1-xxx.cloudfunctions.net/hello_world?message=hoge"
hoge
```
はい。

動作していますね^^


#### その他コマンド

```list``` コマンドはbetaでもかわりなし。

```sh
> gcloud functions list
NAME                         STATUS  TRIGGER        REGION
cloud-functions-python-test  ACTIVE  HTTP Trigger   us-central1
hello_world                  ACTIVE  HTTP Trigger   us-central1

> gcloud beta functions list
NAME                         STATUS  TRIGGER        REGION
cloud-functions-python-test  ACTIVE  HTTP Trigger   us-central1
hello_world                  ACTIVE  HTTP Trigger   us-central1
```

```describe``` コマンドは```updateTime```と```versionId```が追加されてました。

```sh
> gcloud functions describe hello_world
availableMemoryMb: 256
entryPoint: hello_world
httpsTrigger:
  url: https://us-central1-xxx.cloudfunctions.net/hello_world
labels:
  deployment-tool: cli-gcloud
name: projects/xxx/locations/us-central1/functions/hello_world
runtime: python37
serviceAccountEmail: (略)
sourceUploadUrl: (略)
timeout: 60s

> gcloud beta functions describe hello_world
availableMemoryMb: 256
entryPoint: hello_world
httpsTrigger:
  url: https://us-central1-xxx.cloudfunctions.net/hello_world
labels:
  deployment-tool: cli-gcloud
name: projects/xxx/locations/us-central1/functions/hello_world
runtime: python37
serviceAccountEmail: (略)
sourceUploadUrl: (略)
status: ACTIVE
timeout: 60s
updateTime: '2018-08-07T03:07:17Z'
versionId: '3'
```

試し終わったら```delete```コマンドで関数を削除しておきましょう。
管理コンソールから作成した関数もお忘れなく^^

こちらもランタイムがPythonでも、Betaじゃなくても削除できました。

```sh
> gcloud functions delete cloud-functions-python-test

Resource [projects/xxx/locations/us-central1/functions/
cloud-functions-python-test] will be deleted.

Do you want to continue (Y/n)?  Y

Waiting for operation to finish...done.
Deleted [projects/xxx/locations/us-central1/functions/cloud-functions-python-test].


> gcloud beta functions delete hello_world

Resource [projects/xxx/locations/us-central1/functions/
hello_world] will be deleted.

Do you want to continue (Y/n)?  Y

Waiting for operation to finish...done.
Deleted [projects/xxx/locations/us-central1/functions/hello_world].
```

これまでnode.jsしか対応していなかったのが、Pythonが増えて、さらに便利になってきましたね。

では良きサーバレスライフを^^


Cloud FunctionsでPython利用記事まとめ
https://qiita.com/kai_kou/items/2f65db5305ba280ad81e