kakakakakku blog

Weekly Tech Blog: Keep on Learning!

FaaS フレームワーク「OpenFaaS」を実践的に学べる公式ワークショップ

Docker Swarm と Kubernetes をサポートしている FaaS フレームワークとして「OpenFaaS」がある.CNCF Cloud Native Landscape を見ても Serverless カテゴリに入っている.OpenFaaS は前から気になっていたけど,今まで試したことがなく,最近 GitHub に OpenFaaS 公式のワークショップがあることを知って,さらに日本語版も用意されていたため,今回はワークショップを進めながら OpenFaaS を学ぶことにした.

www.openfaas.com

アジェンダ

  • 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」まで追加されている.

github.com

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

github.com

最後に 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

github.com

さらに OpenFaaS にはコンソールもあり,既に http://localhost:8080/ui/ にアクセスすると,接続できるようになっている.

f:id:kakku22:20190130214050p:plain

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 がある.

f:id:kakku22:20190130214110p:plain

他には入力した文章から文字数をカウントする function/wordcount Function など,計6種類あった.

f:id:kakku22:20190130214130p:plain

OpenFaaS には Function を公開できる仕組みとして「Function Store」がある.今回はアスキーアートを表示する function/figlet Function をコンソールからデプロイした.

f:id:kakku22:20190130214151p:plain

github.com

また 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 も合わせて試せるのは良い点だと思う.

f:id:kakku22:20190130214222p:plain

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

github.com

今回は 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 buildfaas-cli pushfaas-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 builddocker push が実行されているため,Docker Hub を見ると,Docker イメージも公開されている.

f:id:kakku22:20190130214324p:plain

次に外部 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 のログを出力するときに,デフォルトの挙動だと stderrstdout に統合するため,もし統合を解消する場合は 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 にラベルを登録できた.

f:id:kakku22:20190130214346p:plain

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

f:id:kakku22:20190130214404p:plain

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) にも所属するメッセージングサービスを提供するミドルウェアで,前から試したいと思っていたところだった.

nats.io

Lab 8 : 応用編 - タイムアウト

Lab 8 では,Function のタイムアウト設定を学んだ.OpenFaaS では「計4種類」の環境変数でタイムアウトの時間を制御することができる.

  • sleep_duration
  • read_timeout
  • write_timout
  • exec_timeout

今回は sleep_duration = 10sleep_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 と連携する仕組みになっている.

docs.openfaas.com

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

f:id:kakku22:20190130234728p:plain

Lab 10 : 応用編 - secretの使い方

Lab 10 では,OpenFaaS と「Docker secrets」を組み合わせて,機密情報を扱う方法を学んだ.

docs.docker.com

今回は 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個送った.

github.com

github.com

ワークショップ改善(フィードバック)

プルリクエストは送らなかったけど,ワークショップを改善できる点をまとめておく.OpenFaaS コミュニティに届くと良いなぁー!

  • 全体的に
    • mkdir を実行する手順が微妙で,ディレクトリ階層が /openfaas/faas/lab2/lab3 のようになってしまう
    • Lab ごとに起点となるディレクトリ直下で mkdir をすると良さそう
  • Lab 3
    • 「複数のfunctionの管理」のところにある faas-cli new でも --prefix を付けると良さそう
  • 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 のアーキテクチャが詳しく載っていて,参考になった.