Faasを作れるOSS, IronFunctions触ってみた

# IronFunctionsって？

こちら。
http://open.iron.io/
>IronFunctions is an open source serverless computing platform for any cloud - private, public, or hybrid.

最近流行りのサーバーレスアーキテクチャーを特定のクラウドベンダーにとらわれずに実行するための、オープンソースのプラットフォーム。

次のような特徴がある。

- どんな言語でも実装できる
- AWS Lambdaのフォーマットもサポートしてる(!)
- どこでも動かせる

過去に、AWS Lambdaで実行されているファンクションをオンプレでも動かせないか、という要望をもらったこともあったが正直厳しいですーという話をしていた。どこでも動かせてAWS LambdaフォーマットもサポートしているというIronFunctionsにはかなり興味を持っている。

なお現在はまだAlphaバージョンが出たばかりで、今後どんどん変化していくと思う。
あくまで2016/11時点での確認ということでご了承を。
理解が間違っている場合もあるかもしれない。もし間違いを発見した場合は是非ご連絡ください。

# Quickstart

まずはクイックスタートの通りにやってみる。
golangで書かれたファンクションが実行できるようだ。
https://github.com/iron-io/functions#quickstart

## Prequisites

- Docker1.12が動作していること
- Docker Hubにログインしていること

実行されるファンクションは全てコンテナイメージとして保存されて、そこから実行される。また実行されるコンテナイメージDocker Hubからダウンロードされて実行される流れのようだ。そのためDocker環境が必要なのと、ファンクション作成時のコンテナイメージの保存先としてDocker Hubが使用されるため事前にログインしておく必要がある。

## Run IronFunctions

普段golangのディレクトリフォーマットでプロジェクトを管理しているので、今回もそれに沿った形ですすめる。
適当にいい感じのディレクトリで `docker run`
特に問題なく実行される。

```
$ cd ~/src/github.com/youyo/
$ mkdir iron-functions
$ cd $_
$ docker run --rm -it --name functions --privileged -v $PWD/data:/app/data -p 8080:8080 iron/functions
```

## CLI tool

これ以降の操作に使用するCLIツールをインストール。
インストールと言ってもgolang製のバイナリが `/usr/local/bin/fnctl` に配置されるだけなのでサクッと実行する。

```
$ curl -sSL http://get.iron.io/fnctl | sh
```

## Write a Function

そのまま使用する。

``` func.go
package main

import (
    "encoding/json"
    "fmt"
    "os"
)

type Person struct {
    Name string
}

func main() {
    p := &Person{Name: "World"}
    json.NewDecoder(os.Stdin).Decode(p)
    fmt.Printf("Hello %v!!", p.Name)
}
```

`func.go` という名前で保存して次のコマンドを実行する。

```
$ fnctl init youyo/iron-functions
$ fnctl build
$ fnctl run
$ fnctl push
$ fnctl apps create myapp
$ fnctl routes create myapp /hello
```

`fnctl build` 実行時に次のログが表示される。初回実行時はいいのだが、二回目以降はここの部分が実行されずスキップされているようだ。先ほどの `func.go` を修正した後は次の `docker run` を実行してバイナリを再作成する必要があるのかも。

```
"./func"
Running prebuild command: docker run --rm -v /Users/youyo/src/github.com/youyo/iron-functions:/go/src/github.com/x/y -w /go/src/github.com/x/y iron/go:dev go build -o func
```

最後に次のhttpリクエストを送れば実行できる。
初回はDocker Hubからコンテナイメージのダウンロードが行われるので実行まで時間がかかる。

```
$ curl http://localhost:8080/r/myapp/hello
Hello World!!
```

`fnctl` を使ってもok.

```
$ fnctl call myapp /hello
Hello World!!
```

パラメーターを渡すこともできる。

```
$ curl -d '{"name":"youyo"}' http://localhost:8080/r/myapp/hello
Hello youyo!!

$ echo '{"name":"youyo"}' | fnctl call myapp /hello
Hello youyo!!
```

# AWS Lambdaフォーマットで動かせるか試してみた

ここにドキュメントがあるのでそれに従ってやってみる。
https://github.com/iron-io/functions/blob/master/docs/lambda/getting-started.md

## Creating the function

まずはスクリプトを作成する。

```hello_world.py
# -*- coding: utf-8 -*-

def my_handler(event, context):
    message = 'Hello {} {}!'.format(event['first_name'],
                                    event['last_name'])
    return {
        'message' : message
    }
```

`fnctl` コマンドを使ってファンクションを動かすためのDockerfileを作成する。
なおドキュメントでは `irontest/hello_world:1` となっており `:1` というバージョン名が付いているが、このバージョンを付与するとエラーになって動かなかったので外した。 

```
$ fnctl lambda create-function youyo/irontest-hello_world python2.7 hello_world.my_handler hello_world.py
```

## Publishing the function to IronFunctions

コンテナイメージを作成してDocker Hubにpublishする。
前のコマンドで作成されたディレクトリに移動してから実行しないとエラーとなったので移動してから。

```
$ cd youyo/irontest-hello_world
$ fnctl publish -v -f -d .
```

## Testing the function

`fnctl` でもhttpリクエストでも実行可能。

```
$ fnctl lambda test-function youyo/irontest-hello_world --payload '{ "first_name": "Jon", "last_name": "Snow" }'
{"message": "Hello Jon Snow!"}

$ curl -d '{"first_name":"Jon","last_name":"Snow"}' http://localhost:8080/r/youyo/irontest-hello_world
{"message": "Hello Jon Snow!"}
```

ちゃんと動いた！！

# 所感

- いろんな言語が使えるのは魅力的
- AWS Lambdaフォーマットがどこでも動かせるというのも魅力的
- AzureFunctionsやCloudFunctionsとの互換性にも期待したいところ
- Triggerとして使えるイベントはどうなんだろう？ OpenstackのCeilometerには対応しているみたい
- Serverlessアーキテクチャーの特徴の一つとして、イベントドリブンなものを作れるかというのも重要なウェイトを占めると思うので、この辺りにも期待したい  
(イベント発行側は何者？というのは置いといて)