概要
このエントリでは、Oracle Cloud Infrastructure(OCI)のMicro Instanceの上で動作するCentOSに、FaaS型のサーバを作るためのOSS「Fn Project」のサーバをインストールして、疎通確認用のアプリを動作させるところまでを扱います。
OCIであれば、「Functions」のサービスがありますのでそれを使おう、という話もありますが、このエントリでは、OSS版のサービスを自分で動かす方を取り上げています。(OCIのFunctionsは、別エントリにて取り扱いたい予定です)
想定読者
- Fn Projectのサーバをまだ自身で動かしていない方
準備
ほぼ、Fn projectのチュートリアルに従って進めます。方法が複数示されている中、今回利用している部分について、この後詳細を紹介しています。
docker CE
Fn projectでは、2020年1月時点では、Docker 17.10以降が必要です。
CentOS7を入れた後、yumで普通に導入されるバージョンはちょっと古そうなので、
$ yum info docker-latest | grep -i version
Version : 1.13.1
Dockerのサイトに従い、自分でインストールします。
(参考)Ubuntuのものにはなりますが、インストール方法を別エントリ「Utuntu 19.04 に Docker CE をインストールする」に書いてあります
このエントリでは、サイトの記載に従い、下記も実施して、自身のユーザをdockerグループに追加してあります。
sudo usermod -aG docker $USER
Fn project(のコマンドラインツール)
Fn projectのチュートリアルを眺めると、GitHub上のインストールスクリプトをダウンロードしてきて実行する手順になっていますので、リンクをちらっと眺めた後、実行してみます。
$ curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh
fn version 0.5.92
______
/ ____/___
/ /_ / __ \
/ __/ / / / /
/_/ /_/ /_/`
本エントリ執筆時点では、fnはversion 0.5.92でした。(サイトの説明は0.5.86になっています)。下記のバイナリが/usr/local/binにインストールされています。
[opc@instance-20200117-1627 ~]$ ls -la /usr/local/bin/fn
-rwxr-xr-x. 1 root root 17306174 Feb 2 06:25 /usr/local/bin/fn
動かしてみる
fn serverのローカル環境での起動
筆者は、下記のようなスクリプトをstart_fn.shとして用意して実行しました。
#!/bin/sh
export FN_PORT=18080
fn start -p $FN_PORT --log-level DEBUG
初回起動時は、必要なコンテナのイメージがダウンロードされます。
$ ./start_fn.sh
2020/02/02 06:34:05 ¡¡¡ 'fn start' should NOT be used for PRODUCTION !!! see https://github.com/fnproject/fn-helm/
Unable to find image 'fnproject/fnserver:latest' locally
latest: Pulling from fnproject/fnserver
ff3a5c916c92: Pull complete
1a649ea86bca: Pull complete
ce35f4d5f86a: Pull complete
b6206661264b: Pull complete
b8b71dba24d3: Pull complete
3873004a68ee: Pull complete
f4205b132661: Pull complete
91a85eeeb257: Pull complete
93c96d032b32: Pull complete
bb761748d6e1: Pull complete
81f6c51c4ac2: Pull complete
2ba715696dba: Pull complete
f46c2b56aaf3: Pull complete
aef258868c13: Pull complete
9a72ccea4c0a: Pull complete
Digest: sha256:34a51ad87dbe9e360ad194556f3cc21b6a75d73e41abd7d541a223beeb7f7271
Status: Downloaded newer image for fnproject/fnserver:latest
time="2020-02-02T06:34:25Z" level=info msg="Setting log level to" fields.level=DEBUG
time="2020-02-02T06:34:25Z" level=info msg="Registering data store provider 'sql'"
time="2020-02-02T06:34:25Z" level=debug msg="creating new datastore" db=sqlite3
time="2020-02-02T06:34:25Z" level=debug msg="mysql does not support sqlite3"
time="2020-02-02T06:34:25Z" level=debug msg="postgres does not support sqlite3"
time="2020-02-02T06:34:25Z" level=debug msg="mysql does not support sqlite3"
time="2020-02-02T06:34:25Z" level=debug msg="postgres does not support sqlite3"
time="2020-02-02T06:34:25Z" level=info msg="Connecting to DB" url="sqlite3:///app/data/fn.db"
time="2020-02-02T06:34:25Z" level=info msg="datastore dialed" datastore=sqlite3 max_idle_connections=256 url="sqlite3:///app/data/fn.db"
time="2020-02-02T06:34:25Z" level=info msg="agent starting cfg={MinDockerVersion:17.10.0-ce ContainerLabelTag: DockerNetworks: DockerLoadFile: DisableUnprivilegedContainers:false FreezeIdle:50ms HotPoll:200ms HotLauncherTimeout:1h0m0s HotPullTimeout:10m0s HotStartTimeout:5s DetachedHeadRoom:6m0s MaxResponseSize:0 MaxHdrResponseSize:0 MaxLogSize:1048576 MaxTotalCPU:0 MaxTotalMemory:0 MaxFsSize:0 MaxPIDs:50 MaxOpenFiles:0xc42003c018 MaxLockedMemory:0xc42003c040 MaxPendingSignals:0xc42003c048 MaxMessageQueue:0xc42003c050 PreForkPoolSize:0 PreForkImage:busybox PreForkCmd:tail -f /dev/null PreForkUseOnce:0 PreForkNetworks: EnableNBResourceTracker:false MaxTmpFsInodes:0 DisableReadOnlyRootFs:false DisableDebugUserLogs:false IOFSEnableTmpfs:false EnableFDKDebugInfo:false IOFSAgentPath:/iofs IOFSMountRoot:/home/opc/.fn/iofs IOFSOpts: ImageCleanMaxSize:0 ImageCleanExemptTags:ImageEnableVolume:false}"
time="2020-02-02T06:34:25Z" level=info msg="no docker auths from config files found (this is fine)" error="open /root/.dockercfg: no such file or directory"
time="2020-02-02T06:34:25Z" level=info msg="available memory" cgroup_limit=9223372036854771712 head_room=268435456 total_memory=734953472
time="2020-02-02T06:34:25Z" level=info msg="ram reservations" avail_memory=466518016
time="2020-02-02T06:34:25Z" level=info msg="available cpu" avail_cpu=2000 total_cpu=2000
time="2020-02-02T06:34:25Z" level=info msg="cpu reservations" cpu=2000
time="2020-02-02T06:34:25Z" level=info msg="\n ______\n / ____/___\n / /_ / __ \\\n / __/ / / / /\n /_/ /_/ /_/\n"
time="2020-02-02T06:34:25Z" level=info msg="Fn serving on `:8080`" type=full version=0.3.749
この時点で、fnにdefaultのコンテキストができています。
$ fn list contexts
CURRENT NAME PROVIDER API URL REGISTRY
default default http://localhost:8080
これを以下のように選択して、
$ fn use context default
Now using context: default
ローカル開発用に、任意の名前(この例では"fndemouser")をレジストリに指定します。
$ fn update context registry fndemouser
Current context updated registry with fndemouser
先ほどと同じ、"fn list contexts"を実施したとき、REGISTRYの部分が変わっていることがわかります。
$ fn list contexts
CURRENT NAME PROVIDER API URL REGISTRY
* default default http://localhost:8080 fndemouser
アプリを実行
Create Apps with Fnに従って、アプリを一つ動かしてみます。
前述のように、サーバが動作するポート番号をデフォルトの8080から18080に変更しているため、下記のように環境変数で接続先を指定します。
export FN_API_URL=http://127.0.0.1:18080
[opc@instance-20200117-1627 myapp2]$ fn deploy --create-app --all --local
Successfully created app: myapp2
Deploying myapp2 to app: myapp2
Bumped to version 0.0.2
Building image fndemouser/myapp2:0.0.2 ................................................................
Updating function myapp2 using image fndemouser/myapp2:0.0.2...
Successfully created function: myapp2 with fndemouser/myapp2:0.0.2
Successfully created trigger: myapp2
Trigger Endpoint: http://127.0.0.1:18080/t/myapp2/myapp2
Deploying hello to app: myapp2
Bumped to version 0.0.2
Building image fndemouser/hello:0.0.2 .................................................................................................
Updating function hello using image fndemouser/hello:0.0.2...
Successfully created function: hello with fndemouser/hello:0.0.2
Successfully created trigger: hello
Trigger Endpoint: http://127.0.0.1:18080/t/myapp2/hello
出来たエンドポイントを「fn list」で確認します。
[opc@instance-20200117-1627 myapp2]$ fn list triggers myapp2
FUNCTION NAME ID TYPE SOURCE ENDPOINT
hello hello 01E02CGP7NNG8G00GZJ0000005 http /hello http://127.0.0.1:18080/t/myapp2/hello
myapp2 myapp2 01E02CDPS2NG8G00GZJ0000003 http /myapp2 http://127.0.0.1:18080/t/myapp2/myapp2
curlで、エンドポイントにアクセスしてみます。
[opc@instance-20200117-1627 myapp2]$ curl http://localhost:18080/t/myapp2/hello
{"message":"Hello World"}
メッセージが出力されました。
なお、ここでメッセージを返しているGoのソースコードは、下記のようなものです。CLIでアプリを作った段階で、テンプレートとして出力されたものそのままです。
package main
import (
"context"
"encoding/json"
"fmt"
"io"
fdk "github.com/fnproject/fdk-go"
)
func main() {
fdk.Handle(fdk.HandlerFunc(myHandler))
}
type Person struct {
Name string `json:"name"`
}
func myHandler(ctx context.Context, in io.Reader, out io.Writer) {
p := &Person{Name: "World"}
json.NewDecoder(in).Decode(p)
msg := struct {
Msg string `json:"message"`
}{
Msg: fmt.Sprintf("Hello %s", p.Name),
}
json.NewEncoder(out).Encode(&msg)
}
おわりに
このエントリでは、Oracle Cloud Infrastructure(OCI)のMicro Instanceの上で動作するCentOSに、Fn Projectのサーバをインストールして、疎通確認用のアプリを動作させました。
fn server自体は、さほどメモリを使わず(筆者が試した時点では、二けたMBの前半)動作しているようなので、メモリをあまり積んでいないマシンでも、お試しをするには十分そうです。