サーバレス(Oracle Functions)でWeb動的サイトを構築しました

#本投稿の背景

フットサル大会の運用をシステム化([ こちらの記事 ](https://qiita.com/kngsym2018/items/514bf738ce1c6a1c81ba))したのですが、
2020年3月からコロナの影響でフットサルの大会は実施されていません。。

この状況で以下を考えました。
**・コロナで大会が中止。システム運用している仮想マシンは24時間 x 365日稼働する必要なし**
**・大会結果を参照したい人がいれば、そのタイミングで参照できればよい**
**・内容はチーム順位、得点者を表示するシンプルなものなので、Wordpressでなくてもよい**

それを解決するのが、「サーバレス」と思ったので、
実験的にOCIでサーバレス「Oracle Functions」でWeb動的サイトを作ってみました。

※息子たちがF１マシンの絵をかいていたので、
　それを使ったWebサイトを作ろうと思ったのも理由です。

#構成図
・DBは Autonomous Databaseを使用 ※無料枠の[Always free]
・Oracle Functionsでは(「チーム一覧ページ」、「チーム詳細ページ」）を作成
　 **<font color="Red">※いずれのページもDBに接続してデータからページ内容を作成しています
　　　(静的ページ表示ではありません)**</font>
　 ※詳細表示ページではオブジェクトストレージに格納した画像を参照しています
・API Gatewayでユーザから接続するエンドポイントをまとめる
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/9bfdf535-a88a-4e76-cf1a-ff9f49cbcc7f.png" width=500 />


#実際につくってみたWebサイト

|<img width="300" alt="take3.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/75e0cff8-70ae-762d-84b4-5d1d149160f7.gif">|
|:-:|


#サーバレス(Oracle Functions)でWebサイトを構築する流れ

以下の手順で構築します
**１．Autonomous Databaseを作成**
**２．画像ファイルをオブジェクトストレージに格納**
**３．ネットワークの作成**
**４．Oracle Functions を使う前の準備**
**５．Oracle Functions 「チーム一覧ページ」作成**
**６．API Gatewayの作成**
**７．Oracle Functions 「チーム詳細ページ」作成**
**８．「チーム一覧ページ」の「チーム詳細ページ」動作確認**

※構築の事前準備として
　コンパートメント「serverless」を作成しており、Oracle Functions等はコンパートメント「serverless」に作成します。

**※設定手順などの詳細は、折りたたんでいるので、確認は ▶　をクリックください**

#１．Autonomous Databaseを作成

Autonomous Databaseに２つのテーブルを作成します。
「チーム一覧ページ」、「チーム詳細ページ」で使用するテーブル・データとなります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/1394bf0c-a578-d215-df1c-196e79951357.png" width=500 />

作成するテーブルとデータ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/b6dd688e-45a4-5468-e08c-032b1c5450b6.png)

##１－１．Autonomous Databaseを作成

<details><summary>Autonomous Databaseを作成する詳細手順はこちら</summary><div>
作成するWebサイトは、DBに格納しているデータを使用してWebページを作成します。
Always free(無料)でDBを作成します。

[Oracle Database] - [Autonomous Database]を選択

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/997e7d39-6d52-814f-4c72-a277efe9ce7e.png" width=300 />

「コンパートメント」を確認して、[Autonomous Databaseの作成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/34668167-eb02-7bd8-f364-8e1a9d710e3b.png" width=450 />


「コンパートメント」、「表示名」、「データベース名」を設定。
「ワークロード・タイプ」は[データウェアハウス]、「デプロイメント・タイプ」は[共有インフラストラクチャ」を選択
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/8b683722-d971-b2be-baa6-f622fc5ef8b2.png" width=450 />

「Always Free」をON、「パスワード」を入力して、[Autonomous Databaseの作成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/f78eae79-afda-46c3-ab06-7dac10c17f2a.png" width=450 />

作成されたDBをクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/e43c5d7e-f9f6-b8a7-b094-37e5023d7ab7.png" width=450 />

</div></details>

##１－２．Autonomous Database の wallet を取得
<details><summary>Autonomous Database の wallet を取得する詳細手順はこちら</summary><div>
Autonomous Database にDB接続する際、walletが必要になりますので取得します。
※Oracle Functions でもwalletを使用します

>Autonomous Databaseには暗号化およびSSL相互認証を利用した接続が前提としており、そのため接続する際はクレデンシャル・ウォレット（Credential.zipファイル）を利用する必要があります
https://oracle-japan.github.io/ocitutorials/database/adb104-connect-using-wallet/

[DB接続]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/ba31aea4-0563-3b40-5a50-c29ba5ebe54d.png" width=300 />

[ウォレットのダウンロード]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/a69f6d07-94cd-a744-7ec7-d382100cc80d.png" width=300 />

設定したパスワードを入力して、[ダウンロード]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/b0882fa0-0b5e-1133-a293-b4aea7ae4e09.png" width=300 />

</div></details>

##１－３．DBスキーマ、テーブル作成

<details><summary>DBスキーマ、テーブル作成する詳細手順はこちら</summary><div>
Webサイトで使用するDBスキーマ、テーブルを作成します。

[データベース・アクション]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/9cca6862-b1a3-d0a3-6a54-313fa6251e2d.png" width=300 />
[ユーザの作成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/255f801f-66e1-9405-f514-66014881c05e.png" width=450 />

ユーザ情報とWebアクセスを有効、表領域を割り当て、[ユーザの作成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/63ab2294-f78d-c536-46cf-15c7fa19f185.png" width=450 />

コンソール画面右上をみると、ADMINでログインになっているので、[サインアウト]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/f5df619c-63c2-a916-ca40-ecf2e7e5dc9e.png" width=250 />

作成したユーザ名、パスワードを入力して[サインイン]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/c48b4f9f-21b6-38a4-3273-70ccebf08245.png" width=350 />

「SQL」をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/522f8348-5989-8f39-4608-5babd65c4337.png" width=450 />

[ワークシート]にSQLを入力して、[実行(赤枠）]をクリックしてSQLを実行
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/727b0bde-a73a-452d-65c3-511bafea5d56.png" width=350 />


```sql:ddl文

CREATE TABLE  TEAM 
    ( 
     TEAM_ID     NUMBER , 
     TEAM_NAME VARCHAR2 (100) ,
     IMG_URL VARCHAR2 (100) ,
     CONSTRAINT PK_TEAM PRIMARY KEY(TEAM_ID)
    ) ;

CREATE TABLE F1DRIVER 
    ( 
     TEAM_ID     NUMBER , 
     DRIVER_NO   NUMBER , 
     DRIVER_NAME VARCHAR2 (100),
     CONSTRAINT PK_F1DRIVER PRIMARY KEY ( TEAM_ID, DRIVER_NO ) 
    ) ;

```

あとは、データを登録。

</div></details>

#２．画像ファイルをオブジェクトストレージに格納
「チーム詳細ページ」で表示する画像をオブジェクトストレージに格納します。
 バケットを作成して、画像ファイルをアップロードして、可視性の設定をします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/49e028de-0e81-1819-6207-ee0fcb50d778.png" width=500 />

##２－１．オブジェクト・ストレージの設定

<details><summary>オブジェクト・ストレージ設定する詳細手順はこちら</summary><div>
[ストレージ]-[オブジェクト・ストレージ]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/886d4111-7e27-a59b-c9c5-cf6ba62b7eab.png" width=300 />

コンパートメントを確認して、[バケットの作成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/03d351fd-464b-f3a3-9bcc-3bbc79260a7a.png" width=300 />

[バケット名]を入力して、[作成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/f5a027c3-8c35-1b12-5e88-d4d8be7fc41b.png" width=300 />

[可視性の編集]をクリックして、[パブリック]を選択して、[変更の保存]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/a74fd3c4-580f-6ea5-f29b-ece20f0fef48.png" width=450 />

[可視性]がパブリックになっていることを確認
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/b73abf56-2377-cdd3-49eb-983f16b02771.png" width=450 />

画像をアップロードするため、[アップロード]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/dcc968e3-12b1-2ed2-95c7-e2a8e6246fbb.png" width=300 />
画像を赤枠にドロップして、[アップロード]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/8aa89aff-c44b-e2cc-ee4c-2a840eaf4610.png" width=450 />

[オブジェクト詳細の表示]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/a5ac6541-cdad-3a3d-1d02-cc1c6c93bf18.png" width=450 />

URLパスをクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/06956d95-889e-6556-b78d-1bdb7dbf7f11.png" width=450 />
画像が表示されれば設定は完了
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/eda0eada-cc92-b90b-b96d-7d80881bbc75.png" width=300 />

</div></details>

#３．ネットワークの作成
Oracle Functions、API Gatewayを配置するネットワークを作成します。
※VCNウィザードでネットワークを作成します

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/1cfdd6ec-cd11-fcac-217a-6a4ef2580be1.png" width=500 />

##３－１．VCNウィザードを実行

<details><summary>VCNウィザードを実行する詳細手順はこちら</summary><div>
[ネットワーキング]-[仮想クラウド・ネットワーク]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/7d6c1d84-54c1-5170-effa-d6b1ff3c5dc5.png" width=300 />
[VCNウィザードの起動]をクリックします
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/8994cc6f-ea9b-5a04-3eae-f32a12515d54.png" width=300 />

[インターネット接続性を持つVCNの作成]を選択して、[VCNウィザードの起動]をクリックします
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/747a311f-d418-7588-ae48-19ff74e86f0e.png" width=300 />
[VCN名]を入力、[コンパートメント]を選択して、[次]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/489995c0-cc71-a8f8-6802-d36e191c5489.png" width=300 />
[作成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/85045625-8594-5eb1-d712-6008a98cf1eb.png" width=300 />
[仮想クラウド・ネットワークの表示]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/8f8d2e26-5940-2989-1599-af07cef9f643.png" width=450 />
パブリックサブネットにSSLの通信許可をするため、「パブリックサブネット」をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/05e6d11c-3205-9c09-8a98-226b040588fb.png" width=450 />

</div></details>

##３－２．ネットワークセキュリティ設定
<details><summary>ネットワークセキュリティ設定する詳細手順はこちら</summary><div>
セキュリティリストをクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/8999453d-39bc-0333-5556-dc11015c0726.png" width=450 />
[イングレス・ルールの追加]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/a5e0be34-4212-1f5a-e4b8-443e29d2d7ee.png" width=300 />
[イングレス・ルールの追加]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/5261bb7e-e6d8-3b25-ffb4-60cde65da777.png" width=300 />

「ソースCIDR」を[0.0.0.0/0]、「宛先ポート範囲」を[443]を設定して、[イングレス・ルールの追加]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/32a4803c-3c5d-b4c6-c859-a801439013ee.png" width=450 />

ポート443の許可設定を確認
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/f74cf4dc-2e45-f26a-f4a6-0e001ce7c0d9.png" width=350 />

</div></details>

#４．Oracle Functions を使う前の準備

Oracle Functionsを使う前準備をします。
ここではCloud shellを使用してOracle Functionsをデプロイする設定とOracle Functionsを登録するアプリケーションの設定を行います。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/a14f9764-a004-cc21-db7b-f8d7a811317c.png" width=500 />

事前準備の詳細は以下のページを参照ください（わかりやすく解説されています)
https://oracle-japan.github.io/ocitutorials/cloud-native/functions-for-beginners/

##４－１．Cloud shellを設定

<details><summary>Cloud shellを設定する詳細手順はこちら</summary><div>
コンソール画面の右上の Cloud Shellをクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/3aa31ed2-3cc3-d83d-233e-231372ac60ac.png" width=300 />

Cloud Shellのコンソールが起動(赤枠)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/f43e2c24-166c-dc9e-ce57-97af92509030.png" width=450 />

ユーザ設定の認証トークンを取得します。
※Oracle Functions管理するOracle提供のプライベートDockerレジストリのログインに必要
コンソール画面の人のアイコンをクリックして、[ユーザ設定]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/3ef9a3b5-b330-1b21-c705-a29ff5c69afe.png" width=300 />

[認証トークン]-[トークンの生成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/43145759-9d29-4083-744f-abc2faa147b6.png" width=300 />
[説明]を入れて、[トークンの生成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/c7ea235f-43b3-4098-bab9-08337dec212d.png" width=300 />
「生成されたトークン」の[コピー]をクリック
※この情報を控えておきます。あとで必要になります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/bc28d955-117b-28b6-e987-53d4a1a062a6.png" width=300 />
コンソール画面の人のアイコンをクリックして、[テナンシ]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/047705ee-7085-f762-fced-d0172ac54273.png" width=300 />
「テナンシ情報」のOCIDの[コピー]をクリック
※この情報を控えておきます。あとで必要になります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/5bf69c58-5f09-f91b-30d5-714703c1c6a4.png" width=300 />

Oracle FunctionsをデプロイするためのにOracle Functions CLIを利用して環境を作成します。
開発環境の設定は、fn updateコマンドを使用して行います。
＞https://oracle-japan.github.io/ocitutorials/cloud-native/functions-for-beginners/
※cloud Shellで以下のコマンドを入力していきます。

リージョンを設定します。東京リージョンの場合はap-tokyo-1

```shell:CloudShellで実行
fn use context ap-tokyo-1
```

テナンシーのOCIDを設定

```shell:CloudShellで実行
fn update context oracle.compartment-id ocid1.tenancy.oc1..aaaaaaa<省略>
```

レジストリ名を登録します
※Oracle Functionsを管理するOracle提供のプライベートDockerレジストリ

```shell:CloudShellで実行
fn update context registry iad.ocir.io/xxxxx/functions-serverless

fn update context registry iad.ocir.io/<オブジェクト・ストレージ・ネームスペース>/<任意の名前>
```

※オブジェクト・ストレージ・ネームスペースの確認方法
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/9fe700fb-4b21-33e4-e300-db47c26c0a1e.png" width=350 />


レジストリにログイン
パスワードは「トークンの生成」で作成したものを入力

```shell:CloudShellで実行
 docker login nrt.ocir.io
```

Login Succceeded となれはOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/d1e0fa4b-89e4-037e-6c33-a3466978c042.png)

</div></details>

##４－２．アプリケーションの作成

<details><summary>アプリケーションを作成する詳細手順はこちら</summary><div>
　
アプリケーションとOracle Functions の関係は以下のイメージは以下の図になります。
アプリケーションがいて、その下にファンクションがぶら下がる。
今回はアプリケーション名は「fn-f1site」
ファンクション名は、「f1_teamlist」、「f1_teamdetail」で作成します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/22ec6787-61ee-083c-5862-994aacc1b2a6.png" width=300 />
[開発者サービス]-[ファンクション]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/86868ded-ac2f-4ba0-9f0a-82708deae060.png" width=300 />

コンパートメント名を確認して、[アプリケーションの作成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/ddecd025-65c2-9913-dbf8-8136cd854f46.png" width=300 />

「名前」を入力、「VCN」を作成したVCN、「サブネット」はパブリックサブネットを選択して、[作成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/bf917a42-b234-465f-3238-e1e8a3a7c06e.png" width=300 />

アプリケーションが登録されたことを確認
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/713b8486-cc8b-8f59-4441-5c36837bc6be.png" width=450 />


</div></details>

#５．Oracle Functions 「チーム一覧ページ」作成
ここからは、Oracle Functions を作成します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/e625ccf2-da20-7922-59ab-f478b646fa47.png" width=500 />


ここで実施する作業は、
作業ディレクトリにPythonのコード、Dockerイメージを作成するための
各種ファイルを準備します。結構あります。。

今回、Oracle functions、Dockerfileをさわってみてのイメージ(自分の理解）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/0cc3172b-574d-8b83-e2d7-9a50855ed1ae.png)


##５－１．「チーム一覧ページ」functions [f1_teamlist]の作業ディレクトリを作成

<details><summary>「チーム一覧ページ」functions [f1_teamlist]作業ディレクトリを作成する詳細手順はこちら</summary><div>
Oracle functions [f1_teamlist]の作業ディレクトリを作成



```shell:cloudshellで入力
fn init --runtime python f1_teamlist
```

作成されるのは、func.py、func.yaml、requirements.txt
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/932bc2d8-0fe6-1be3-1e03-d88152b27dbd.png)
　
</div></details>

##５－２．Oracle Instantclientのメディア、Autonomous Database walletを配置
<details><summary>Oracle Instantclientのメディア、Autonomous Database walletを配置する詳細手順はこちら</summary><div>
Oracle InstantClientは[ダウンロード](https://www.oracle.com/jp/database/technologies/instant-client/linux-x86-64-downloads.html)、
Autonomos DatabaseのwalletはAutonomos Database作成時にダウンロードしたものを
cloud shell のホームディレクトリにドラッグ&ドロップすることでコピーできます。
※「１－２．Autonomous Database の wallet を取得」でwalletはダウンロードしています

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/8ea3b484-f7fb-3b29-98d2-fa8c01d04448.png" width=450 />

lsコマンドで各.zipがあることを確認
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/137d826a-0c37-19fc-3b2b-680872e54cca.png" width=400 />


Oracle Instantclientの.zipを media フォルダにコピー、
walletファイルを dbwalletフォルダに解凍して格納

```shell:cloudshellで入力
cd
mkdir f1_teamlist/media
cp instantclient-basiclite-linux.x64-19.14.0.0.0dbru.zip f1_teamlist/media
unzip  Wallet_SERVERLESS.zip -d f1_teamlist/dbwallet
```

</div></details>

##５－３．Pythonのメイン処理「func.py」を作成

<details><summary>Pythonのメイン処理「func.py」を作成する詳細手順はこちら</summary><div>

```python:func.py
import io
import os
from fdk import response
import cx_Oracle


def handler(ctx, data: io.BytesIO=None):
    try:
        #DB接続情報設定
        username = "SCOTT"
        password = "WElcome12345"
        db_url = "serverless_medium"

        #DB接続、データ取得
        con = cx_Oracle.connect(username, password, db_url)
        cur = con.cursor()
        cur.execute('Select * from team')
        rows = cur.fetchall()

        strdata=""
        for r in rows:
            strdata = strdata + "<tr><td><a href='https://iba2rxxxxxx.apigateway.ap-tokyo-1.oci.customer-oci.com/f1detail/v1?teamid=" + str(r[0]) + "'>" + str(r[1]) + "</a></td></tr>"

        #HTML作成
        html = ""\
            "<html lang='ja'>"\
            "<head><title>F1 Team</title></head>"\
            "<meta charset='utf-8'>"\
            "<body>"\
            "<font size='5'><b>F1チーム一覧</b> </font>"\
            "<table border='1'  style='border-collapse: collapse'>"\
            " %s "\
            "</table>"\
            "</body>"\
            "</html>"
        resp = html % (strdata)
    except Exception as e:
        print('ERROR: Missing configuration keys, secret ocid and secret_type', e, flush=True)
    return response.Response(
        ctx,
        response_data=resp,
        headers={"Content-Type": "text/html"}
    )

```

</div></details>

##５－４．requirements.txtに cx_Oracle を追加
<details><summary>requirements.txtに cx_Oracle を追加する詳細手順はこちら</summary><div>
Python で Oracleに接続する際に必要なモジュールです。
（[過去の記事](https://qiita.com/kngsym2018/items/04514d623248a070adee)に詳しいことを書いています）

requirements.txtに cx_Oracle を追加

```requirements.txt
fdk
cx_Oracle
```
</div></details>

##５－５．Dockerfile を新規追加

<details><summary>Dockerfile を新規追加する詳細手順はこちら</summary><div>
Dockerイメージを作成する手順を記載。

```Dockerfile

FROM oraclelinux:7-slim
WORKDIR /function
RUN groupadd --gid 1000 fn && adduser --uid 1000 --gid fn fn

RUN yum -y install python3 oracle-release-el7 && \
    yum install -y unzip && \
    yum install -y libaio-devel && \
    rm -rf /var/cache/yum


ENV ORACLE_HOME=/function/instantclient_19_14
ENV LD_LIBRARY_PATH=/function/instantclient_19_14/lib:$LD_LIBRARY_PATH
ENV PATH=/function/instantclient_19_14:$PATH


ADD media/instantclient-basiclite-linux.x64-19.14.0.0.0dbru.zip  /function/media/instantclient-basiclite-linux.x64-19.14.0.0.0dbru.zip
RUN unzip /function/media/instantclient-basiclite-linux.x64-19.14.0.0.0dbru.zip -d /function/tmp && \
    mkdir /function/instantclient_19_14 && \
    mv /function/tmp/instantclient_19_14 /function/instantclient_19_14/lib


COPY dbwallet/* /function/instantclient_19_14/network/admin/

RUN rm -f  /function/media/instantclient-basiclite-linux.x64-19.14.0.0.0dbru.zip


ADD . /function/

RUN pip3 install --upgrade pip
RUN pip3 install --no-cache --no-cache-dir -r requirements.txt
RUN rm -fr /function/.pip_cache ~/.cache/pip requirements.txt func.yaml Dockerfile README.md

ENV PYTHONPATH=/python
ENTRYPOINT ["/usr/local/bin/fdk", "/function/func.py", "handler"]

```

</div></details>

##５－６．「チーム一覧ページ」Oracle Functions [f1_teamlist]をデプロイ

<details><summary>「チーム一覧ページ」Oracle Functions [f1_teamlist]をデプロイする詳細手順はこちら</summary><div>
f1_teamlistフォルダに移動してデプロイを実行

```shell:cloudshellで入力
cd
cd f1_teamlist
fn -v deploy --app fn-f1site
```

「Successfully created function」 で正常にデプロイ完了。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/6cd5897e-7fe5-26cc-9822-0689f341cf6f.png)

</div></details>

#６．API Gatewayの作成
API Gatewayを使う事でUserからアクセスするエンドポイントを１つにまとめるメリットがあります。
(今回はOracle Functionsは２つしかありませんが、サイトのページが増える事を見越して設定します)

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/486110e5-9fc0-f9f5-81da-515a6b59cba1.png" width=500 />

##６－１．API GatewayからOracle Functions[f1_teamlist]を実行できる設定を行う

<details><summary>API GatewayからOracle Functions[f1_teamlist]を実行できるよう設定する詳細手順はこちら</summary><div>
[開発者サービス]-[ゲートウェイ]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/4dc9c1a3-2d94-c83b-93fb-9086b52c9ad8.png" width=300 />
コンパートメントを確認、[ゲートウェイの作成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/751f4485-cff0-c59f-8f5a-d87ed1436870.png" width=300 />

「名前」：任意、「タイプ」：パブリック、「コンパートメント」：使用コンパートメント、
「VCN」は、作成したVCN、「サブネット」はパブリックサブネットを選択して、
[ゲートウェイの作成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/84176888-17e8-050f-7320-3ee5ad53267f.png" width=300 />
[デプロイメントの作成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/38a58d91-a4fa-199f-1790-49fbc7f2eb45.png" width=300 />

「名前」：任意、「パス接頭辞」:/teamlist (今回は/teamlist)、コンパートメント:使用コンパートメント
を設定したら、[次]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/55c5d2b5-210e-f450-932b-3ce7b45bbfd1.png" width=450 />
「パス」：/v1 (今回は/v1)、「メソッド」:GET、「タイプ」：Oracle Functions、
「アプリケーション」：fn-f1site(『４－２．アプリケーションの作成』で作ったもの)、
「機能名」：f1_teamlist(『５．Oracle Functions 「チーム一覧ページ」作成』で作ったもの)を
設定して、[次]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/ca571315-6f55-e6c0-3f29-18b4b436f112.png" width=450 />
[作成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/23ed7663-9cd2-e486-8bbd-15b71e1b7969.png" width=300 />

デプロイメントが作成されたことを確認
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/e5447803-92ab-0b57-9214-f9e6246e6820.png" width=300 />

</div></details>

##６－２．API GatewayがOracle Functionsを使用できるように、動的グループ、ポリシーを作成

<details><summary>動的グループ、ポリシーを作成する詳細手順はこちら</summary><div>
イメージとして、API Gatewayを動的グループに登録。
その動的グループにOracle Functionsを使用できる権限付与をします。

まずは、動的グループ設定をします。
[アイデンティティとセキュリティ]-[動的グループ]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/67057f3d-e4b2-1b9e-c55c-89e1b2b073e3.png" width=300 />

[動的グループの作成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/c7e99213-111e-802b-e364-e10731ff9277.png" width=300 />

「名前」：任意、「説明」：任意、
「ルール」：使用コンパートメントのAPI Gatewayと指定 ※記載は下記に記載
[作成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/b6eb51d9-84f0-d856-66eb-b056140b8761.png" width=600 />

```
ALL {resource.type = 'ApiGateway', resource.compartment.id = '<functionsがあるコンパートメントのOCID>'}
```

次はポリシーの作成

[ポリシーの作成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/e5095a59-c8f6-17b0-a144-1f0118ebe0fd.png" width=300 />

「名前」：任意、「説明」：任意、「コンパートメント」：使用コンパートメント、
ポリシービルダでは、動的グループがコンパートメント内のファンクションを使用できると記載
 ※記載は下記に記載
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/c059eca2-17a3-ed6e-57a9-1ff3c73c4da5.png" width=300 />

```
Allow dynamic-group <動的グループ> to use functions-family in compartment <コンパートメント>
```

</div></details>

##６－３．API Gatewayのエンドポイントからアクセス

<details><summary>API Gatewayのエンドポイントからアクセスする詳細手順はこちら</summary><div>
API Gatewayの設定がおわったので、エンドポイントからアクセスします。

「デプロイメント」の「エンドポイント」の[コピー]をクリックします
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/3876361d-2413-d2dc-5100-700fe6aa71bf.png" width=600 />

URLにアクセス(API Gatewayで設定したパスをつける)
※注意点は、パスを付けないといけません。パスは以下で設定しています。
　『６－１．API GatewayからOracle Functions[f1_teamlist]を実行できる設定を行う』参照

```
 https://ibxxx.apigateway.ap-tokyo-1.oci.customer-oci.com/teamlist/<API Gatewayで設定したパスを設定>
```

API Gatewayのエンドポイントからアクセス。画面が表示されることを確認。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/66b0d20d-d753-84c0-521a-bb555e18d94c.png)

</div></details>

#７．Oracle Functions 「チーム詳細ページ」作成

チーム詳細ページをOracle Functionsで作成します。
あわせてAPI Gatewayに作成するOracle Functionsを登録します。
※基本的な流れは、『５．Oracle Functions 「チーム一覧ページ」作成
』と同じです

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/8bbca03b-20fe-49c3-4f29-47f5f82d3707.png" width=500 />


Oracle Functions 「チーム詳細ページ」でも、作業ディレクトリに各種ファイルを作成していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/0cc3172b-574d-8b83-e2d7-9a50855ed1ae.png)


##７－１．「チーム詳細ページ」functions [f1_teamdetail]の作業ディレクトリを作成

<details><summary>「チーム詳細ページ」functions [f1_teamdetail]の作業ディレクトリを作成する詳細手順はこちら</summary><div>
Oracle functions [f1_teamlist]の作業ディレクトリを作成

```shell:CloudShellで実行
fn init --runtime python f1_teamdetail
```

「f1_teamdetail」フォルダが作成される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/31174c0f-84b9-3a04-ac05-2c1c62059533.png)

</div></details>

##７－２．Oracle Instantclientのメディア、Autonomous Database walletを配置

<details><summary>Oracle Instantclientのメディア、Autonomous Database walletを配置する詳細手順はこちら</summary><div>
『５－２．Oracle Instantclientのメディア、Autonomous Database walletを配置』で
Oracle Instantclientのメディア、Autonomous Database walletは、
Cloud Shellのホームディレクトリにあるので、ここでは、作業フォルダにコピーします。

Oracle Instantclientの.zipを media フォルダにコピー、
walletファイルを dbwalletフォルダに解凍して格納

```shell:cloudshellで入力
cd
mkdir f1_teamdetail/media
cp instantclient-basiclite-linux.x64-19.14.0.0.0dbru.zip f1_teamdetail/media
unzip  Wallet_SERVERLESS.zip -d f1_teamdetail/dbwallet
```

</div></details>

##７－３．Pythonのメイン処理「func.py」を作成
<details><summary>Pythonのメイン処理「func.py」を作成する詳細手順はこちら</summary><div>

```python:func.py
import io
import os
from fdk import response
import cx_Oracle
import logging


def handler(ctx, data: io.BytesIO=None):
    try:
        #GETでteamidを連携。Teamidを取得
        #getvalue = "teamid=3"
        getvalue = str(ctx.RequestURL())
        pos = getvalue.find("teamid")
        teamid = getvalue[pos+7:]
        #logging.getLogger().info("function start")

        #DB接続
        username = "SCOTT"
        password = "WElcome12345"
        db_url = "serverless_medium"

        #チーム名、画像URLを取得
        sql="select * from team where team_id=" + str(teamid)
        con = cx_Oracle.connect(username, password, db_url)
        cur = con.cursor()
        cur.execute(sql)
        rows = cur.fetchall()

        strteam =""
        strimg=""
        strdriver=""
        resp=""

        #Teamテーブルから情報取得
        for r in rows:
            strteam = str(r[1])
            strimg = "<img src='" + str(r[2])  + "' height='250' width='350' >"

        #F1ドライバ情報取得
        sql="select driver_name from f1driver  where team_id=" + str(teamid) + " order by driver_no "
        cur.execute(sql)
        rows = cur.fetchall()

        for r in rows:
            strdriver = strdriver + "<tr><td>" + str(r[0]) + "</td></tr>"

        #HTML作成
        html = ""\
            "<html lang='ja'>"\
            "<head><title>F1 Team Deatail</title></head>"\
            "<meta charset='utf-8'>"\
            "<body>"\
            "<font size='5'><B>"\
            " %s "\
            "</B></FONT>"\
            "<p>"\
            " %s "\
            "</p>"\
            "<table border='1'  style='border-collapse: collapse'>"\
            "<tr ><th  width='346'>ドライバー</th> </tr>"\
            " %s "\
            "</table>"\
            "<br><button type='button' onclick=\"location.href='https://iba2rxxxxx.apigateway.ap-tokyo-1.oci.customer-oci.com/teamlist/v1'\">戻る</button>"\
            "</body>"\
            "</html>"

        resp = html % (strteam,strimg,strdriver)

    except Exception as e:
        print('ERROR: Missing configuration keys, secret ocid and secret_type', e, flush=True)
    return response.Response(
        ctx,
        response_data=resp,
        headers={"Content-Type": "text/html"}
    )

```

</div></details>

##７－４．requirements.txtに cx_Oracle を追加

<details><summary>requirements.txtに cx_Oracle を追加する詳細手順はこちら</summary><div>

```text:requirements.txt
fdk
cx_Oracle
```

</div></details>

##７－５．Dockerfile を新規追加

<details><summary>Dockerfile を新規追加する詳細手順はこちら</summary><div>

```Dockerfile
FROM oraclelinux:7-slim
WORKDIR /function
RUN groupadd --gid 1000 fn && adduser --uid 1000 --gid fn fn

RUN yum -y install python3 oracle-release-el7 && \
    yum install -y unzip && \
    yum install -y libaio-devel && \
    rm -rf /var/cache/yum


ENV ORACLE_HOME=/function/instantclient_19_14
ENV LD_LIBRARY_PATH=/function/instantclient_19_14/lib:$LD_LIBRARY_PATH
ENV PATH=/function/instantclient_19_14:$PATH


ADD media/instantclient-basiclite-linux.x64-19.14.0.0.0dbru.zip  /function/media/instantclient-basiclite-linux.x64-19.14.0.0.0dbru.zip
RUN unzip /function/media/instantclient-basiclite-linux.x64-19.14.0.0.0dbru.zip -d /function/tmp && \
    mkdir /function/instantclient_19_14 && \
    mv /function/tmp/instantclient_19_14 /function/instantclient_19_14/lib


COPY dbwallet/* /function/instantclient_19_14/network/admin/

RUN rm -f  /function/media/instantclient-basiclite-linux.x64-19.14.0.0.0dbru.zip


ADD . /function/

RUN pip3 install --upgrade pip
RUN pip3 install --no-cache --no-cache-dir -r requirements.txt
RUN rm -fr /function/.pip_cache ~/.cache/pip requirements.txt func.yaml Dockerfile README.md

ENV PYTHONPATH=/python
ENTRYPOINT ["/usr/local/bin/fdk", "/function/func.py", "handler"]
```

</div></details>

##７－６．「チーム詳細ページ」Oracle Functions [f1_teamdetail]をデプロイ

<details><summary>「チーム詳細ページ」Oracle Functions [f1_teamdetail]をデプロイする詳細手順はこちら</summary><div>
f1_teamdetailフォルダに移動してデプロイを実行

```shell:CloudShellで実行
cd
cd f1_teamdetail
fn -v deploy --app fn-f1site
```

「Successfully created function」 で正常にデプロイ完了。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/aa497b82-6a92-b407-b81f-364d58fc1174.png)

</div></details>

##７－７．API Gateway に Oracle Functions [f1_teamdetail]を設定

<details><summary>API Gateway に Oracle Functions [f1_teamdetail]を設定する詳細手順はこちら</summary><div>
API GatewayからOracle Functions [f1_teamdetail]が実行できるように設定します。

[開発者サービス]-[ゲートウェイ]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/4dc9c1a3-2d94-c83b-93fb-9086b52c9ad8.png" width=300 />

『６－１．API GatewayからOracle Functions[f1_teamlist]を実行できる設定を行う』で
作成した、API Gateway をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/acd5dc64-7276-361e-3650-f1106908cdc3.png" width=450 />

[デプロイメントの作成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/55b8bf92-b790-cf7a-b3da-5925a7e9e57b.png" width=300 />

「名前」：任意、「パス接頭辞」：/f1detail(今回は/f1detail) 、
「コンパートメント：使用コンパートメントを入力して、[次]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/27e615a8-6a4c-5b55-fa33-90dce2b7b721.png" width=400 />

「パス」：/v1 (今回は/v1)、「メソッド」:GET、「タイプ」：Oracle Functions、
「アプリケーション」：fn-f1site(『４－２．アプリケーションの作成』で作ったもの)、
「機能名」：f1_teamdetailを設定して、[次]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/539ae9da-3dcb-f3e7-035f-88775a0a86f2.png" width=400 />

[作成]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/8a9ce4fb-c7b4-d098-b1a4-567194c343fc.png" width=300 />

作成した「f1detail」のエンドポイントの[コピー]をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/89b73496-7bd5-3b22-9e6f-5cc20ebd22c1.png" width=600 />

URLにアクセス(API Gatewayで設定したパスをつける)
※注意点は、パスを付けないといけません。パスは今回は「v1」で設定しています。
※「チーム詳細ページ」では、「チーム一覧ページ」で選択したTeamidを引数にしていますので
   ?teamidをつけています

```
https://iba2xxxxx.apigateway.ap-tokyo-1.oci.customer-oci.com/f1detail/v1?teamid=2
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/0420fffc-0620-24a1-1a79-bf903cbe0782.png)

</div></details>

#８．「チーム一覧ページ」の「チーム詳細ページ」動作確認

「チーム一覧ページ」を開いて、選択したチームの詳細が表示されるかを確認

```
 https://ibxxx.apigateway.ap-tokyo-1.oci.customer-oci.com/teamlist/v1
```

|<img width="300" alt="take3.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261475/75e0cff8-70ae-762d-84b4-5d1d149160f7.gif">|
|:-:|

#最後に
Oracle Functionsを使用してWebサイト(動的）を作ることができました。
今回はDBのデータを参照するのみでしたが、
DB接続ができたのでデータ更新するページも作成できるはずです。



※2022年はRed Bullは、
　「ORACLE Red Bull Racing（オラクル・レッドブル・レーシング）」として参戦です。

https://f1-gate.com/redbull/f1_67144.html

#参考URL
https://blogs.oracle.com/cloud-infrastructure/post/the-power-of-oracle-functions-using-python-connecting-to-an-autonomous-transacting-processing-database-with-a-wallet-stored-as-secrets

https://oracle-japan.github.io/ocitutorials/cloud-native/functions-for-beginners/

https://oracle-japan.github.io/ocitutorials/cloud-native/functions-apigateway-for-beginners/

https://oracle-japan.github.io/ocitutorials/cloud-native/apigateway-for-beginners/


https://oracle-japan.github.io/ocitutorials/database/adb104-connect-using-wallet/