OCI Functions をPodman 環境から実行する

# 今回やりたいこと
タイトルの通りコンピュート・インスタンス（以下インスタンス）内に作成したPodman環境から、OCI Functions（以下ファンクション）を実行できるか検証を行います。
![スクリーンショット 2025-03-20 9.08.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/3b2193ff-c5cc-47a7-8762-f6f5f2e01706.png)

# 実行環境
今回の実行環境は以下の通りです。
## ネットワーク
* VCN：`VCN_10.0.0.0/16`
    * パブリック・サブネット：`Pubsub_10.0.0.0/24`
    * インターネット・ゲートウェイ：IGW（パブリック・サブネットにアタッチ）
* ルート表(パブリック・サブネット用)​
    * 宛先CIDR：`0.0.0.0/0`
    * ターゲット：`IGW​`
※ セキュリティ・リストはデフォルト設定のまま使用します。

## ポリシー
以下のIAM ポリシーを設定することで、ファンクションを適切に利用できるようになります。
（`fn-group`は例です。実際に使用するグループに置き換えて設定してください。）
* **コンパートメントの作成権限**
`Allow group fn-group to manage compartments in tenancy`
※ 既にコンパートメントを作成済みの場合、このポリシーは不要です。
* **VCNの作成権限**
`Allow group fn-group to manage virtual-network-family in tenancy`
※ 今回はVCNの作成から実施するため、`manage`権限を付与しています。
既にVCNを作成済みの場合、使用権限を許可する`use`権限の付与を推奨します。
* **ファンクションおよびアプリケーションの作成権限**
`Allow group fn-group to manage functions-family in tenancy`
* **オブジェクト・ストレージ・ネームスペースの取得権限**
`Allow group fn-group to read objectstorage-namespaces in tenancy`
* **ファンクションのレジストリ読み取り権限**
`Allow service FaaS to read repos in tenancy`
* **インスタンスの作成権限**
`Allow group fn-group to manage instance-family in tenancy`
※ インスタンスからではなく、ローカル端末から実行する場合は不要です。


## インスタンス
認証を分離するため、ローカル端末ではなく、同じパブリック・サブネット内にインスタンスを構築してファンクションの設定を行います。
インスタンスのスペックは任意ですが、今回は以下の設定で作成します。
※ローカル端末からでも実行可能であるため、本手順ではインスタンス作成を割愛します。
* OS：`Oracle Linux 9`
* OCPU：`1 OCPU`
* メモリ：`8 GB`
* ストレージ：`50 GB`

# 本手順
## 1.コンパートメントの作成
最初にコンパートメントの作成を行います。
既にコンパートメント作成済みの場合、この手順をスキップしてください。
OCIコンソール画面左上のナビゲーションメニューから「**アイデンティティとセキュリティ**」→「**コンパートメント**」をそれぞれ選択します。
![スクリーンショット 2025-03-20 9.22.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/71bbf0a5-0cf7-4bde-a575-8ed7c78c8569.png)

「**コンパートメントの作成**」を選択します。
![スクリーンショット 2025-03-20 9.24.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/023861a2-8d3e-4717-be7d-12d4cfc54929.png)

名前・説明ともに任意ですが、ここでは以下リソース名を入力、「**コンパートメントの作成**」を選択します。
* 名前：`fn-compartment`
* 説明：`ファンクション用コンパートメント`
![スクリーンショット 2025-03-20 9.27.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/28de8e2f-e237-41db-88f3-a86149f0c78e.png)

`fn-compartment`コンパートメントが作成されます。
![スクリーンショット 2025-03-20 9.34.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/638f4601-b1a1-4b51-b4ae-aaf844df7976.png)

## 2.ネットワークの作成
コンパートメントの作成後、VCNを作成します。
今回はVCNウィザードからではなく、手動でVCNを作成します。
### VCN
OCIコンソール画面左上のナビゲーションメニューから「**ネットワーキング**」→「**仮想クラウド・ネットワーク**」をそれぞれ選択します。
![スクリーンショット 2025-03-20 9.37.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/9280876d-5edf-484d-a703-7d6d1ce484fe.png)

作成したコンパートメント（ここでは`tf-compartment`）が選択されていることを確認、「**VCNの作成**」を選択します。
![スクリーンショット 2025-03-20 9.39.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/fcbdf7d6-d308-446b-9a35-ac6bbb11b59e.png)

ここでは以下リソース名を入力、「**VCNの作成**」を選択します。
* 名前：`VCN_10.0.0.0/16`
* IPv4 CIDR ブロック：`10.0.0.0/16`
※他の設定は任意で問題ございません。
![スクリーンショット 2025-03-20 9.44.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/e5fdea54-702f-4082-8d0d-7020b6bb6657.png)

VCNが作成されます。
![スクリーンショット 2025-03-20 10.31.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/0210b066-8b8b-4149-8381-a151ec98d6e7.png)

### サブネット
「**サブネットの作成**」から、今回はパブリック・サブネットを作成します。
![スクリーンショット 2025-03-20 10.31.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/b6da55d6-c112-46f5-bd6c-8c9f38e24db9.png)

ここでは以下リソース名を入力、「**サブネットの作成**」を選択します。
* 名前：`Subpub_10.0.0.0/24`
* IPv4 CIDR ブロック：`10.0.0.0/24`
* サブネット・アクセス：パブリック
※他の設定は任意で問題ございません。
![スクリーンショット 2025-03-20 10.34.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/1fa6c7f5-cfbc-499f-8066-5cd474b3713e.png)
![スクリーンショット 2025-03-20 10.35.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/b2366a21-290f-4090-89b0-9abb3e1d76be.png)

状態が「**プロビジョニング中**」→「**使用可能**」に遷移、サブネットが作成されます。
![スクリーンショット 2025-03-20 10.36.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/a043a294-31e0-4132-a494-02c195750be0.png)

### インターネット・ゲートウェイ
「**インターネット・ゲートウェイ**」→「**インターネット・ゲートウェイの作成**」から作成を行います。
![スクリーンショット 2025-03-20 10.37.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/5ed90567-ada0-49ae-a154-de77d85c2f72.png)

ここでは名前を`IGW`とし、「**インターネット・ゲートウェイの作成**」を選択します。
![スクリーンショット 2025-03-20 10.38.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/52f823c7-0093-4b24-87eb-8d69d80810e0.png)

インターネット・ゲートウェイが作成されます。
![スクリーンショット 2025-03-20 10.39.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/d4bff34e-8f36-4d77-a9bd-131e9bcca3ff.png)

### ルート表
ゲートウェイの作成後、パブリック・サブネット用のルート表を作成します。
「**ルート表**」→「**ルート表の作成**」を選択します。
![スクリーンショット 2025-03-20 10.41.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/374c0c6e-0c5a-4ad2-84e9-a2c8fb6024ab.png)

ここでは以下を入力、「**作成**」を選択します。
* 名前：`RT-Pub`
* ルート・ルール
    * ターゲット・タイプ：`インターネット・ゲートウェイ`
    * 宛先CIDRブロック：`0.0.0.0/0`
    * ターゲット・インターネット・ゲートウェイ：`IGW`
※他の設定は任意で問題ございません。
![スクリーンショット 2025-03-20 10.44.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/e7d8debc-fb87-47cb-badb-1d813b9901a1.png)

ルート表が作成されます。
![スクリーンショット 2025-03-20 10.45.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/29d7b3ab-848e-4554-846b-7d5c7df02a0d.png)

パブリック・サブネットのルート表はデフォルトのルート表を使用しているため、作成したルート表に置き換える必要があります。
サブネットの詳細画面の「**編集**」を選択します。
![スクリーンショット 2025-03-20 10.47.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/d55b84a1-8381-49db-8eda-3ef0a1168ec5.png)

ルート表を作成したリソースに変更、「**変更の保存**」を選択します。
![スクリーンショット 2025-03-20 10.49.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/fd730016-34d7-4cad-a93a-1aad12c9542a.png)

状態が「**UPDATING**」→「**AVAILABLE**」に遷移、ルート表が変更されます。
![スクリーンショット 2025-03-20 10.50.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/810c97db-ec92-47d2-8b9e-bfbd20b36351.png)

ネットワーク関連のリソース作成については以上です。
なお、NSGやセキュリティリストは、必要に応じて適宜設定してください。

## 3.ファンクションの作成
コンテナ・レジストリの作成後、ファンクションを作成します。
OCIコンソール画面左上のナビゲーションメニューから「**開発者サービス**」→「**アプリケーション**」をそれぞれ選択します。
![スクリーンショット 2025-03-20 10.57.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/148b8fa9-0e40-46bd-a6fe-8d3ff98861a9.png)

「**アプリケーションの作成**」を選択します。
![スクリーンショット 2025-03-20 11.07.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/c30eae85-160d-47be-9b53-83282f0ba982.png)

ここでは以下を入力、「**作成**」を選択します。
* 名前：`helloworld-app`
* VCN：`VCN_10.0.0.0/16`
* サブネット：`Subpub_10.0.0.0/24`
※他の設定は任意で問題ございません。
![スクリーンショット 2025-03-20 11.08.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/f614ce0f-39cf-48c3-a8fd-14b46f474dba.png)

ファンクションが作成されます。
![スクリーンショット 2025-03-20 11.11.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/7cbcacc6-1c6c-4a6b-bee5-071e84357959.png)

## 4.ファンクションのセットアップ
ここでは、パブリックサブネット上のインスタンスからファンクションのセットアップを実行します。
その前に、インスタンス上でOCI CLIをセットアップする必要があります。
手順については、以下を参考にしてください。

https://docs.oracle.com/ja-jp/iaas/Content/API/SDKDocs/cliinstall.htm

### podmanとpodman-dockerのインストール
この後インストールするFn Projectではpodmanをサポートしているため、今回はpodmanを以下コマンドでインストールします。
```
sudo dnf install -y podman
```
```
sudo dnf install -y podman-docker
```

以下コマンドで結果を確認します。
```
docker version
```

```:実行結果例
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
Client:       Podman Engine
Version:      5.2.2
API Version:  5.2.2
Go Version:   go1.22.9 (Red Hat 1.22.9-2.el9_5)
Built:        Tue Feb  4 19:50:29 2025
OS/Arch:      linux/amd64
```

### Fnのインストール
合わせてFn Projectのインストールも行います。
Fn Projectとは、開発者エクスペリエンス重視なFaaSを構築するためのプラットフォームです。
インストール前に.bashrcのPATHに`/usr/local/bin`を追加します。
```shell
cd ~
```

```
vim .bashrc
```

```shell:.bashrc
# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

# User specific environment
if ! [[ "$PATH" =~ "$HOME/.local/bin:$HOME/bin:" ]]
then
    PATH="$HOME/.local/bin:$HOME/bin:$PATH"
fi
export PATH

# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

# 以下の行を追加
export PATH="$PATH:/usr/local/bin"
```

追加後、`source`コマンドで設定を反映します。
```
source .bashrc
```

以下コマンドでFn Projectをインストールします。
```
curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh
```
```:実行結果例
fn version 0.6.39

        ______
       / ____/___
      / /_  / __ \
     / __/ / / / /
    /_/   /_/ /_/`
```

インストール後、`which`コマンドでFn Projectの実行コマンド(`fn`）が使用可能か確認します。
```
which fn
```
```:実行結果例
/usr/local/bin/fn
```

FnのコンテナエンジンをDockerからPodmanに変更します。
```
vim ~/.fn/config.yaml
```

```:実行結果例
cli-version: 0.6.39
# docker→podmanに変更
container-enginetype: podman
```

### 認証トークンの取得
Fn Projectをインストールした後、OCIコンソールに戻り、Dockerのログインに必要な認証トークンを取得します。
対象ユーザー（ここでは`fn-user`）のマイ・プロファイルから「**認証トークン**」→「**トークンの生成**」を選択します。
![スクリーンショット 2025-03-20 12.47.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/9685b071-943e-4b1a-9a11-4fa1414a15ea.png)

任意の説明（ここでは「ファンクション用」）を入力、「**トークンの生成**」を選択します。
![スクリーンショット 2025-03-20 12.50.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/3d514758-3f31-4e46-bd66-c54f3243f468.png)

Dockerのログイン時に必要となるため、「**コピー**」でトークンを控えておきます。
![スクリーンショット 2025-03-20 12.51.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/269a3a5f-4b6c-4398-bc3d-a4e738229fbb.png)


### ローカル・セットアップ
認証トークンの取得後、アプリケーションの詳細画面にある「**Local setup**」の手順を参考にセットアップを行います。
![スクリーンショット 2025-03-20 12.33.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/41f5f321-2a31-4493-91d8-c1a2db7aa7e1.png)

最初に、ここではPythonを実行環境として`my-func`というファンクションを作成します。
```
fn init --runtime python my-func
```
```:実行結果例
Creating function at: ./my-func
Function boilerplate generated.
func.yaml created.
```

作成した`my-func`ディレクトリに移動します。
```
cd my-func
```

`fn-compartment`という名前のFnプロジェクトのコンテキストを作成し、OCIをプロバイダとして指定します。
```
fn create context fn-compartment --provider oracle
```
```:実行結果例
Successfully created context: fn-compartment
```

作成した`fn-compartment`コンテキストを現在の作業環境として使用します。
```
fn use context fn-compartment
```
```:実行結果例
Now using context: fn-compartment
```

コンテキストにコンパートメントOCIDを設定します。
```
fn update context oracle.compartment-id ocid1.compartment.oc1..aaaaaaaaxxx
```
```:実行結果例
Current context updated oracle.compartment-id with ocid1.compartment.oc1..aaaaaaaaxxx
```

ファンクションのエンドポイントURLを設定します。
（ここでは東京リージョンを指定します。）
```
fn update context api-url https://functions.ap-tokyo-1.oraclecloud.com
```
```:実行結果例
Current context updated api-url with https://functions.ap-tokyo-1.oraclecloud.com
```

関数をコンテナイメージとして保存するコンテナ・レジストリ（OCIR）のURLを設定します。
```
fn update context registry nrt.ocir.io/<オブジェクト・ストレージのネームスペース>/fn-repo
```
```:実行結果例
Current context updated registry with nrt.ocir.io/<オブジェクト・ストレージのネームスペース>/fn-repo
```

Dockerにコンテナ・レジストリへの認証情報を設定し、ログインします。
```
docker login -u '<オブジェクト・ストレージのネームスペース>/fn-user' nrt.ocir.io
```
```:実行結果例
Password: 
Login Succeeded!
```

作成したアプリケーション（ここでは`helloworld-app`）に作成したファンクション（ここでは`my-func`） をデプロイ（デプロイ時にコンテナイメージが作成され、OCIRへプッシュされる）。
```
fn deploy --app helloworld-app
```
```:実行結果例
Deploying my-func to app: helloworld-app
Bumped to version 0.0.6
Using Container engine podman
Building image nrt.ocir.io/nrxe3k7cw1gm/fn-repo/my-func:0.0.6 TargetedPlatform:  amd64HostPlatform:  amd64
..................
Using Container engine  podman  to push
Pushing nrt.ocir.io/<オブジェクト・ストレージのネームスペース>/fn-repo/my-func:0.0.6 to docker registry...Getting image source signatures
Copying blob 7211f2483774 done   | 
Copying blob f5f24e15a6d0 done   | 
Copying blob 1508d2f8d3a7 done   | 
Copying blob a7b34eff3525 done   | 
Copying blob b6b3ea7877e7 done   | 
Copying config d5b0caea1d done   | 
Writing manifest to image destination
Updating function my-func using image nrt.ocir.io/<オブジェクト・ストレージのネームスペース>/fn-repo/my-func:0.0.6...
Successfully created function: my-func with nrt.ocir.io/<オブジェクト・ストレージのネームスペース>/fn-repo/my-func:0.0.6
```

デプロイ時に以下エラーが発生する場合があります。
```:エラー
Deploying my-func to app: helloworld-app
Bumped to version 0.0.5
Using Container engine podman
Building image nrt.ocir.io/<オブジェクト・ストレージのネームスペース>/fn-repo/my-func:0.0.5 TargetedPlatform:  amd64HostPlatform:  amd64

Error during build. Run with `--verbose` flag to see what went wrong. eg: `fn --verbose CMD`

Fn: error running docker build: exit status 125

See 'fn <command> --help' for more information. Client version: 0.6.39
```

この場合、短縮名のコンテナイメージは解決できないことが原因で`/etc/containers/registries.conf`で以下内容に変更すればエラー解消される可能性があります。
```:/etc/containers/registries.conf
# enforcing→permissiveに変更
[registries]
short-name-mode = "permissive"
```

アプリケーションの詳細画面を確認すると、ファンクションが新たに作成されています。
![スクリーンショット 2025-03-20 14.42.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/4b9046a1-d46e-4152-9a09-07b6009cc5b8.png)


作成したアプリケーション（ここでは`helloworld-app`）の ファンクション（ここでは`my-func`）を実行し、結果を取得します。
```
fn invoke helloworld-app my-func
```

30秒程度時間が経過したのち、スクリプト（ここでは`func.py`）で設定した内容が表示されます。
```:実行結果例
{"message": "Hello World"}
```

OCI FuctionsをPodman環境から実行する手順については以上となります。

# 引用ドキュメント等

https://docs.oracle.com/ja-jp/iaas/Content/API/SDKDocs/cliinstall.htm#InstallingCLI__oraclelinux9

https://qiita.com/ora_gonsuke777/items/2efa42eb189778c5417e