OCI Functionsのアーキテクチャを理解する

# はじめに
[こちらで](https://qiita.com/dingtianhongjie/items/8bce6b451d658f03ca68)Fn Projectのアーキテクチャを整理しましたが、これをもとにFn ProjectのマネージドサービスであるOCI Functionsのアーキテクチャを整理したいと思います。

# 事前準備
今回はFunctionsのクライアントとして、Oracle Linuxのインスタンスを使用します。
Docker, Fn CLIなど必要なパッケージはインストール済みです。

## ポリシーの設定
以下のポリシーを設定します。

```
Allow service FaaS to use virtual-network-family in compartment <コンパートメント名>
Allow service FaaS to read repos in compartment <コンパートメント名>
```

## VCNの作成
今回は作成済みのVCNを利用します。

## OCIRの作成
今回はコンテナレジストリとしてOCIRを使用します。
事前に作成しない場合、Functionデプロイ時にルートコンパートメントにリポジトリが作成されます。

今回は以下のようにプライベートリポジトリを作成します。リポジトリ名は`任意の名称/Function名`とします。

![スクリーンショット 2023-07-10 15.54.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/d8c6d17f-29ca-555d-9ccd-38047be75588.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/d61a6f03-30fa-2a12-9b9c-64e9c740468f.png)

# Functionsの作成、実行

## アプリケーションの作成
OCIのコンソールからアプリケーションを作成します。
アプリケーション名、VCN、サブネットを以下のように指定します。

![スクリーンショット 2023-07-10 15.56.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/38ae9751-a03c-11bb-67d4-8e7436e85874.png)

こちらを確認すると、アプリケーションを作成するとFn ServerもFunction単位で作成されるようです。

https://docs.oracle.com/ja-jp/iaas/Content/Functions/Concepts/functionshowitworks.htm


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/38670e9d-7ea7-4db0-a49c-acf1067a85f8.png)


以降はアプリケーション作成後のコンソールの`スタート・ガイド`にサンプルファンクションの実行手順がありますので、これに沿って設定します。
今回は`ローカル設定`の手順です。

![スクリーンショット 2023-07-10 15.58.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/e83e75e4-2b5a-9e73-5247-4fe1f6d54093.png)

## Functionの初期化、雛形作成
引数に言語とFunction名を指定して雛形を作成します。

```
$ fn init --runtime go hello-func
Creating function at: ./hello-func
Function boilerplate generated.
func.yaml created.
$ ls -l hello-func/
total 12
-rw-r--r--. 1 opc opc 521 Jul 10 06:33 func.go
-rw-r--r--. 1 opc opc 152 Jul 10 06:42 func.yaml
-rw-r--r--. 1 opc opc  58 Jul 10 06:33 go.mod
$ cd hello-func/
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/cd07bfae-0126-4173-1895-82b172cbb475.png)


## Contextの設定
デフォルトでContextはLocalhostになっていますので、新しいContextを追加して、OCIに接続するように変更します。

```
$ fn create context lhr --provider oracle
Successfully created context: lhr 
$ fn use context lhr
Now using context: lhr 
$ fn list context
CURRENT NAME    PROVIDER        API URL                 REGISTRY
        default default         http://localhost:8080
*       lhr     oracle
```

FunctionをデプロイするコンパートメントのOCIDを設定します。

```
$ fn update context oracle.compartment-id ocid1.compartment.oc1..aaaaaaaamyemvazvbgl42f5pi7gzxxxxxxxxxxxxxxxxxxxxxxxxxxx
Current context updated oracle.compartment-id with ocid1.compartment.oc1..aaaaaaaamyemvazvbgl42f5pi7gzxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

API URLを指定します。これはリージョンによって異なります。

```
$ fn update context api-url https://functions.uk-london-1.oraclecloud.com
Current context updated api-url with https://functions.uk-london-1.oraclecloud.com
```

Buildしたコンテナイメージを保存するリポジトリを設定します。
これは事前に作成したリポジトリからFunction名を除いて設定します。

```
$ fn update context registry lhr.ocir.io/orasejapan/lhr-functions-repo-01
Current context updated registry with lhr.ocir.io/orasejapan/lhr-functions-repo-01
```

確認します。

```
$ fn list context
CURRENT NAME    PROVIDER        API URL                                         REGISTRY
        default default         http://localhost:8080
*       lhr     oracle          https://functions.uk-london-1.oraclecloud.com   lhr.ocir.io/orasejapan/lhr-functions-repo-01
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/da297a7d-f515-6602-6987-55573336210a.png)


## Functionのデプロイ
OCIRにログインします。ログインする際のパスワードは認証トークンです。
認証トークンは事前に作成する必要がありますが、今回は[こちら](https://qiita.com/dingtianhongjie/items/7d1270bfd327da800bbd#%E8%AA%8D%E8%A8%BC%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%81%AE%E4%BD%9C%E6%88%90)で作成したトークンを利用します。

```
$ docker login lhr.ocir.io
```

アプリケーション名を指定してFunctionをデプロイします。

```
$ fn deploy --app app01
Deploying hello-func to app: app01
Bumped to version 0.0.2
Using Container engine docker
Building image lhr.ocir.io/orasejapan/lhr-functions-repo-01/hello-func:0.0.2 ......................................
Updating function hello-func using image lhr.ocir.io/orasejapan/lhr-functions-repo-01/hello-func:0.0.2...
```

Buildされたコンテナイメージが指定したOCIRのリポジトリに保存されています。

![スクリーンショット 2023-07-10 15.51.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/0090d4ea-5400-2acc-f9fe-289c6802028b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/e5220691-61b8-1715-0150-5190192cacaa.png)


fnコマンドでもアプリケーションとFunctionが確認できます。

```
$ fn list app
NAME    ID
app01   ocid1.fnapp.oc1.uk-london-1.aaaaaaaaxp5k5v6q3wqqfbyctrqzsvofpxxxxxxxxxxxxxxxxxxxxxxxx
$ fn list f app01
NAME            IMAGE                                                           ID
hello-func      lhr.ocir.io/orasejapan/lhr-functions-repo-01/hello-func:0.0.2   ocid1.fnfunc.oc1.uk-london-1.aaaaaaaarbcpzevlocpdtpcn622ep4qnzcz4x27prmqtkeqswbpt5s6x7bhq
```

# Functionの実行
以下のコマンドを実行してFunctionを実行します。

```
$ fn invoke app01 hello-func
{"message":"Hello World"}
```

Functionを実行すると以下のような流れでコードが実行されます。

1. コンテナイメージのPull
1. コンテナの実行
1. コードの実行
1. コンテナの削除

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/9a0ce844-0eb2-bca9-4a06-750e3119a33b.png)

Functionが複数回実行された場合の動作は、以下のように実行されたタイミングによって異なります。

> ファンクションの実行が終了し、アイドル状態の期間が経過すると、Dockerコンテナは削除されます。コンテナが削除される前に、OCIファンクションが同じファンクションに対する別のコールを受信すると、2番目のリクエストは同じ実行中のコンテナにルーティングされます。OCIファンクションが、実行中のコンテナ内で現在実行中のファンクションに対するコールを受け取ると、OCIファンクションは水平方向にスケーリングして、両方の着信リクエストを提供し、2番目のDockerコンテナが開始されます。

https://docs.oracle.com/ja-jp/iaas/Content/Functions/Concepts/functionshowitworks.htm#invoke