■■■Oracle Cloudのウェビナーシリーズは→こちら■■■
Oracle Cloud Infrastructure(OCI)では、Architecture Centerのページで、リファレンスアーキテクチャーの紹介など、OCI上での実装に関するいろいろな情報が参照できます。
そこに、Autonomous Database (ADB) への自動データロードが掲載されていたので、やってみました。
- [Oracle Architecture Center]
(https://docs.oracle.com/en/solutions/index.html)
※そのうち、こちらにも日本語化されたものが出てくると思います。
[Oracleアーキテクチャ・センター]
(https://docs.oracle.com/ja/solutions/index.html?page=0&is=true&sort=0)
今回使用するOCIのサービス
- Oracle Functions
- Oracle Events
- Oracle Autonomous Database
- Oracle Object Storage
- Oracle Cloud Shell
- Oracle Cloud Infrastructure Registry (OCIR)
ユーザがObject Storageの特定のバケットにファイルをアップロードしたら、そのことを Events が検知して、そのEventsに紐付けられているFunctionsを呼び出します。Functionsではアップロードされたファイルを読み取りADBにデータをロードするようなプログラムを実装しておくことで、「Object Storageにファイルがアップロードされたら自動でADBへデータをロードする」ということが実現できます。
Functionsの登録などのコマンド操作は、Cloud Shellから実行できます。OCIRはFunctionsの実体であるDocker Imageの格納先(Oracle提供のプライベートDockerレジストリ)となります。
Autonomous Databaseへのデータロードは、REST用のSODAを利用します。ORDS(Oracle REST Data Services)にデプロイ済みのSODAを、ファンクション内で実行(REST APIをCall)しています。
SODA(Simple Oracle Document Access)はNoSQL形式のAPIセットであり、これを使用すると、Oracle Databaseのドキュメント(特にJSON)のコレクションを作成および格納でき、ドキュメントがどのようにデータベースに格納されているかを理解していなくても、そのコレクションの取得や問合せを行うことができます。
Oracle Functionsは、サーバレスプラットフォームであるFn Projectの、OCI上でのマネージドサービスです。イベント発生に応じてファンクションを都度起動し実行するような場面で利用されます。
Oracle Functions は、OCIチュートリアルの中で、詳しく紹介されています。
今回使用しなかったOCIのサービス
- Oracle Cloud Infrastructure Vault (OCI Vault、ボールト)
ここでは簡単のため、Autonomous Database接続のためのパスワード情報など、全てファンクションに対してカスタム構成パラメータとして設定しています。しかし、セキュリティの観点から、他の実装方法、例えば、Oracle Cloud Infrastructure Vault に格納する、などが望ましいです。OCI Vault(OCI シークレット)については、以下がわかりやすいです。
さらにいうと、本投稿と同じ内容で、かつ、Oracle Cloud Infrastructure Vault を使っての完全手順が以下で紹介されています。
え!本投稿の意味...とも思ったんですが、途中まで書いてから気づいたこともあり、このまま備忘録として残したいと思います。
やってみる
Automate loading data to a data warehouse using a serverless application を読んで、いざやり方は、
- Go to GitHub.
- Copy the code to your local computer.
- Follow the instructions in the README document.
とのことでGitHubに行き、以下、READMEに従って進めます。
事前準備(Prerequisites)
まずはOracle Functionsが実行できるよう、別のドキュメント[(Oracle Functions Quick Start Guide for Cloud Shell)]
(https://www.oracle.com/webfolder/technetwork/tutorials/infographics/oci_functions_cloudshell_quickview/functions_quickview_top/functions_quickview/index.html)を見てA~Cを済ませておくこと。
A - Set up your tenancy
B - Create application
C - Set up your Cloud Shell dev environment
以下、ユーザ名やグループ名など、名称は任意で。
A - Set up your tenancy
グループとユーザの作成
-
三 > アイデンティティ > グループ > グループの作成
- 名前:Oracle-Functions-Group ※任意
-
三 > アイデンティティ > ユーザ > ユーザの作成
- 名前:fnuser ※任意
-
ユーザ作成後にやること
- ユーザ(fnuser)を グループ(Oracle-Functions-Group)に追加
- ※ユーザの画面から左下 グループ より、「ユーザをグループに追加」
- ユーザ(fnuser)がログインできるよう、パスワードを発行
- ※ユーザの画面上部「パスワードの作成/リセット」で、ワンタイムパスワードを発行し、パスワードを保存しておく
コンパートメントの作成
- 三 > アイデンティティ > コンパートメント > コンパートメントの作成
- 名前:mycomp ※任意
VCNとサブネットの作成
- 三 > ネットワーキング > 仮想クラウド・ネットワーク > VCNウィザードの起動
- 「インターネット接続性を持つVCN」をチェックし、VCNウィザードの起動
- VCN名:myvcn ※任意
- コンパートメント:mycomp ※上で作成したコンパートメント名を指定
あとはデフォルトのまま次へ次へ、下図右側にあるような、パブリックサブネットとプライベートサブネットと外部へのそれぞれ適切なGatewayを持つVCNが作成される。
Oracle Functionsが実行できるようなポリシーを作成(グループに適用)
ポリシーとは、権限の塊(1つ以上の権限(ポリシー・ステートメント))のようなもの。Oracle Functionsが実行できるような権限を付与したいが、OCIでは権限付与はユーザ個別ではなく必ずグループを経由して付与するので、冒頭で作成したユーザ fnuser が所属するOracle-Functions-Groupに対し、いくつかのリソースの使用権限を付与する。
- 三 > アイデンティティ > ポリシー
- ※左側:リスト範囲 コンパートメント:「XXXXX(ルート)」(=ルートコンパートメント)を選択
- 「ポリシーを作成」を押下
- ポリシー名:Oracle-Functions-Policy ※任意
- コンパートメント:ルートを選択
- 以下の8つのポリシー・ステートメントを入力し、「作成」
- Allow service FaaS to read repos in tenancy
- Allow service FaaS to use virtual-network-family in tenancy
- Allow group Oracle-Functions-Group to manage repos in tenancy
- Allow group Oracle-Functions-Group to read metrics in tenancy
- Allow group Oracle-Functions-Group to read objectstorage-namespaces in tenancy
- Allow group Oracle-Functions-Group to use virtual-network-family in tenancy
- Allow group Oracle-Functions-Group to manage functions-family in tenancy
- Allow group Oracle-Functions-Group to use cloud-shell in tenancy
※簡単のため、allow ... in tenancy で、最上位であるテナンシー全体に対して有効なポリシー・ステートメントになっていますが、必要に応じて、特定のコンパートメントに絞るなど、要件に合わせて適宜修正する。
B - Create application
はじめての Oracle Functions アプリケーションを作成
- OCIコンソールをログアウトし、Aで作成したユーザでログインし直す
ログアウトすると下記画面になるので、右側のOCI IAMユーザログイン用の画面に入力し、ログイン(fnuser/ワンタイムパスワードを入力)
ワンタイムパスワードの場合は、ログイン後、新しいパスワードを求められるので入力する。
- 右上からリージョンを選択
- 左側の「リスト範囲」から、作成したコンパートメントを選択(ここではmycomp)
- 三 > 開発者サービス > ファンクション > アプリケーションの作成
- 名前:helloworld-app ※任意
- MYCOMPのVCN:myvcn ※作成したコンパートメント内にある作成したVCNを指定
- MYCOMPのサブネット:パブリック・サブネット を選択
- ※任意:ロギング・ポリシーを「オブジェクト・ストレージにログを記録」にすると、Functionの実行ログが保存されるのでデバッグなどにも使えます
あとはデフォルトのまま、一番下の「作成」を押下
C - Set up your Cloud Shell dev environment
Cloud Shell ウィンドゥを表示し、コマンドを順番に実行
- 作成した helloworld-app をクリックして詳細ページへ行く
- 左側「開始」を押下 > 中央「Cloud Shell設定」を選択
すると、①「Cloud Shellの起動」ボタンと、その下にこれから実行していくべきコマンドが②以降順番に表示されている。
「Cloud Shellの起動」を押下。ブラウザ下部にCloud Shellが起動するので、②から順番に、指定されたコマンドをコピペして実行していく。
コピペ実行時の注意点
- ④fn update context registry phx.ocir.io/axdxxxxxx/[YOUR-OCIR-REPO]
- [YOUR-OCIR-REPO] 部分は、任意の文字列(小文字)に変更する
- 今回は functions-test に変更
- ※OCIR(Oracle Functionsを管理するOracle提供のプライベートDockerレジストリ)の名前を指定している
- ⑤AuthTokenの生成 ※ここだけはGUI操作
- 「AuthTokenの生成」を押下し、別ウィンドゥで起動するOCIコンソール画面から行う
結局、私の環境で実行したコマンドは以下。
$ history
31 fn list context
32 fn use context us-phoenix-1
33 fn update context oracle.compartment-id ocid1.compartment.oc1..aaxxxxxxxxxxxx
34 fn update context registry phx.ocir.io/axdxxxxxx/functions-test
35 docker login -u 'axdxxxxxx/fnuser' phx.ocir.io
36 fn list apps
37 fn init --runtime java hello-java
38 cd hello-java
39 fn -v deploy --app helloworld-app
40 fn invoke helloworld-app hello-java
環境に合わせたOCIDなどがセットされてブラウザ上に表示されているようなので、[YOUR-OCIR-REPO]部分以外は、コピペで大丈夫だった。
(私の環境ではリージョンがPHOENIXなので、OCIR(Dockerレジストリ)等も、Phonixを指す。)
って、気づいたら、C - Set up your Cloud Shell dev environmentを全部やって、D. Create, deploy, and invoke your function の途中まで行ってました。上の実行例では、docker login まで が必須項目です。でも、サンプルファンクションの動作確認も出来るので、最後まで行ってしまってOKです。
最後まで実行すると、以下のように、hello-java ファンクションの実行結果が返ります。
$ fn invoke helloworld-app hello-java
Hello, world!
githubのREADMEに戻ります。
以降の作業は、OCIコンソールでログインするユーザを切り替えて実施する
- Functionの実装(fn コマンドで始まる一連の作業)は、冒頭Aで作成した OCI IAMユーザ
- それ以外(各種ポリシー設定やグループ、バケットの作成など)は、必要な権限を持つユーザ(今回はAdministoratorグループのメンバーで実施している)
Functionsアプリケーションをリスト
Cloud Shellからコマンドを実行。
事前準備で作成したhelloworld-app が登録されている。
$ fn list apps
NAME ID
helloworld-app ocid1.fnapp.oc1.phx.aaaaxxxxxxxxx
動的グループを作成(or Update)
- 三 > アイデンティティ > 動的グループ > 動的グループの作成
- 名前:Function-Group-Dynamic ※任意
- 説明:Function-Group-Dynamic ※任意
- ルール1:ALL {resource.type = 'fnfunc', resource.compartment.id = 'ocid1.compartment.oc1..aaaaaxxxxx'} ※mycompコンパートメントのOCIDを指定
Object Storageのバケットを2つ作成
- 三 > オブジェクト・ストレージ > オブジェクト・ストレージ > バケットの作成
- 以下の名前で、それぞれ、2つのバケットを作成する
- input-bucket ※こちらは「オブジェクト・イベントの出力」にチェックを付ける
- processed-bucket
input-bucket は、ユーザがCSVファイルを投入するバケット。処理終了後(=自動データロード終了後)、CSVファイルはもう片方の processed-bucket に移動するように、Functionを実装する。
IAMポリシーの作成(or Update)
作成した動的グループ名(Function-Group-Dynamic)、バケット名(input-bucket, processed-bucket)、 コンパートメント名(mycomp)に合わせて、以下のポリシーを動的グループに割当てる
- 三 > アイデンティティ > ポリシー
- ※左側:リスト範囲 コンパートメント が、「XXXXX(ルート)」(ルートコンパートメント)を選択
- 「ポリシーを作成」を押下
- ポリシー名:Function-Dynamic-Policy ※任意
- コンパートメント:ルートを選択
- 以下 2つのポリシー・ステートメントを入力し、「作成」
- Allow dynamic-group Function-Group-Dynamic to manage objects in compartment mycomp where target.bucket.name='input-bucket'
- Allow dynamic-group Function-Group-Dynamic to manage objects in compartment mycomp where target.bucket.name='processed-bucket'
- ※以下のポリシーも追加(us-phoenix-1部分は使用中のリージョンに合わせて変更する)
- Allow service objectstorage-us-phoenix-1 to manage object-family in compartment mycomp
Autonomous Database(ADB)を作成
※ここでは簡単のためAutonomous Databaseの管理者である admin で接続・データロードしていますが、一般ユーザで実行したい場合は、追加の手順で別のユーザとそれに準じたURLで実現できます(Autonomous Databaseのバージョンが 19c であれば、DWROLEを付与しSQL Developer Webを実行できるよう設定すればOKです。詳しくは Oracle Cloud Infrastructure の Autonomous Databaseで使える SQL Developer Web (ブラウザベース) の 追記 参照)。
ATPでもADWでもOK。ADB作成後、サービスコンソール > 開発 から、RESTのエンドポイントを確認する
「RESTfulサービスとSODA」にある、「URLのコピー」を押下してRESTのエンドポイントURLをコピー。
(Oracle REST Data Services (ORDS)は、Oracle Databaseのコンテンツを1つ以上のREST対応スキーマで操作するためのHTTPSインタフェースを提供します。ORDSで提供されるAutonomous Database用のリソースはすべて、共通ベースURLを持ちます)
任意の端末から(CloudShellでOK)、以下を実行する。
### <ADW-ORDS-URL> と <DB password>は、環境に合わせて変更する
## コピーしたURLの、最後の / は削除して指定
$ export ORDS_BASE_URL=<ADW-ORDS-URL>
## コレクション:regionsnumbers を作成 -- ①
$ curl -X PUT -u 'ADMIN:<DB password>' -H "Content-Type: application/json" $ORDS_BASE_URL/admin/soda/latest/regionsnumbers
## コレクションをリスト -- ②
$ curl -u 'ADMIN:<DB-password>' -H "Content-Type: application/json" $ORDS_BASE_URL/admin/soda/latest/
## データ投入後は、以下で コレクション:regionsnumbers の内容が検索できる -- ③
$ curl -X POST -u 'ADMIN:<DB-password>' -H "Content-Type: application/json" --data '{}' $ORDS_BASE_URL/admin/soda/latest/regionsnumbers?action=query
## コレクション:regionsnumbers のデータを削除 -- ④
$ curl -X POST -u 'ADMIN:<DB-password>' -H "Content-Type: application/json" $ORDS_BASE_URL/admin/soda/latest/regionsnumbers?action=truncate
Oracle Database から見ると、①でREGIONSNUMBERS表が作成され、③でSELECTしたり、④でTRUNCATEする。
①実行後、出来たテーブルの定義は以下。
SQL> desc regionsnumbers
Name Null? Type
------------- -------- -------------
ID NOT NULL VARCHAR2(255)
CREATED_ON NOT NULL TIMESTAMP(6)
LAST_MODIFIED NOT NULL TIMESTAMP(6)
VERSION NOT NULL VARCHAR2(255)
JSON_DOCUMENT BLOB
Functionsの中身を確認しカスタマイズ
OCIにfnuserでログイン、クラウドシェルを起動。
oci-adb-ords-runsql-python という名前のファンクションを作成していく。
fn init --runtime python oci-adb-ords-runsql-python
すると、oci-adb-ords-runsql-python/ ディレクトリとその下にboilerplate(サンプル)が作成される。ファイルは3つ(func.py, func.yaml, requirements.txt)。
$ fn init --runtime python oci-adb-ords-runsql-python
Creating function at: ./oci-adb-ords-runsql-python
Function boilerplate generated.
func.yaml created.
$ cd oci-adb-ords-runsql-python/
$ ls
func.py func.yaml requirements.txt
それぞれ、githubからローカルにダウンロードしたファイルの内容や処理を確認し、それぞれ上書きする。
- func.py - the code of the function ※処理内容
- requirements.txt - its dependencies
- func.yaml - the function metadata
(今回は func.py と requirements.txt を上書き。func.yaml は違いが version くらいだったのでそのまま利用)
※この部分の作業は、もちろんCloudShell上に直接ダウンロードして、cd でもOK。
$ git clone https://github.com/oracle/oracle-functions-samples
$ cd oci-adb-ords-runsql-python/
Funtionのデプロイ
事前準備で作成した helloworld-app アプリケーションに oci-adb-ords-runsql-python ファンクションをデプロイする。
$ fn -v deploy --app helloworld-app
Function実行時に使用する、カスタム構成パラメータをセット
※冒頭の「今回使用しなかったOCIのサービス」に記載したように、パスワードなども全てここに登録してしまっているので、本当は別の実装方法が望ましい。
$ fn config function helloworld-app oci-adb-ords-runsql-python ords-base-url "https://XXXXX-PUPPY.adb.us-phoenix-1.oraclecloudapps.com/ords"
helloworld-app oci-adb-ords-runsql-python updated ords-base-url with https://XXXXX-PUPPY.adb.us-phoenix-1.oraclecloudapps.com/ords
$ fn config function helloworld-app oci-adb-ords-runsql-python db-schema "admin"
helloworld-app oci-adb-ords-runsql-python updated db-schema with admin
$ fn config function helloworld-app oci-adb-ords-runsql-python db-user "admin"
helloworld-app oci-adb-ords-runsql-python updated db-user with admin
$ fn config function helloworld-app oci-adb-ords-runsql-python dbpwd-cipher "<adminのパスワード>"
helloworld-app oci-adb-ords-runsql-python updated dbpwd-cipher with XXXXXXXXXX
$ fn config function helloworld-app oci-adb-ords-runsql-python input-bucket "input-bucket"
helloworld-app oci-adb-ords-runsql-python updated input-bucket with input-bucket
$ fn config function helloworld-app oci-adb-ords-runsql-python processed-bucket "processed-bucket"
helloworld-app oci-adb-ords-runsql-python updated processed-bucket with processed-bucket
$
Eventsのルール作成
-
三 > アプリケーション統合 > イベント・サービス > ルールの作成
- 表示名:load_csv_to_ADB ※任意
- 説明:load_csv_to_ADB ※任意
-
ルール条件に3つ入力
- イベントタイプ, Object Storage, Object-Created
- 属性, compartmentName, mycomp
- 属性, bucketName, input-bucket
-
アクション:ファンクション, mycomp, helloworld-app, oci-adb-ords-runsql-python
※プルダウンメニューにも見えるUIだが、手動で任意の値を入力できる(一瞬焦る💦)
「ルールの作成」を押下。
Eventsのルール作成が完了した。
いざ実行
やることはただひとつで、input-bucket にCSVファイルを投入する。
あとは全自動で動くはずなので、投入後の状況を、Autonomous Databaseやバケット、Functionの実行状況を見てみる。
CSVファイルをinput-bucketにUpload
githubにある file1.csv を、input-bucket にUPLOADしてみる。
OCIコンソールからGUI操作でUpload、または、以下のようにCloud ShellからOCI CLIでのUploadで実行。
### oci os object put -ns <ネームスペース> -bn <バケット名> --file <uploadしたいファイル名>
$ oci os object put -ns axxxxxxx -bn input-bucket --file /home/xxxx/file1.csv --no-multipart
Functionの実行状況を確認
- 三 > 開発者サービス > ファンクション > 該当アプリケーション(helloworld-app) > 該当ファンクション(oci-adb-ords-runsql-python)
「メトリック」で、実行状況やエラー発生などが確認できる。
事前準備 B.の、はじめての Oracle Functions アプリケーションを作成 で、ログを保存する設定にしている場合は、エラー発生時にはそのログを参照すると良い。
Autonomous Databaseに接続し、データロードできていることを確認
githubに記載されている、以下のSQLで確認。
select UTL_RAW.CAST_TO_VARCHAR2( DBMS_LOB.SUBSTR( JSON_DOCUMENT, 4000, 1 )) AS json from regionsnumbers;
JSONの構造は分かっているので、以下のSQLでも確認できる。
SELECT
a.json_document.region,
a.json_document.col1,
a.json_document.col2,
a.json_document.col3
FROM regionsnumbers a;
処理済みファイルが processed-bucketに移動していることを確認
OCIコンソールからGUI操作で、または、以下のようにCloud ShellからOCI CLIで確認できる。
### oci os object list -ns <ネームスペース> -bn <バケット名>
$ oci os object list -ns axxxxxx -bn processed-bucket
参考(本文中に記載したものも含む)
- [Oracle Architecture Center]
(https://docs.oracle.com/en/solutions/index.html) - Autonomous DatabaseでのREST用のSODAの使用
- チュートリアル : Oracle Cloud Infrastructure を使ってみよう
- [OCI] Functions を使用して、Object StorageにUploadされたCSVファイルをJSON形式でAutonomous DBにロードしてみた。
- [OCI] OCIシークレットを使ってOracle FunctionsからAutonomous DBに接続してみた。