Azure で とっても簡単に python のサーバレス環境を作ってみる

同僚から、Azure のサーバーレスに対して一つのリクエストをもらった。彼は、python で書きたいらしい。サーバーレスのもっとも良いところは、サーバーをある意味気にしなくていいところだが、使ったぶんだけ課金というパートを除けば、常にクラスタをデプロイしたままでのサーバーレス環境も生産性という意味では悪くないかもしれない。

<img width="945" alt="Screen Shot 2017-09-22 at 12.59.11 AM.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/d1db1e57-0ec0-39c3-a37c-12b06ecef03c.png">


自分がサーバーレスの世界に求めるのは、何と言っても簡単さだ。だから、セットアップもできるだけしたくない。今回は、たまたまハッカソンで触った OpenFaaS という Swarm / k8s にデプロイしたら動くシンプルなものを作って、彼のデマンドに答えてみたい。OpenFaaS は、ストレージや、キューのトリガーすらない、httpだけの非常にシンプルなものだ。

# 基礎的なアイデア

基礎的なアイデアはとしてもシンプルだ。彼からのお題は、ブロブにアップロードした画像解析をpython でサクッとしたいとのことだ。ライブラリが充実しているから python がいいらしい。ところが、Azure Functions は今の所、Windows ベースなので、Python や Ruby が使えたところで、ネィティブエクステンション系のライブラリは相当辛いだろう。

だから、こんな感じはどうだろう？

```
Blob -> Logic Apps -> OpenFaaS -> Blob
```

単純にいうと、ブロブに何かアップロードされたら、Logic Apps が拾って、httpのリクエストを、Open FaaS に投げる。Open FaaS は同期もしくは、非同期でそのリクエストを受け取って、リスクエストに格納されたファイル名にアクセスして、取得して分析するという感じ。このクソシンプルな作戦だと、OpenFaaSじゃなくても他のでも使える。ちなみに、Azure Container Instance を使わなかったのは、今の所オースケストレーターがないから。また、高負荷にも多分耐えられないから（スケールしないので）今後楽しみね。

# OpenFaaS でファンクションを作る

まずは、OpenFaaS 側でファンクションを作ろう。必要なものは、２つだけ。シンプルなエコーもどきを、実装しよう。JSON の方がいいだろうから、JSON でエコーするようにする。OpenFaaS のセットアップは、私のブログポストを参考にしてほしい。

* [OpenFaaS on ACS (Kubernetes)](https://blogs.technet.microsoft.com/livedevopsinjapan/2017/09/19/open-faas-on-acs-kubernetes/)
* [OpenFaaS on Azure (Swarm)](https://blogs.technet.microsoft.com/livedevopsinjapan/2017/09/21/openfaas-on-azure-swarm/)

必要なものは、２つだけ。 handler.py と、storage.yaml 。ファンクションの名前をつけたディレクトリを作って、そこに、handler.py を置くだけ。

```
├── storage
│   └── handler.py
├── storage.yaml
```

handler.py

```py
import json

def handle(req):   
    print('{ "recieve" : ' + req + "}")
```

storage.yaml (名前はなんでも良い)

```yaml
provider:
  name: faas
  gateway: http://13.93.212.187:8080

functions:
  storage-trigger:
    lang: python
    handler: ./storage/
    image: tsuyoshiushio/storage-trigger
```

どちらも一回書いてしまえばクソ簡単。デプロイしよう。

```
faas-cli -action build -f ./storage.yaml
faas-cli -action push -f ./storage.yaml
faas-cli -action deploy -f ./storage.yaml
```

準備おっけー。ちなみに、OpenFaaS は内部で Docker を使っているので、ネイティブエクステンション問題は問題ない。Windows Container にも対応しているらしい。（それだったら、Azure Function使うけどw)

<img width="945" alt="Screen Shot 2017-09-22 at 12.59.11 AM.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/947b9de1-ff9d-ceca-ec11-39faec144a9b.png">

# Logic Apps を設定する

[Logic Apps](https://azure.microsoft.com/en-us/services/logic-apps/) は、Azure のサーバーレスのオファーの一つで、コーディングレスで、いろんなサービスをつなぐことができる。Azure に限らない。いろんなイベントを拾うことができる。Blob にアップされたらとか、VM ができたら、[Event Grid](https://azure.microsoft.com/en-us/services/event-grid/) という仕組みもできたので、ほぼ全てのイベントを拾うことができる。
  イベントきっかけで、いろんなサービスを連携させることができる。今回は、ブロブのイベントを拾って、OpenFaaS で作ったファンクションに連携させる。ちなみに、事前に、Storage Account は作成しておいた。

ちなみに Logic Apps の　Web action でハマったところは、最初、このアプリがBad Request で帰ってきたこと。正しい Json ではないとのこと。原因は、Logic Apps 側の設定ではなく、Function が返してきたレスポンスが、正しい Json ではないから。手元を散々見直してハマったが、実は、向こう側の問題だったということ。

<img width="571" alt="Screen Shot 2017-09-22 at 1.07.18 AM.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/2b7bac13-f451-78f4-e10c-3a5024df4002.png">

これを、保存して実行させておいて、ブロブに何かの画像をアップさせる
<img width="949" alt="Screen Shot 2017-09-22 at 1.08.48 AM.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/b2cf281d-0d34-150a-ae72-e33781ca680d.png">

そしたら、自動的に、Logic Apps がイベントを拾って、ファイル名を、ファンクションにポストする

<img width="327" alt="Screen Shot 2017-09-22 at 1.09.59 AM.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/0319e3a4-14d2-e518-d1ef-50685a1010b3.png">

あとは、自分で、Azure SDK を使ってキューを取りに行かないと行けないけど、かなり楽チンじゃないかなぁー。

# 終わりに

次回は、ここから発展させてみて、色々繋げてみる。また、Function を作ったら、できれば、Logic Apps を書くのを自動化できないかなとかふと思ってみたり。

# リソース


* [OpenFaaS on ACS (Kubernetes)](https://blogs.technet.microsoft.com/livedevopsinjapan/2017/09/19/open-faas-on-acs-kubernetes/)
* [OpenFaaS on Azure (Swarm)](https://blogs.technet.microsoft.com/livedevopsinjapan/2017/09/21/openfaas-on-azure-swarm/)
* [Functions as a Service (OpenFaaS) - a serverless framework for Docker & Kubernetes](https://github.com/alexellis/faas)