本投稿の背景
フットサル大会の運用をシステム化( こちらの記事 )したのですが、
2020年3月からコロナの影響でフットサルの大会は実施されていません。。
この状況で以下を考えました。
・コロナで大会が中止。システム運用している仮想マシンは24時間 x 365日稼働する必要なし
・大会結果を参照したい人がいれば、そのタイミングで参照できればよい
・内容はチーム順位、得点者を表示するシンプルなものなので、Wordpressでなくてもよい
それを解決するのが、「サーバレス」と思ったので、
実験的にOCIでサーバレス「Oracle Functions」でWeb動的サイトを作ってみました。
※息子たちがF1マシンの絵をかいていたので、
それを使ったWebサイトを作ろうと思ったのも理由です。
構成図
・DBは Autonomous Databaseを使用 ※無料枠の[Always free]
・Oracle Functionsでは(「チーム一覧ページ」、「チーム詳細ページ」)を作成
※いずれのページもDBに接続してデータからページ内容を作成しています
(静的ページ表示ではありません)
※詳細表示ページではオブジェクトストレージに格納した画像を参照しています
・API Gatewayでユーザから接続するエンドポイントをまとめる
実際につくってみたWebサイト
サーバレス(Oracle Functions)でWebサイトを構築する流れ
以下の手順で構築します
1.Autonomous Databaseを作成
2.画像ファイルをオブジェクトストレージに格納
3.ネットワークの作成
4.Oracle Functions を使う前の準備
5.Oracle Functions 「チーム一覧ページ」作成
6.API Gatewayの作成
7.Oracle Functions 「チーム詳細ページ」作成
8.「チーム一覧ページ」の「チーム詳細ページ」動作確認
※構築の事前準備として
コンパートメント「serverless」を作成しており、Oracle Functions等はコンパートメント「serverless」に作成します。
※設定手順などの詳細は、折りたたんでいるので、確認は ▶ をクリックください
1.Autonomous Databaseを作成
Autonomous Databaseに2つのテーブルを作成します。
「チーム一覧ページ」、「チーム詳細ページ」で使用するテーブル・データとなります。
1-1.Autonomous Databaseを作成
[Oracle Database] - [Autonomous Database]を選択 「コンパートメント」を確認して、[Autonomous Databaseの作成]をクリック 「コンパートメント」、「表示名」、「データベース名」を設定。Autonomous Databaseを作成する詳細手順はこちら
作成するWebサイトは、DBに格納しているデータを使用してWebページを作成します。
Always free(無料)でDBを作成します。
「ワークロード・タイプ」は[データウェアハウス]、「デプロイメント・タイプ」は[共有インフラストラクチャ」を選択
1-2.Autonomous Database の wallet を取得
Autonomous Databaseには暗号化およびSSL相互認証を利用した接続が前提としており、そのため接続する際はクレデンシャル・ウォレット(Credential.zipファイル)を利用する必要がありますAutonomous Database の wallet を取得する詳細手順はこちら
Autonomous Database にDB接続する際、walletが必要になりますので取得します。
※Oracle Functions でもwalletを使用します
https://oracle-japan.github.io/ocitutorials/database/adb104-connect-using-wallet/
1-3.DBスキーマ、テーブル作成
[データベース・アクション]をクリック ユーザ情報とWebアクセスを有効、表領域を割り当て、[ユーザの作成]をクリック コンソール画面右上をみると、ADMINでログインになっているので、[サインアウト]をクリック 作成したユーザ名、パスワードを入力して[サインイン]をクリック [ワークシート]にSQLを入力して、[実行(赤枠)]をクリックしてSQLを実行 あとは、データを登録。DBスキーマ、テーブル作成する詳細手順はこちら
Webサイトで使用するDBスキーマ、テーブルを作成します。
[ユーザの作成]をクリック
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 )
) ;
2.画像ファイルをオブジェクトストレージに格納
「チーム詳細ページ」で表示する画像をオブジェクトストレージに格納します。
バケットを作成して、画像ファイルをアップロードして、可視性の設定をします。
2-1.オブジェクト・ストレージの設定
3.ネットワークの作成
Oracle Functions、API Gatewayを配置するネットワークを作成します。
※VCNウィザードでネットワークを作成します
3-1.VCNウィザードを実行
3-2.ネットワークセキュリティ設定
4.Oracle Functions を使う前の準備
Oracle Functionsを使う前準備をします。
ここではCloud shellを使用してOracle Functionsをデプロイする設定とOracle Functionsを登録するアプリケーションの設定を行います。
事前準備の詳細は以下のページを参照ください(わかりやすく解説されています)
https://oracle-japan.github.io/ocitutorials/cloud-native/functions-for-beginners/
4-1.Cloud shellを設定
ユーザ設定の認証トークンを取得します。 [認証トークン]-[トークンの生成]をクリック Oracle FunctionsをデプロイするためのにOracle Functions CLIを利用して環境を作成します。 リージョンを設定します。東京リージョンの場合はap-tokyo-1 テナンシーのOCIDを設定 レジストリ名を登録します レジストリにログインCloud shellを設定する詳細手順はこちら
コンソール画面の右上の Cloud Shellをクリック
※Oracle Functions管理するOracle提供のプライベートDockerレジストリのログインに必要
コンソール画面の人のアイコンをクリックして、[ユーザ設定]をクリック
[説明]を入れて、[トークンの生成]をクリック
「生成されたトークン」の[コピー]をクリック
※この情報を控えておきます。あとで必要になります。
コンソール画面の人のアイコンをクリックして、[テナンシ]をクリック
「テナンシ情報」のOCIDの[コピー]をクリック
※この情報を控えておきます。あとで必要になります。
開発環境の設定は、fn updateコマンドを使用して行います。
>https://oracle-japan.github.io/ocitutorials/cloud-native/functions-for-beginners/
※cloud Shellで以下のコマンドを入力していきます。fn use context ap-tokyo-1
fn update context oracle.compartment-id ocid1.tenancy.oc1..aaaaaaa<省略>
※Oracle Functionsを管理するOracle提供のプライベートDockerレジストリfn update context registry iad.ocir.io/xxxxx/functions-serverless
fn update context registry iad.ocir.io/<オブジェクト・ストレージ・ネームスペース>/<任意の名前>
パスワードは「トークンの生成」で作成したものを入力 docker login nrt.ocir.io
4-2.アプリケーションの作成
アプリケーションを作成する詳細手順はこちら
5.Oracle Functions 「チーム一覧ページ」作成
ここからは、Oracle Functions を作成します。
ここで実施する作業は、
作業ディレクトリにPythonのコード、Dockerイメージを作成するための
各種ファイルを準備します。結構あります。。
今回、Oracle functions、Dockerfileをさわってみてのイメージ(自分の理解)
5-1.「チーム一覧ページ」functions [f1_teamlist]の作業ディレクトリを作成
5-2.Oracle Instantclientのメディア、Autonomous Database walletを配置
Oracle Instantclientの.zipを media フォルダにコピー、Oracle Instantclientのメディア、Autonomous Database walletを配置する詳細手順はこちら
Oracle InstantClientはダウンロード、
Autonomos DatabaseのwalletはAutonomos Database作成時にダウンロードしたものを
cloud shell のホームディレクトリにドラッグ&ドロップすることでコピーできます。
※「1-2.Autonomous Database の wallet を取得」でwalletはダウンロードしています
walletファイルを dbwalletフォルダに解凍して格納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
5-3.Pythonのメイン処理「func.py」を作成
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"}
)
5-4.requirements.txtに cx_Oracle を追加
requirements.txtに cx_Oracle を追加requirements.txtに cx_Oracle を追加する詳細手順はこちら
Python で Oracleに接続する際に必要なモジュールです。
(過去の記事に詳しいことを書いています)
fdk
cx_Oracle
5-5.Dockerfile を新規追加
Dockerfile を新規追加する詳細手順はこちら
Dockerイメージを作成する手順を記載。
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"]
5-6.「チーム一覧ページ」Oracle Functions [f1_teamlist]をデプロイ
6.API Gatewayの作成
API Gatewayを使う事でUserからアクセスするエンドポイントを1つにまとめるメリットがあります。
(今回はOracle Functionsは2つしかありませんが、サイトのページが増える事を見越して設定します)
6-1.API GatewayからOracle Functions[f1_teamlist]を実行できる設定を行う
「名前」:任意、「タイプ」:パブリック、「コンパートメント」:使用コンパートメント、 「名前」:任意、「パス接頭辞」:/teamlist (今回は/teamlist)、コンパートメント:使用コンパートメントAPI GatewayからOracle Functions[f1_teamlist]を実行できるよう設定する詳細手順はこちら
[開発者サービス]-[ゲートウェイ]をクリック
コンパートメントを確認、[ゲートウェイの作成]をクリック
「VCN」は、作成したVCN、「サブネット」はパブリックサブネットを選択して、
[ゲートウェイの作成]をクリック
[デプロイメントの作成]をクリック
を設定したら、[次]をクリック
「パス」:/v1 (今回は/v1)、「メソッド」:GET、「タイプ」:Oracle Functions、
「アプリケーション」:fn-f1site(『4-2.アプリケーションの作成』で作ったもの)、
「機能名」:f1_teamlist(『5.Oracle Functions 「チーム一覧ページ」作成』で作ったもの)を
設定して、[次]をクリック
[作成]をクリック
6-2.API GatewayがOracle Functionsを使用できるように、動的グループ、ポリシーを作成
まずは、動的グループ設定をします。 「名前」:任意、「説明」:任意、 次はポリシーの作成 「名前」:任意、「説明」:任意、「コンパートメント」:使用コンパートメント、動的グループ、ポリシーを作成する詳細手順はこちら
イメージとして、API Gatewayを動的グループに登録。
その動的グループにOracle Functionsを使用できる権限付与をします。
[アイデンティティとセキュリティ]-[動的グループ]をクリック
「ルール」:使用コンパートメントのAPI Gatewayと指定 ※記載は下記に記載
[作成]をクリック
ALL {resource.type = 'ApiGateway', resource.compartment.id = '<functionsがあるコンパートメントのOCID>'}
ポリシービルダでは、動的グループがコンパートメント内のファンクションを使用できると記載
※記載は下記に記載
Allow dynamic-group <動的グループ> to use functions-family in compartment <コンパートメント>
6-3.API Gatewayのエンドポイントからアクセス
「デプロイメント」の「エンドポイント」の[コピー]をクリックします URLにアクセス(API Gatewayで設定したパスをつける) API Gatewayのエンドポイントからアクセス。画面が表示されることを確認。API Gatewayのエンドポイントからアクセスする詳細手順はこちら
API Gatewayの設定がおわったので、エンドポイントからアクセスします。
※注意点は、パスを付けないといけません。パスは以下で設定しています。
『6-1.API GatewayからOracle Functions[f1_teamlist]を実行できる設定を行う』参照 https://ibxxx.apigateway.ap-tokyo-1.oci.customer-oci.com/teamlist/<API Gatewayで設定したパスを設定>
7.Oracle Functions 「チーム詳細ページ」作成
チーム詳細ページをOracle Functionsで作成します。
あわせてAPI Gatewayに作成するOracle Functionsを登録します。
※基本的な流れは、『5.Oracle Functions 「チーム一覧ページ」作成
』と同じです
Oracle Functions 「チーム詳細ページ」でも、作業ディレクトリに各種ファイルを作成していきます。
7-1.「チーム詳細ページ」functions [f1_teamdetail]の作業ディレクトリを作成
7-2.Oracle Instantclientのメディア、Autonomous Database walletを配置
Oracle Instantclientの.zipを media フォルダにコピー、Oracle Instantclientのメディア、Autonomous Database walletを配置する詳細手順はこちら
『5-2.Oracle Instantclientのメディア、Autonomous Database walletを配置』で
Oracle Instantclientのメディア、Autonomous Database walletは、
Cloud Shellのホームディレクトリにあるので、ここでは、作業フォルダにコピーします。
walletファイルを dbwalletフォルダに解凍して格納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
7-3.Pythonのメイン処理「func.py」を作成
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"}
)
7-4.requirements.txtに cx_Oracle を追加
requirements.txtに cx_Oracle を追加する詳細手順はこちら
fdk
cx_Oracle
7-5.Dockerfile を新規追加
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"]
7-6.「チーム詳細ページ」Oracle Functions [f1_teamdetail]をデプロイ
7-7.API Gateway に Oracle Functions [f1_teamdetail]を設定
『6-1.API GatewayからOracle Functions[f1_teamlist]を実行できる設定を行う』で 「名前」:任意、「パス接頭辞」:/f1detail(今回は/f1detail) 、 「パス」:/v1 (今回は/v1)、「メソッド」:GET、「タイプ」:Oracle Functions、 作成した「f1detail」のエンドポイントの[コピー]をクリック URLにアクセス(API Gatewayで設定したパスをつける)API Gateway に Oracle Functions [f1_teamdetail]を設定する詳細手順はこちら
API GatewayからOracle Functions [f1_teamdetail]が実行できるように設定します。
作成した、API Gateway をクリック
「コンパートメント:使用コンパートメントを入力して、[次]をクリック
「アプリケーション」:fn-f1site(『4-2.アプリケーションの作成』で作ったもの)、
「機能名」:f1_teamdetailを設定して、[次]をクリック
※注意点は、パスを付けないといけません。パスは今回は「v1」で設定しています。
※「チーム詳細ページ」では、「チーム一覧ページ」で選択したTeamidを引数にしていますので
?teamidをつけていますhttps://iba2xxxxx.apigateway.ap-tokyo-1.oci.customer-oci.com/f1detail/v1?teamid=2
8.「チーム一覧ページ」の「チーム詳細ページ」動作確認
「チーム一覧ページ」を開いて、選択したチームの詳細が表示されるかを確認
https://ibxxx.apigateway.ap-tokyo-1.oci.customer-oci.com/teamlist/v1
最後に
Oracle Functionsを使用してWebサイト(動的)を作ることができました。
今回はDBのデータを参照するのみでしたが、
DB接続ができたのでデータ更新するページも作成できるはずです。
※2022年はRed Bullは、
「ORACLE Red Bull Racing(オラクル・レッドブル・レーシング)」として参戦です。