Java
flow
docker

Fn Project ことはじめ - Fn ServerとUIの投入

はじめに

Publickeyの「Java対応のサーバレスプラットフォーム「Fn Project」、オラクルがオープンソースで公開」によると、先日、米国でのJavaOneでFn Projectが発表されたようです。

すでにこのQiitaで記事を書かれた方もいらっしゃいますが、GitHubの「Fn Project」を参照にして、Fn Projectを導入してみましょう。

以下、作業手順です。
なお、「#」とあるのはrootユーザー、「$」とあるのはdockerユーザーで実行するコマンドです。

CentOS 7 64ビットの仮想マシン作成

  1. Windows 64ビットで、Oracle VM VirtualBoxでCentOSの仮想マシンを作成します
  2. 作成した仮想マシンでCentOSをインストールします
  3. インストール時にGUIでネットワーク設定できるので、IPアドレスを決めます(今回は「192.168.1.10」)

Docker投入

Fn ProjectはDockerを使う前提で開発されたものです。なので、まず、Dockerを投入します。
「rpm -qa」コマンドで仮想マシンに古いDockerがないか確認します。

# rpm -qa | grep docker

docker-common、docker-client、docker等が出力された場合、「rpm -e」コマンドで削除します。

# rpm -e docker-common docker-client docker

Dockerを投入します。

# yum install -y yum-utils
# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# yum makecache fast
# yum -y install docker-ce

Dockerサービスを登録し、有効化します。
これにより、仮想マシンの起動時に、Dockerも起動されるようになります。

# systemctl start docker
# systemctl enable docker.service

Dockerサービスの状況を確認します。

# ls /usr/lib/systemd/system | grep docker
# systemctl status docker.service

Fn Server投入

次に「GitHubのFn Serverリポジトリ」のREADME.mdを参考にして、Fn Serverを投入します。
curlコマンドで一発です。

# curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh

「fn start」コマンドで、Fn Serverを起動します。

$ (fn start > /dev/null 2>&1 &)

ここで、psコマンドで確認すると、Dockerコンテナがキックされていることとがわかります。

docker 15285 0.0 0.5 123704 11260 pts/0 Sl 00:34 0:00 docker run --rm -i --name functions -v /home/docker/data:/app/data -v /var/run/docker.sock:/var/run/docker.sock -p 8080:8080 fnproject/functions

また、「docker ps -a」コマンドを実行すると、Dockerコンテナの状態を確認できます。
Dockerコンテナの名前は「functions」であり、ポート番号8080でサービスを提供していることがわかります。

CONTAINER ID IMAGE               COMMAND                CREATED STATUS               PORTS                            NAMES
2dd93c867a93 fnproject/functions "preentry.sh ./fun..." 12 seconds ago Up 11 seconds 2375/tcp, 0.0.0.0:8080->8080/tcp functions

Fn Serverにはサンプルがあり、ブラウザから「http://<仮想マシンのIPアドレス>:8080」でアクセスし、次が帰ってくれば成功です。

{"goto":"https://github.com/fnproject/fn","hello":"world!"}

function作成

Fn Serverには複数のアプリを登録可能であり、また、各アプリごとに複数のfunctionをデプロイできます。
functionを「関数」と訳すには違和感があるので、ここではそのままfunctionと書きます。

functionを作成するために、ディレクトリを作成しそこに移動します。

$ mkdir -p ~/fn/hello
$ cd ~/fn/hello

「fn init」コマンドでfunctionプロジェクト(開発環境)のひな形を作成してくれます。
どの言語で開発するかを「--runtime」オプションで指定します。

$ fn init -runtime java

すると、次のファイルが生成されます。

├ func.yaml
├ pom.xml
└ src/
  ├ main/java/com/example/fn/HelloFunction.java
  └ test/java/com/example/fn/HelloFunctionTest.java

サンプルは、お決まりのHello worldです。
修正しなくてもすぐ動作するので、さっそく「fn run」でビルドおよび実行させます。

$ fn run

「fn run」でビルドし、成功すればローカルでfunctionを実行します。
もちろん、お決まりの「Hello, world」が出力されます。

通常のJavaアプリと違い、Docker上でビルドするため、仮想マシンにMaven等を入れる必要がない点が特徴です。
しかし、ビルドするたびにDockerイメージを作成するので、放置するとすぐディスク容量を圧迫します。
業務でFn Projectを使う場合、その辺をどうするか調査する必要がありそうです。

functionデプロイ

ビルドに成功したら、Fn Serverが起動されている状態であることを確認し、functionをデプロイします。

デプロイには「fn deploy」コマンドを使うわけですが、デフォルトではビルドの生産物であるDockerイメージを自動的にDocker Hubへpushします。しかし、開発段階ではDocker Hubへのpushは不要なので、「--local」オプションを指定します。また、「--app」にはアプリ名を指定します。

$ API_URL=http://192.168.1.10:8080 fn deploy --local --app myapp

API_URLを指定しないとデフォルトは「http://localhost:8080 」となりDockerイメージの外部からアクセスできません。したがって、Fn Serverを投入したマシンのIPアドレスを指定します。

以上でmyappというアプリがFn Serverにデプロイされるわけですが、function名はどうなるかというと、親ディレクトリの名前で決まります。今回は「~/fn/hello/」ディレクトリ上で「fn deploy」コマンドを実行したので、function名がhelloとなりました。

なお、DockerHubにpushさせる場合は、次のようにあらかじめDocker Hubにログインしておいてから、「fn deploy」コマンドを「--local」オプション無しで実行します。

$ docker login
$ export FN_REGISTRY=<Docker Hubのアカウント名>
$ API_URL=http://192.168.1.10:8080 fn deploy --app myapp

functionをデプロイしたら、「fn routes」コマンドでfunctionのルーティングを確認できます。

$ API_URL=http://192.168.1.10:8080 fn routes list myapp
path   image       endpoint
/hello hello:0.0.5 192.168.1.10:8080/r/myapp/hello

上のようにpath、imageおよびendpointが出力されますが、先述のとおり「fn run」を実行するたびにバージョンがどんどん上がり、すでに0.0.5となっています。
pathとendpointの違いですが、functionをFn Server投入マシン上でCLIで実行させる場合には次のようにpathを指定し、ブラウザから実行させる場合にはendpointの「http://192.168.1.10:8080/r/myapp/hello 」へGETを投げます。両方ともfunction実行後に「Hello, world!」が返ってきます。

$ fn call myapp /hello
Hello, world!

Fn User Interface投入

Fn Serverやfunctionの稼働状況をWebブラウザで確認するには、別途Fn User Interface(以降、FnUI)を投入する必要があります。
FnUIもDockerコンテナとして実行するので、次のようにコマンドを実行します。最初にこのコマンドを実行する場合はDocker Hubから「fnproject/ui」のDockerイメージを取得してから、FnUIが起動することになります。こういう手軽さはDockerの特長ですね。

$ docker run --name fnui --rm -it -d --link functions:api -p 4000:4000 -e "API_URL=http://api:8080" fnproject/ui

FnUI起動後、ブラウザから「http://192.168.1.10:4000/ 」へGETすれば、次の画面が表示されます。

FnUI

終了処理

先述のとおり、Fn ServerもFnUIもDockerコンテナなので、終了させるにはdocker stopコマンドを用います。

$ docker stop fnui
$ docker stop functions

宿題

Fn Server本体にはフロー機能が備わっているわけではなく、別途、Fn Flowを投入する必要があるのですが、Fn Projectの魅力はこのフロー機能に懸かっていると見ています。

Serverless Sagas with Fn Flow」を参考にすれば、フロー機能を実現できそうです。この記事にある通り、「チュートリアルのGitHubリポジトリ」の「FlowSaga」がFn Flowのサンプルです。また、「scripts」ディレクトリにあるスクリプトが参考になります。

まとめ

以上、ざっとFn Projectを触ってきた感想です。

  • Fn Projectの魅力は、Fn FlowとFn Flow UI等のフロー機能に懸かっている
  • クラウドでFn Projectを展開する際、課金の自動計算方法を調べる必要あり
  • 「fn xxx」コマンドは簡易コマンドの位置付けであり、コマンド群の強化も課題になりそう
    • 特にFn Serverにデプロイしたfunctionを削除するコマンドが見当たらない
    • functionをビルドするたびにDockerイメージを作成するので、別のビルド方法やデプロイ方法等を検討する必要あり
    • Fn UIは3秒位の短い間隔でfunctionの実行状況をチェックする。チェック間隔を調整する方法等を知りたい