Fn Projectを使ってJavaScriptで書いたfunctionを動かしてみる

# 概要

このエントリでは、OSSのFaaSサーバである「Fn Project」を使い、JavaScriptの関数を動かすパターンを扱います。JavaScriptのエンジンはNodeです。

下図のようなJavaScriptによる足し算の関数をFnのサーバにデプロイして動かします。

![write_node_with_code_server.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65002/ef38d5df-e149-c593-a4fa-11bfbe0e841f.png)


## 想定読者

- Fn ProjectでのJavaScriptプログラムまだ自分で動かしていない方

# 準備

Fn Projectを動かすまでのところは、別エントリ[「OCIのMicro InstanceでCentOSにFn Projectのサーバをインストールしてみる」](https://qiita.com/hrkt/items/e37bab448c8aa1b00117)を参照ください。

# Nodeでfunctionを動かす

作業の基本的な流れは、[Introduction to Fn with Node.js](https://fnproject.io/tutorials/node/intro/)に書いてあるものに従っています。

## 登録

/plusという位置にNodeで関数を一つ作るため、「fn init」を実行します。

```console
$ fn init --runtime node --trigger http plus
Creating function at: ./plus
Function boilerplate generated.
func.yaml created.
```

下記のような3つのファイルができています。

```console
$ ls
func.js  func.yaml  package.json
```

## コードを変更

下記のような、入力値のleftとrightを足して返すような関数に書き換えます。

```js
const fdk=require('@fnproject/fdk');

fdk.handle(function(input){
  let l = 0
  let r = 0
  if (input.left) {
    l = Number(input.left)
  } 
  if (input.right) {
    r = Number(input.right)
  }
  const result = l + r
  return {'result': String(result)}
})
```

「fn create app」で、fn上に「calc-fn-app」アプリを作ります。

```
$ fn create app calc-fn-app
Successfully created app:  calc-fn-app
```

アプリデプロイします。このエントリでは、「/」のfunctionは作っておらず、「/plus」のsub functionだけ作っているので、「/」に何かfunctionがある前提で作業するとエラーとなりました。このため、「-w」で作業ディレクトリを指定して、登録しています。

```console
fn --verbose deploy --app calc-fn-app --local -w /home/opc/calc-fn-app/plus
```

初回実行時には、以下のような流れとなるようです。

```console
$ fn --verbose deploy --app calc-fn-app --local -w /home/opc/calc-fn-app/plus
Deploying plus to app: calc-fn-app
Bumped to version 0.0.2
Building image fndemouser/plus:0.0.2
FN_REGISTRY:  fndemouser
Current Context:  default
Sending build context to Docker daemon   5.12kB
Step 1/9 : FROM fnproject/node:dev as build-stage
dev: Pulling from fnproject/node
bdf0201b3a05: Pull complete
ed514f6061af: Pull complete
bc8940a76c7f: Pull complete
Digest: sha256:c77966d42f46328662978a68ecd5b3b3b26cf9e4c29a91c6064f07f59f97621a
Status: Downloaded newer image for fnproject/node:dev
 ---> b557a05fec78
Step 2/9 : WORKDIR /function
 ---> Running in 36ebd3bdfcbf
Removing intermediate container 36ebd3bdfcbf
 ---> cb6b0800a4e0
Step 3/9 : ADD package.json /function/
 ---> 2a33a539a0ed
Step 4/9 : RUN npm install
 ---> Running in a2442113e25d
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN hellofn@1.0.0 No repository field.

added 1 package from 2 contributors and audited 1 package in 2.383s
found 0 vulnerabilities

Removing intermediate container a2442113e25d
 ---> ed8badb8b363
Step 5/9 : FROM fnproject/node
latest: Pulling from fnproject/node
bdf0201b3a05: Already exists
ed514f6061af: Already exists
bc8940a76c7f: Already exists
f93406d580f9: Pull complete
Digest: sha256:2ee8e9e4b1de3a29cde6fa957e3d7aaf6d2486f46926863e42af92c9d4a02404
Status: Downloaded newer image for fnproject/node:latest
 ---> c8da69259495
Step 6/9 : WORKDIR /function
 ---> Running in dd07a4c71ef0
Removing intermediate container dd07a4c71ef0
 ---> 61759b0fc6f8
Step 7/9 : ADD . /function/
 ---> a8313e0bbfa3
Step 8/9 : COPY --from=build-stage /function/node_modules/ /function/node_modules/
 ---> b0c74d29b452
Step 9/9 : ENTRYPOINT ["node", "func.js"]
 ---> Running in 17e2e33597e8
Removing intermediate container 17e2e33597e8
 ---> dc88e5ef5ab0
Successfully built dc88e5ef5ab0
Successfully tagged fndemouser/plus:0.0.2

Updating function plus using image fndemouser/plus:0.0.2...
Successfully created function: plus with fndemouser/plus:0.0.2
Successfully created trigger: plus
Trigger Endpoint: http://127.0.0.1:18080/t/calc-fn-app/plus
```

fnのコマンドで確認します。

```console
$ fn list fn calc-fn-app
NAME    IMAGE                   ID
plus    fndemouser/plus:0.0.2   01E0393FDCNG8G00GZJ000000E
```

Dockerのコマンドで確認すると、対応するコンテナのイメージができていることがわかります。

```console
$ docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
fndemouser/plus      0.0.2               dc88e5ef5ab0        33 minutes ago      75.5MB
```




## 実行

登録時の末尾にあったURLにcurlでアクセスしてみます。

```console
$ curl -d '{"left":"1", "right":"2"}' http://127.0.0.1:18080/t/calc-fn-app/plus
{"result":"3"}
```

1+2の結果である3が返ってきています。

## 補足: 引数と計算結果

JavaScriptの中で、left, rightのパラメータが指定されていなかった時には0を指定したものとみなしているため、パラメータを渡さなくても特にエラーになりません。

```console
$ curl -d '{"right":"2"}' http://127.0.0.1:18080/t/calc-fn-app/plus
{"result":"2"}
```

JavaScriptで数値として評価できない文字列、例えば「"a"」を渡すと、計算結果がJavaScriptでの「NaN」となります。

```console
$ curl -d '{"left":"a", "right":"2"}' http://127.0.0.1:18080/t/calc-fn-app/plus
{"result":"NaN"}
```

## 補足: コンテナの利用状況

計算実行直後、dockerコマンドで起動中のコンテナを調べると、下記の通り、「fnserver」と、Nodeで書いた「plus」のそれぞれのイメージのコンテナが起動しています。

```console
$ docker ps
CONTAINER ID        IMAGE                       COMMAND             CREATED             STATUS                  PORTS                               NAMES
e6d08422b11b        fndemouser/plus:0.0.2       "node func.js"      8 seconds ago       Up 7 seconds (Paused)                                       01E03BESS2NG8G00GZJ000000Y
9583c9d3662d        fnproject/fnserver:latest   "./fnserver"        9 hours ago         Up 9 hours              2375/tcp, 0.0.0.0:18080->8080/tcp   fnserver
```

少し経つと、「plus」のコンテナは終了しています。

```
$ docker ps
CONTAINER ID        IMAGE                       COMMAND             CREATED             STATUS              PORTS                               NAMES
9583c9d3662d        fnproject/fnserver:latest   "./fnserver"        9 hours ago         Up 9 hours          2375/tcp, 0.0.0.0:18080->8080/tcp   fnserver
```

この挙動は、サイトのFAQにも記載がある通り、デフォルトでは、30秒間不使用のFunction用のコンテナは捨てられます。再度リクエストがあった際、コンテナが作成されます。

再度リクエストを投げた後にdocker psしてみると、「plus」コンテナのIDが変わっていることがわかります。

```
 docker ps
CONTAINER ID        IMAGE                       COMMAND             CREATED             STATUS                  PORTS                               NAMES
7a0584e6c364        fndemouser/plus:0.0.2       "node func.js"      5 seconds ago       Up 3 seconds (Paused)                                       01E03BRZWDNG8G00GZJ0000011
9583c9d3662d        fnproject/fnserver:latest   "./fnserver"        9 hours ago         Up 9 hours              2375/tcp, 0.0.0.0:18080->8080/tcp   fnserver
```

# おわりに

このエントリでは、Fn projectを使ってJavaScriptで書いたfunctionをNodeで動かしてみることを扱いました。

このエントリで使用したコードは、[https://github.com/hrkt/calc-fn-app/releases/tag/0.0.1](https://github.com/hrkt/calc-fn-app/releases/tag/0.0.1)のタグに格納してあります。

## 補足：外部ライブラリ

このエントリでは、外部ライブラリを使いませんでした。
外部ライブラリを使う場合には、サイトの記載によると、下記の動きとなるようです。

- node_modules ディレクトリがなければ、package.jsonに従ってインストール(npm install)
- node_modules ディレクトリがある場合には、すでに外部ダウンロードされたものとみなし、node_modules以下をそのまま利用

## 補足：このエントリを書くにあたり

このエントリを書くにあたり、OCIのマイクロインスタンス上に下記の状況を作り、ノートPCからクラウド側にsshでリモートでつないで作業しました。

- sshの先にscreenで複数枚のウインドウ上げておいて作業して
- VS CodeをWEBで動かして「[cdr/code-serverとOCIのAlways FreeのMicroインスタンスでVS Codeを動かしてみる](https://qiita.com/hrkt/items/44c78f71eb72f9d29f38)」
- Fn projectのサーバもそこで動かして
- コードはGitHubに