Docker Swarm と Kubernetes をサポートしている FaaS フレームワークとして「OpenFaaS」がある.CNCF Cloud Native Landscape を見ても Serverless カテゴリに入っている.OpenFaaS は前から気になっていたけど,今まで試したことがなく,最近 GitHub に OpenFaaS 公式のワークショップがあることを知って,さらに日本語版も用意されていたため,今回はワークショップを進めながら OpenFaaS を学ぶことにした.
アジェンダ
- Lab 1 : まずはOpenFaaSの準備
- Lab 2 : OpenFaaSを試してみよう
- Lab 3 : はじめてのfunction
- Lab 4 : functionについてさらに掘り下げてみよう
- Lab 5 : Gitbotを作ろう
- Lab 6 : functionでHTMLを扱ってみよう
- Lab 7 : 非同期 function
- Lab 8 : 応用編 - タイムアウト
- Lab 9 : 応用編 - functionのオートスケール
- Lab 10 : 応用編 - secretの使い方
- Appendix
英語版だと,既に「Lab 11 - Advanced feature - Trust with HMAC」まで追加されている.
Lab 1 : まずはOpenFaaSの準備
Lab 1 では,OpenFaaS を動かす環境を構築する.今回は「Docker Desktop for Mac + Docker Swarm」を使うことにした.Docker Swarm ではなく Kubernetes もサポートしているけど,ワークショップの推奨構成は Docker Swarm となる.
$ docker --version
Docker version 18.09.1, build 4c52b90
次に「OpenFaaS CLI」をインストールする.今回は brew を使った.
$ brew install faas-cli $ faas-cli version ___ _____ ____ / _ \ _ __ ___ _ __ | ___|_ _ __ _/ ___| | | | | '_ \ / _ \ '_ \| |_ / _` |/ _` \___ \ | |_| | |_) | __/ | | | _| (_| | (_| |___) | \___/| .__/ \___|_| |_|_| \__,_|\__,_|____/ |_| CLI: commit: a141dedf94ffeed84412365fd591bdc8999c5a1b version: 0.8.3
最後に OpenFaaS をデプロイする.OpenFaaS の公式リポジトリを git clone
し,deploy_stack.sh
を実行すると,Docker Swarm にデプロイできる.OpenFaaS フレームワークとして,複数のコンテナが動いていることも確認できる.
$ git clone https://github.com/openfaas/faas $ cd faas && \ git checkout master $ ./deploy_stack.sh --no-auth $ docker service ls ID NAME MODE REPLICAS IMAGE PORTS j8sukvimvk20 func_alertmanager replicated 1/1 prom/alertmanager:v0.15.0 azd1ypjtat6r func_faas-swarm replicated 1/1 openfaas/faas-swarm:0.6.1 xslhyv2k81ij func_gateway replicated 1/1 openfaas/gateway:0.9.14 *:8080->8080/tcp lmuottao09ga func_nats replicated 1/1 nats-streaming:0.11.2 kslgx10aa2md func_prometheus replicated 1/1 prom/prometheus:v2.3.1 *:9090->9090/tcp ocpfj4xiofns func_queue-worker replicated 1/1 openfaas/queue-worker:0.5.4
さらに OpenFaaS にはコンソールもあり,既に http://localhost:8080/ui/
にアクセスすると,接続できるようになっている.
Lab 2 : OpenFaaSを試してみよう
Lab 2 では,OpenFaaS の公式リポジトリにある stack.yml
を使って,実際に Function をデプロイする.
$ faas-cli deploy -f https://raw.githubusercontent.com/openfaas/faas/master/stack.yml Parsed: https://raw.githubusercontent.com/openfaas/faas/master/stack.yml Deploying: hubstats. Deployed. 202 Accepted. URL: http://127.0.0.1:8080/function/hubstats Deploying: nodeinfo. Deployed. 202 Accepted. URL: http://127.0.0.1:8080/function/nodeinfo Deploying: echoit. Deployed. 202 Accepted. URL: http://127.0.0.1:8080/function/echoit Deploying: wordcount. Deployed. 202 Accepted. URL: http://127.0.0.1:8080/function/wordcount Deploying: base64. Deployed. 202 Accepted. URL: http://127.0.0.1:8080/function/base64 Deploying: markdown. Deployed. 202 Accepted. URL: http://127.0.0.1:8080/function/markdown
コンソールから Function を実行することができる.例えば,Markdown を HTML に変換する function/markdown
Function がある.
他には入力した文章から文字数をカウントする function/wordcount
Function など,計6種類あった.
OpenFaaS には Function を公開できる仕組みとして「Function Store」がある.今回はアスキーアートを表示する function/figlet
Function をコンソールからデプロイした.
また faas-cli list --verbose
を実行すると,Function ごとの実行回数 (Invocations) を確認できる.
$ faas-cli list --verbose Function Image Invocations Replicas figlet functions/figlet:0.9.6 6 1 nodeinfo functions/nodeinfo:latest 0 1 wordcount functions/alpine:latest 3 1 echoit functions/alpine:latest 0 1 hubstats functions/hubstats:latest 0 1 markdown functions/markdown-render:latest 5 1 base64 functions/alpine:latest 0 1
最後はモニタリング関連の話題となり,OpenFaaS を Docker Swarm にデプロイしたときに,実は Docker Compose によって Prometheus も起動していて,OpenFaaS のメトリクスを取得している.今回は Prometheus を可視化するために Grafana を起動する.
$ docker service create -d \ --name=grafana \ --publish=3000:3000 \ --network=func_functions \ stefanprodan/faas-grafana:4.6.3
さっそく http://127.0.0.1:3000/dashboard/db/openfaas
にアクセスすると,Grafana で OpenFaaS のメトリクスを可視化できるようになっている.OpenFaaS だけではなく,Prometheus や Grafana も合わせて試せるのは良い点だと思う.
Lab 3 : はじめてのfunction
Lab 3 では,公式テンプレートから Function を作る.現時点で「計15種類」のテンプレートが公開されている.今回使う Python 3 以外にも,Go や Ruby も用意されていた.
$ faas-cli template pull
$ faas-cli new --list
Languages available as templates:
- csharp
- csharp-armhf
- dockerfile
- go
- go-armhf
- java8
- node
- node-arm64
- node-armhf
- php7
- python
- python-armhf
- python3
- python3-armhf
- ruby
今回は Python 3 テンプレートを使って hello-openfaas
Function を作る.テンプレートは --lang
オプションで指定する.なお --prefix
オプションで指定するのは Function 名のプレフィックスで,今回は Docker Hub に公開することを前提に,Docker Hub のアカウント名を指定する.
$ faas-cli new --lang python3 hello-openfaas --prefix="kakakakakku" Folder: hello-openfaas created. ___ _____ ____ / _ \ _ __ ___ _ __ | ___|_ _ __ _/ ___| | | | | '_ \ / _ \ '_ \| |_ / _` |/ _` \___ \ | |_| | |_) | __/ | | | _| (_| | (_| |___) | \___/| .__/ \___|_| |_|_| \__,_|\__,_|____/ |_| Function created in folder: hello-openfaas Stack file written: hello-openfaas.yml
Function を作ると,合わせて Stack ファイルも作られる.以下に hello-openfaas.yml
を載せておく.
provider: name: faas gateway: http://127.0.0.1:8080 functions: hello-openfaas: lang: python3 handler: ./hello-openfaas image: kakakakakku/hello-openfaas:latest
そして,単純な文字列 "Hello OpenFaaS" を返す実装を handler.py
にして,hello-openfaas
Function をデプロイする.今回は faas-cli build
→ faas-cli push
→ faas-cli deploy
のフローになる.さらに Function の実行は faas-cli invoke
でできる.
$ faas-cli build -f ./hello-openfaas.yml $ faas-cli push -f ./hello-openfaas.yml $ faas-cli deploy -f ./hello-openfaas.yml Deploying: hello-openfaas. Deployed. 202 Accepted. URL: http://127.0.0.1:8080/function/hello-openfaas $ faas-cli invoke hello-openfaas Reading from STDIN - hit (Control + D) to stop. Hello OpenFaaS
コマンドの裏側では docker build
と docker push
が実行されているため,Docker Hub を見ると,Docker イメージも公開されている.
次に外部 API と連携し,宇宙飛行士の名前をランダムに表示する astronaut-finder
Function を実装し,デプロイする.特別な内容はなく,実行結果を載せておく.
$ echo | faas-cli invoke astronaut-finder Oleg Kononenko is in space $ echo | faas-cli invoke astronaut-finder Anne McClain is in space
今度は Docker Compose のように,OpenFaaS で複数の Function を管理する設定を試す.faas-cli new
コマンドには --append
オプションがあり,複数の Function を同じ Stack ファイルにまとめることができる.
$ faas-cli new --lang python3 first $ faas-cli new --lang python3 second --append=./first.yml
最後にカスタムバイナリの紹介で,faas-cli new
コマンドの --lang
オプションには,プログラミング言語だけではなく dockerfile
も指定することができる.これは指定した Docker イメージをテンプレートにできる機能で,Function をカスタマイズするときに必要になりそう.
$ faas-cli new --lang dockerfile sorter --prefix="kakakakakku"
Lab 4 : functionについてさらに掘り下げてみよう
Lab 4 では,詳細な Function 管理を学ぶ.OpenFaaS では「Watchdog」と呼ばれる HTTP サーバも起動していて,標準入力と標準出力をプロキシする役割となる.Function のログを出力するときに,デフォルトの挙動だと stderr
を stdout
に統合するため,もし統合を解消する場合は Stack ファイルに以下の設定を追加する必要がある.
environment: combine_output: false
次に OpenFaaS で Function を組み合わせたワークフローを実現する方法を学ぶ.大きく2種類あり「クライアント側でパイプを使って組み合わせる方法」と「Function から Function を呼び出す方法」がある.お手軽に実現するなら「クライアント側でパイプを使って組み合わせる方法」を使う.
$ echo -n "" | faas-cli invoke nodeinfo | faas-cli invoke markdown
Lab 5 : Gitbotを作ろう
Lab 5 では,OpenFaaS で GitHub の Webhooks を受け取る Function を実装する.機能としては GitHub Issue が作られると,Function が Webhooks を受け取り,GitHub Issue のタイトルと本文を分析してポジティブかどうかを判定し,結果を GitHub Issue のラベルに登録する.ただし,ローカルに構築した OpenFaaS 環境では Webhooks を受け取れないため,今回は ngrok コンテナを起動し,トンネルを作る.
$ faas-cli list --gateway http://xxxxxxxx.ngrok.io/ Function Invocations Replicas figlet 0 1 env 0 1 nodeinfo 0 1 wordcount 0 1 sorter 0 1 sentimentanalysis 0 1 echoit 0 1 hubstats 0 1 hello-openfaas 0 1 markdown 0 1 base64 0 1 astronaut-finder 0 1
まず,Webhooks を受け取る issue-bot
Function を作る.手順と実装は省略する.事前に GitHub の Settings で Webhooks を設定しておく必要もある.
$ faas-cli new --lang python3 issue-bot --prefix="kakakakakku" $ faas-cli build -f ./issue-bot.yml $ faas-cli push -f ./issue-bot.yml
Webhooks を受け取れることを確認したら,今度はタイトルと本文がポジティブかどうかを判定する function/sentimentanalysis
Function を呼び出せるように修正する.最後に GitHub の Personal Access Tokens を env.yml
に設定し,issue-bot
Function の環境変数として読み込むことで,GitHub Issue のラベルを登録できるようにする.function/sentimentanalysis
Function の実行例を以下に載せておく.
$ echo -n "I am really excited to participate in the OpenFaaS workshop." | faas-cli invoke sentimentanalysis {"polarity": 0.375, "sentence_count": 1, "subjectivity": 0.75} $ echo -n "The hotel was clean, but the area was terrible" | faas-cli invoke sentimentanalysis {"polarity": -0.31666666666666665, "sentence_count": 1, "subjectivity": 0.8500000000000001}
実際に OpenFaaS 経由で GitHub Issue にラベルを登録できた.
Lab 6 : functionでHTMLを扱ってみよう
Lab 6 では,HTTP サーバのように HTML を返す Function を作る.Function の作成は今まで通り.
$ faas-cli new --lang python3 show-html --prefix="kakakakakku"
重要なのは Stack ファイルで,以下のように content_type: text/html
を指定すると,レスポンスの Content-Type
を固定することができる.
provider: name: faas gateway: http://127.0.0.1:8080 functions: show-html: lang: python3 handler: ./show-html image: kakakakakku/show-html:latest environment: content_type: text/html
HTML を返す Function を実装し,以下の URL にアクセスすると,ウェブページにアクセスできる.
http://127.0.0.1:8080/function/show-html
http://127.0.0.1:8080/function/show-html?action=new
http://127.0.0.1:8080/function/show-html?action=list
最後は JavaScript も組み合わせて,入力した文字列をアスキーアートに変換する function/figlet
Function を呼び出すアプリケーションを実装した.
http://127.0.0.1:8080/function/show-html?action=figlet
Lab 7 : 非同期 function
Lab 7 では,Function を「同期的」に実行する方法と「非同期的」に実行する方法を学んだ.具体的には faas-cli invoke
コマンドには --async
オプションがあり,非同期的に実行することができる.非同期的に実行をすると,Function は Gateway から 「202 Accepted」のレスポンスを受けることになる.また HTTP ヘッダーに X-Callback-Url
を設定することにより,Function の実行後にコールバックを受けることもできる.Function の特性に応じて,非同期的な実行が必要になる場面もありそう.
$ echo -n "" | faas-cli invoke long-task --async Function submitted asynchronously.
さらに OpenFaaS は非同期実行のために「NATS Streaming」を採用していると書いてあった.確かに docker service ls
で確認したコンテナの中にも NATS があった.NATS は CNCF (Cloud Native Computing Foundation) にも所属するメッセージングサービスを提供するミドルウェアで,前から試したいと思っていたところだった.
Lab 8 : 応用編 - タイムアウト
Lab 8 では,Function のタイムアウト設定を学んだ.OpenFaaS では「計4種類」の環境変数でタイムアウトの時間を制御することができる.
sleep_duration
read_timeout
write_timout
exec_timeout
今回は sleep_duration = 10
と sleep_duration = 2
の動作を確認した.
provider: name: faas gateway: http://127.0.0.1:8080 functions: sleep-for: lang: python3 handler: ./sleep-for image: kakakakakku/sleep-for:latest environment: sleep_duration: 10 read_timeout: 5 write_timeout: 5 exec_timeout: 5
以下のような結果となり,sleep_duration = 10
の場合はワークショップの記載内容と少し差があった.
$ echo | faas-cli invoke sleep-for Server returned unexpected status code: 502 - $ echo | faas-cli invoke sleep-for Starting to sleep for 2 Finished the sleep
Lab 9 : 応用編 - functionのオートスケール
Lab 9 では,OpenFaaS のオートスケールを学んだ.具体的には Prometheus の Alertmanager と連携する仕組みになっている.
function/nodeinfo
Function を大量に実行するときに,Mac だと記載されているコマンドだと使えなかった.
$ while [ true ]; do curl -X POST http://localhost:8080/function/nodeinfo\; done; while>
今回は以下のコマンドを実行した.
$ while : do curl -X POST http://localhost:8080/function/nodeinfo done
Prometheus のアラート画面を見ると,FIRING / PENDING になっていることを確認できた.faas-cli list
でも,実行回数 (Invocations) が増えていた.
$ faas-cli list | egrep 'Function|nodeinfo' Function Invocations Replicas nodeinfo 1447 1
Lab 10 : 応用編 - secretの使い方
Lab 10 では,OpenFaaS と「Docker secrets」を組み合わせて,機密情報を扱う方法を学んだ.
今回は GitHub の Personal Access Tokens を Docker secrets に登録し,Function から参照するように issue-bot
Function をリファクタリングした.環境変数ではなく Docker secrets を使う Lab があるのは素晴らしいと思う.
$ echo -n xxx | docker secret create auth-token - $ docker secret inspect auth-token
ワークショップ改善(プルリクエスト)
ワークショップを進めながら気になった点を修正して,プルリクエストを2個送った.
ワークショップ改善(フィードバック)
プルリクエストは送らなかったけど,ワークショップを改善できる点をまとめておく.OpenFaaS コミュニティに届くと良いなぁー!
- 全体的に
mkdir
を実行する手順が微妙で,ディレクトリ階層が/openfaas/faas/lab2/lab3
のようになってしまう- Lab ごとに起点となるディレクトリ直下で
mkdir
をすると良さそう
- Lab 3
- 「複数のfunctionの管理」のところにある
faas-cli new
でも--prefix
を付けると良さそう
- 「複数のfunctionの管理」のところにある
- Lab 6
- HTML に指定されているフォントが「Roboto Mono」で,等幅フォントではないため,アスキーアートの表示が崩れてしまう
- 例えば「Courier New」など,等幅フォントに変更すると良さそう
- Lab 7
- 正式表記にするならば「Github」ではなく「GitHub」にすると良さそう
- Lab 8
echo | faas-cli invoke sleep-for
で 502 が返ってくるため,最新バージョンでの出力結果に更新すると良さそう
- Lab 9
- 正式表記にするならば「AlertManager」ではなく「Alertmanager」にすると良さそう
- Alertmanager | Prometheus
まとめ
- 「OpenFaaS」を学ぶために OpenFaaS 公式ワークショップを試した
- 日本語版もある
- OpenFaaS の基礎から応用まで幅広く学ぶことができた
- OpenFaaS だけではなく Prometheus や Grafana や NATS Streaming も学べる題材になっている
- ワークショップの所要時間は3,4時間程度だと思う(個人差あり)
参考資料
OpenFaaS のアーキテクチャが詳しく載っていて,参考になった.