IronFunctions
Iron.ioによって提供されているFaaSのオープンソース版であるIronFunctionsの環境を構築してみます (2017/03/22時点)
IronFunctionsは、CLIやREST APIからリクエストを受け付け、コンテナ内でファンクションを実行し、実行し終えたらコンテナを破壊するといったライフサイクルになります。実行するファンクションはコンテナイメージとして事前に作成/保存され、通常はDocker Hubなどにプッシュするようです。
基本的な機能は揃っている印象ですが、現状で あるイベントが発生した(閾値を超えたなど)際に自動的にファンクションを実行する
という機能が無いのが惜しいところです。(Ceilometerならいける?)
また、Amazon Lambda以外のFaaSプロバイダと連携できないので今後に期待です。
IronFunctionsの他にも色々なFaaS(EPから有志による実装まで)があったのですが、構築の容易さと仕組みが理解しやすそうという理由からIronFunctionsを選択しました。その他のモノは以下になります。
色々と調べてみたのですが、オープンソースのFaaSってあまり無いのですね。
- Enterprise
- Amazon lambda: https://aws.amazon.com/jp/lambda/
- IBM Bluemix OpenWhisk: https://www.ibm.com/cloud-computing/bluemix/ja/openwhisk
- Microsoft Azure Function: https://azure.microsoft.com/ja-jp/services/functions/
- Google Cloud Function: https://cloud.google.com/functions/
- Webtask.io: https://webtask.io
- Iron.io: https://www.iron.io
- Hook.io: https://hook.io
- OpenSource
- Apache OpenWhisk: http://openwhisk.org
- IronFunctions: http://open.iron.io
- Fission: http://fission.io
- Funktion: https://funktion.fabric8.io
事前準備
- Ubuntu16.04LTSを使用
- DockerHubに自身のログインしておく必要があるのですが、今回は必要無いので割愛
※ 実行されるコンテナイメージはDockerHubからダウンロードされるため、事前にログインしておく必要がある。しかし、今回はローカルだけで実行するので必要ない。
(これ、HarborみたいなPrivate Repository利用できないのかな。今度試してみよう)
環境のアップデート
ubuntu@ubuntu-xenial:~$ sudo apt-get update
Dockerのインストール
ubuntu@ubuntu-xenial:~$ sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
ubuntu@ubuntu-xenial:~$ sudo apt-add-repository 'deb https://apt.dockerproject.org/repo ubuntu-xenial main'
ubuntu@ubuntu-xenial:~$ sudo apt-get update
ubuntu@ubuntu-xenial:~$ sudo apt-get install -y docker-engine
ubuntu@ubuntu-xenial:~/workdir$ docker version
Client:
Version: 17.03.0-ce
API version: 1.26
Go version: go1.7.5
Git commit: 60ccb22
Built: Thu Feb 23 11:02:43 2017
OS/Arch: linux/amd64
Server:
Version: 17.03.0-ce
API version: 1.26 (minimum version 1.12)
Go version: go1.7.5
Git commit: 60ccb22
Built: Thu Feb 23 11:02:43 2017
OS/Arch: linux/amd64
Experimental: false
FunctionsServerとFunctionsUIの起動
ubuntu@ubuntu-xenial:~$ sudo docker run --rm -it -d --name functions -v ${PWD}/data:/app/data -v /var/run/docker.sock:/var/run/docker.sock -p 8080:8080 iron/functions
ubuntu@ubuntu-xenial:~$ sudo docker run --rm -it -d --link functions:api -p 4000:4000 -e "API_URL=http://api:8080" iron/functions-ui
ubuntu@ubuntu-xenial:~/workdir$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9a9775f5251f iron/functions-ui "npm start" 4 hours ago Up 4 hours 0.0.0.0:4000->4000/tcp kind_mahavira
30a6e1bb2de7 iron/functions "/usr/local/bin/en..." 4 hours ago Up 4 hours 2375/tcp, 0.0.0.0:8080->8080/tcp functions
CLIツールのインストール
ubuntu@ubuntu-xenial:~$ curl -LSs https://goo.gl/VZrL8t | sh
ubuntu@ubuntu-xenial:~$ fn
fn 0.2.43
IronFunctions command line tools
USAGE:
Check the manual at https://github.com/iron-io/functions/blob/master/fn/README.md
ENVIRONMENT VARIABLES:
API_URL - IronFunctions remote API address
COMMANDS:
init create a local func.yaml file
apps manage applications
routes manage routes
images manage function images
lambda create and publish lambda functions
version displays fn and functions daemon versions
help, h Shows a list of commands or help for one command
ALIASES:
build (images build)
bump (images bump)
deploy (images deploy)
run (images run)
call (routes call)
push (images push)
GLOBAL OPTIONS:
--help, -h show help
--version, -v print the version
ファンクションのデプロイ
作業用フォルダの作成
ubuntu@ubuntu-xenial:~$ mkdir -p ~/workdir
ubuntu@ubuntu-xenial:~$ cd workdir
サンプルコードの作成
以下のコードを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)
}
ubuntu@ubuntu-xenial:~/workdir$ ls
func.go
ファンクションの初期化からデプロイまで
- ファンクションを初期化する
# 本来であれば、"myapp"の箇所にDockerHubのアカウント名を指定するのですが、ローカルだけでやるのであれば適当な名前でOKです
ubuntu@ubuntu-xenial:~/workdir$ fn init myapp/hello
assuming go runtime
func.yaml created.
ubuntu@ubuntu-xenial:~/workdir$ cat func.yaml
name: myapp/hello
version: 0.0.1
runtime: go
entrypoint: ./func
- ファンクションをビルドする
ubuntu@ubuntu-xenial:~/workdir$ fn build
Running prebuild command: docker run --rm -v /home/ubuntu/workdir:/go/src/github.com/x/y -w /go/src/github.com/x/y iron/go:dev go build -o func
Building image myapp/hello:0.0.1
Sending build context to Docker daemon 2.062 MB
Step 1/4 : FROM iron/go
---> c05f82fa066a
Step 2/4 : WORKDIR /function
---> Using cache
---> c7dbf8446c0a
Step 3/4 : ADD . /function/
---> 39fb743114b4
Removing intermediate container 691b263da564
Step 4/4 : ENTRYPOINT ./func
---> Running in b0e4fdaf5517
---> a36cab9bc0fe
Removing intermediate container b0e4fdaf5517
Successfully built a36cab9bc0fe
Function myapp/hello:0.0.1 built successfully.
- ファンクションを直接実行する
ubuntu@ubuntu-xenial:~/workdir$ fn run
Hello World!
- アプリケーションを作成する
ubuntu@ubuntu-xenial:~/workdir$ fn apps create myapp
myapp created
- ルートを作成する
ubuntu@ubuntu-xenial:~/workdir$ fn routes create myapp /hello
/hello created with myapp/hello:0.0.1
これでファンクションのデプロイが完了です。意外とあっさり。
あとは、ファンクションを実行する
箇所のコマンドを打てば良いだけ。
IronFunctionsの使い方まとめ
ファンクションを作成/削除する
# CLI
ubuntu@ubuntu-xenial:~/workdir$ fn apps create myapp
ubuntu@ubuntu-xenial:~/workdir$ fn apps delete myapp
# cURL
ubuntu@ubuntu-xenial:~/workdir$ curl -H "Content-Type: application/json" -X POST -d '{"app": { "name":"myapp" }}' http://localhost:8080/v1/apps
ルートを作成/削除する
# CLI
ubuntu@ubuntu-xenial:~/workdir$ fn routes create myapp /hello -i myapp/hello
ubuntu@ubuntu-xenial:~/workdir$ fn routes delete myapp /hello -i myapp/hello
# cURL
ubuntu@ubuntu-xenial:~/workdir$ curl -H "Content-Type: application/json" -X POST -d '{"route": {"path":"/hello", "image":"iron/hello"}}' http://localhost:8080/v1/apps/myapp/routes
ファンクションを実行する
# CLIからファンクションを直接実行する
ubuntu@ubuntu-xenial:~/workdir$ fn run
Hello World!
# CLIからRoutes経由でファンクションを実行する
ubuntu@ubuntu-xenial:~/workdir$ fn call myapp /hello
Hello World!
# cURL経由で実行する
ubuntu@ubuntu-xenial:~/workdir$ curl http://localhost:8080/r/myapp/hello
Hello World!
# CLIから引数を与えてファンクションを実行する
ubuntu@ubuntu-xenial:~/workdir$ echo '{"name":"Johnny"}' | fn call myapp /hello
Hello Johnny! # World が Johnny に変わる
# cURLから引数を与えてファンクションを実行する
ubuntu@ubuntu-xenial:~/workdir$ curl -H "Content-Type: application/json" -X POST -d '{"name":"Johnny"}' http://localhost:8080/r/myapp/hello
ファンクションを更新する
# ファンクションのバージョンアップとイメージのビルド
ubuntu@ubuntu-xenial:~/workdir$ fn bump && fn build
Bumped to version 0.0.2
Running prebuild command: docker run --rm -v /home/ubuntu/workdir:/go/src/github.com/x/y -w /go/src/github.com/x/y iron/go:dev go build -o func
Building image myapp/hello:0.0.2
Sending build context to Docker daemon 2.062 MB
Step 1/4 : FROM iron/go
---> c05f82fa066a
Step 2/4 : WORKDIR /function
---> Using cache
---> c7dbf8446c0a
Step 3/4 : ADD . /function/
---> 8ddafac107b4
Removing intermediate container b241757fc9dd
Step 4/4 : ENTRYPOINT ./func
---> Running in be42371c6d38
---> 5234e6fedd28
Removing intermediate container be42371c6d38
Successfully built 5234e6fedd28
Function myapp/hello:0.0.2 built successfully.
# ルートのアップデート
ubuntu@ubuntu-xenial:~/workdir$ fn routes update myapp /hello
非同期ファンクションの作成と実行
# 非同期イベントを作成する
ubuntu@ubuntu-xenial:~/workdir$ curl -H "Content-Type: application/json" -X POST -d '{"route": {"type": "async", "path":"/hello-async", "image":"iron/hello"}}' http://localhost:8080/v1/apps/myapp/routes
# 非同期ファンクションを実行する
ubuntu@ubuntu-xenial:~/workdir$ curl -H "Content-Type: application/json" -X POST -d '{"name":"Johnny"}' http://localhost:8080/r/myapp/hello-async
{"call_id":"b296bca4-8574-5211-b762-7f7cb914292b"}
# 非同期ファンクションの実行結果を確認する
# 実行時に出力された`call_id`と同様のIDを持つメッセージを確認する
ubuntu@ubuntu-xenial:~/workdir$ docker logs [FUNCTIONSを起動しているコンテナID]
~~ 一部抜粋 ~~
INFO[18260] Pushed to MQ call_id=b296bca4-8574-5211-b762-7f7cb914292b
INFO[18260] Added new task to queue action="server.handleRunnerRequest)-fm" app=myapp call_id=b296bca4-8574-5211-b762-7f7cb914292b image="iron/hello" route="/hello-async"
INFO[18260] Reserved call_id=b296bca4-8574-5211-b762-7f7cb914292b
INFO[18260] call_id=b296bca4-8574-5211-b762-7f7cb914292b name=run.myapp.requests runner=async type=count value=1
INFO[18260] call_id=b296bca4-8574-5211-b762-7f7cb914292b name=run.myapp.waittime runner=async type=time value=0s
INFO[18260] Deleted call_id=b296bca4-8574-5211-b762-7f7cb914292b
INFO[18260] Task complete call_id=b296bca4-8574-5211-b762-7f7cb914292b runner=async
INFO[18261] Hello World! app_name=myapp call_id=b296bca4-8574-5211-b762-7f7cb914292b image="iron/hello" path= runner=async user_log=true
INFO[18261] container status call_id=b296bca4-8574-5211-b762-7f7cb914292b container_error= container_finished=2017-03-21 11:34:21.807374695 +0000 UTC container_running=false container_status=exited exit_code=0 runner=async
INFO[18261] call_id=b296bca4-8574-5211-b762-7f7cb914292b name=run.myapp.succeeded runner=async type=count value=1
INFO[18261] call_id=b296bca4-8574-5211-b762-7f7cb914292b name=run.myapp.time runner=async type=time value=400.322041ms
INFO[18261] call_id=b296bca4-8574-5211-b762-7f7cb914292b name="run.exec_time" runner=async type=time value=400.322041ms
WebUIにアクセスしてみる
-
http://<FunctionServerIP>:4000
にアクセスする- 右上の
Create App
からアプリケーションの作成を行う事が出来る
- 右上の
- アプリケーション名をクリックすると以下のような画面に遷移する
- 右上の
Add Route
からルートを作成する事が出来る
- 右上の
- WebUI上からファンクションを実行する事も出来る
-
Run Function
をクリックし、出現したウィンドウ上のRun
をクリックする
-
※ ファンクションのコンテナイメージのビルドはWebUIからは行う事が出来ないので、大抵の作業はCLIからになりそう。
感想
- シンプルで使い易い
- なんか名前がかっこいい、あと公式ページのアイ○ンマンみたいなキャラかっこいい
- 不足している機能もあるけど基本的な事は出来そう
- 各クラウドプロバイダとの連携に期待
- イベントドリブンな箇所を充実させて欲しい
- ユーザマネジメントの機能があったら便利そう
- beta版のリリースが遅れているのが気になる
参考
https://github.com/iron-io/functions
https://medium.com/iron-io-blog/ironfunctions-the-open-source-serverless-platform-21dd66d839e8#.mih24j3wg
https://medium.com/@treeder/announcing-project-picasso-openstack-functions-as-a-service-db3fff70ffea#.cwjtgq22a
https://medium.com/@SergeyNuzhdin/how-to-run-functions-in-your-kubernetes-cluster-c7aa38927188#.soubagpg9