【IBM Cloud】Cloud FuntionsからDb2 on Cloudのテーブルへアクセスしてみた(python)


はじめに

クラウドサービスといえばAWSのようなイメージがあったのですが、IBMも"IBM Cloud"としてサービスを提供しています。
調べてみると、IBM Cloudにも多くのサービスが提供されており、いくつかのサービスは無料で使えるとのこと。
特に、代表的なIBM製RDBMS"DB2"を200MB以下であれば無料で使える(2020/07時点)、というのはかなり大きいのではないかなと。個人で色々やるなら、200MBもあれば十分でしょう。
同じく、一定量のリクエスト以下なら無料で使える"IBM Cloud Funtions"と連携して、Db2 on Cloud上のテーブル参照/更新ができるようになるまでを記載してみました。

やったこと

①DB2サービスを作ってみる

IBM Cloudのアカウント作成後からスタートです。
IBM Cloudログイン画面

検索ボックスにdb2と入力して、db2のサービス画面を開きます。

リージョンはロンドンかダラス、料金プランはLiteを選択します。この2つ以外のリージョンではLiteプランが無いので注意です。
右下の作成ボタンで、db2サービスが作られます

db2サービスが作成されました。
テーブルとかを作る前に、資格情報を作成しておきます。Cloud Functionからデータベースへ接続する際に必要となります。
左のメニューから"サービス資格情報"を開きます。

db2サービスを作った直後は、資格情報が何も無い状態だと思います。
①"資格情報作成"ボタンを押します。名称の入力を求められるので、何かしら入力します。
②資格情報が作成されるので、名称の左側の"V"みたいな部分を押して情報を開きます。
③"ssldsn"で始まる部分が接続に必要となるため、控えておきます。

資格情報を作成したら、db2のコンソールを開きます。
左メニューから"管理"を選択し、"Open Console"ボタンを押します。

db2サービスが作られたので、テーブルを作ります。今回は事前に用意したcsvファイルを読み込ませることで、テーブルを作成することとします。
左上の緑色三本線のアイコンをクリックし、LOAD→Load Dataの順に開きます。

今回は、以下のようなcsvファイルを使うこととします。

table_test.csv
NUMBER,NAME,UPDATE_TIME
1,Taro,2020-01-01 18:00:00
2,Hanako,2020-02-03 21:00:00
3,Mike,2020-02-14 14:30:00

真ん中あたりの"File Selection"に、対象のcsvファイルをドラッグアンドドロップします。
ファイルをアップロードしたら、右下の"Next"ボタンで先に進みます。

スキーマー/テーブルを選択する画面となります。今回は既存のスキーマーで、新規にテーブルを作成する形にします。
Schemaは、"AUDIT"や"DB2INST1"みたいなシステムチックな名称のスキーマーとは別に、英語3文字+数字5桁のスキーマーがあると思うので、それを選択します。
次のTableは、右上の"New Table"をクリックします。
Create a New Tableでは、テーブル名を入力して、"Create"ボタンをクリックします。
最後に右下の"Next"ボタンを押すと、次の画面に進みます。

列名などを設定する画面となります。
今回はそのまま、右下の"Next"ボタンで次に進みます。

右下の"Begin Load"ボタンをクリックします。

ロードが実行されるまで、少し待ちます。
ロード完了後、"View Table"ボタンで、ロードしたテーブルを確認することができます。
円グラフでLoadに成功/失敗したレコードの割合が確認できるようです。

以上で、Db2側のセットアップ/テーブル作成は完了です。

SELECTするFunctionを作ってみる

続いて、pythonを実行するためのCloud Functions(アクション)を準備します。
IBM Cloudのトップページに戻り、検索ボックスにfunctionと入力し、"Functions"を開きます。

"作成の開始"ボタンをクリックします。

今回は"アクション"を選択します。

アクション名を入力します。
今回はpythonでコーディングするので、ランタイムは"Python 3.7"を選択して、"作成"ボタンを押します。

コーディングの画面となりました。
デフォルトで用意されているmain関数の中に記述した処理が、アクションを起動することで実行されるようです。

main関数の中に、pythonで処理を書いていきます。
今回は下記のような、テストテーブルから特定の行を取得するコードにしました。最低限、動くための処理のみを記載しているので、実際に運用していく処理を記述する際にはエラー処理や処理状況のログ出力などがあったほうが良いと思います。

select_test
import sys
import ibm_db

def main(dict):

    # 資格情報の内容をssldsn変数に代入する
    # "ssldsn":"DATABASE=XXXXX;HOSTNAME=XXXXX;PORT=XXXXX;PROTOCOL=TCPIP;UID=XXXXX;PWD=XXXXX;Security=SSL;"
    ssldsn = "DATABASE=XXXXX;HOSTNAME=XXXXX;PORT=XXXXX;PROTOCOL=TCPIP;UID=XXXXX;PWD=XXXXX;Security=SSL;"

    #DB接続
    db_conn = ibm_db.connect(ssldsn,"","")

    #SQLの組み立て
    sql = "SELECT * FROM TEST_TABLE WHERE NUMBER = ?"
    db_stmt = ibm_db.prepare(db_conn,sql)
    number = 3
    ibm_db.bind_param(db_stmt,1,number)

    #SQLの実行
    ibm_db.execute(db_stmt)
    row = ibm_db.fetch_tuple(db_stmt)

    #DBの切断
    ibm_db.close(db_conn)

    return {'name' : row[1] }

コーディングしたら、右上の"保存"ボタンで保存します。

保存できたら、同じ位置に"起動"ボタンが表示されます。
押すと記述したコードが実行されて、処理結果が表示されます。

実行する際に覚えておくと良いのが、Functionsの課金額は(使用したメモリーサイズ)×(使用した累計秒数)で計算されます(2020/07時点、400,000GB分は無料枠として使えます)。
なので、お試しで使う際は使用するメモリーサイズは小さくしておくほうが良いです。左側のメニューの"ランタイム"から、使用するメモリーサイズを変更することができます。

INSERTするFunction(引数あり)を作ってみる

次はテスト用テーブルに行を追加するFunctions(アクション)を作ってみます。その際、"NAME"列の値はアクション実行時の引数から取得するようにしてみます。また、"UPDATE_TIME"列にはアクション実行時の時刻が入るようにします。
前のセクションと同じ流れで、Funtionsで新規アクションを作成します。今回は"insert_test"という名前にしました。
コード内容は下記の通りです。

insert_test
import sys
import ibm_db
import datetime

def main(dict):
    # 資格情報の内容をコピペ
    ssldsn = "DATABASE=XXXXX;HOSTNAME=XXXXX;PORT=XXXXX;PROTOCOL=TCPIP;UID=XXXXX;PWD=XXXXX;Security=SSL;"    

    #DB接続
    db_conn = ibm_db.connect(ssldsn,"","")

    #SQL文の組み立て
    sql = "INSERT INTO TEST_TABLE VALUES(?,?,?)"
    db_stmt = ibm_db.prepare(db_conn,sql)

    id = 5
    name = dict['name']
    update_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    ibm_db.bind_param(db_stmt,1,id)
    ibm_db.bind_param(db_stmt,2,name)
    ibm_db.bind_param(db_stmt,3,update_time)

    #SQL文の実行
    rtn = ibm_db.execute(db_stmt)

    #DB切断
    rc = ibm_db.close(db_conn)

    return { 'return-code': rtn }

引数を指定してアクションを実行するには、"起動"ボタンの左にある"パラメータを付けて起動"ボタンをクリックします。

下記のようなポップアップが表示されるので、引数情報をjson形式で記載します。記載した内容がmain関数の引数dictに格納されます。
今回、dictから'name'というキーで'Jiro'という値を取得するようにしたいので、
{ 'name' : 'Jiro'}
と入力して、"適用"ボタンを押します。

あとは、"起動"ボタンを押してアクションを実行します。

テスト用テーブルに正しく行が追加されていることを確認しておきます。
Db2コンソールを開き、左上の緑色三本線のアイコンをクリックし、RUN SQLを開きます。

SQL記述用のコンソールが開きます。ここにSQLを記述して左下の"Run all"を押すとSQL文が実行されます。
今回はテストテーブルの中身を確認したいため、
SELECT * FROM TEST_TABLE;
のSQLを実行してみたところ、Nameが'Jiro'の行が追加されているのが確認できました。

終わりに

IBM Cloudを始めたばかりで、Liteアカウントでもこうやって動くものを作れるみたいです。クラウド環境のサーバーレス処理の体験にぴったりと思います。
今後、トリガー(時刻到来/ファイルのアップロード)でアクションを実行したり、処理結果を別のサービスに渡せるように拡張していきたいです。