まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

タグ:db2

昨年、ブログを使ってこのような夏休み企画(休んでないけど)を実施しました:
「30 日後に死ぬ k8s」


IBM Cloud から提供されている k8s 環境は(ワーカーノード1つなどの条件の下で)30 日間無料で使えます。この環境を使って 30 日間で毎日1つずつ、計 30 種類のコンテナをデプロイして動かす、というものでした。後に追加で動作確認できたり、動作確認はできなかったがデプロイできてるっぽいものもあったのですが、その際も IBM Db2 は公式イメージを docker で動かすことはできたのですが、この k8s 環境ではうまくデプロイできずにいました。

が、最近になって改めて挑戦し、今度は同環境で IBM Db2 コンテナを動かすことができました。Db2 クライアントからの接続も確認できました。以前できなくて今回できた理由ははっきりとはわかっていませんが、自分の腕が上がったのか、イメージ側の更新と関係があるのか、あるいはその両方か・・・ ともあれ、遅ればせながら IBM Db2 コンテナイメージを IBM Cloud の 30 日間無料 k8s クラスタにデプロイして動かす方法を紹介します。


【30 日間無料の k8s クラスタを用意】
こちらの記事を参照して、IBM Cloud の 30 日間無料 k8s クラスタをセットアップしてください。また具体的な操作をする際に必要な ibmcloud CLI や kubectl CLI といったコマンドツール類のインストール手順も含まれています(リンク先最後の "$ kubectl get all" コマンドが正しく実行できる状態にしてください):
http://dotnsf.blog.jp/archives/1079287640.html


なおリンク先でも触れられていますが、この k8s クラスタ環境はシングルワーカーノードです。イメージをデプロイした後に "type = NodePort" を指定することでサービスを公開できます(Ingress などが提供されていないため、他の方法でサービス公開はできません)。


【IBM Db2 コンテナイメージ】
公式な IBM Db2 コミュニティ版のコンテナイメージはこちらから無料で提供されています:
https://hub.docker.com/r/ibmcom/db2


同ページ内の説明文によると、この無料コミュニティ版コンテナイメージを動かす前提条件として、「CPU: 4コア以下、メモリ: 16GB 以下」が挙げられています:
2022011801


一方で IBM Cloud の 30 日間無料 k8s クラスタのワーカーノードは「CPU: 2 コア、メモリ: 4GB」であることがわかっています:
2022011802


一応、条件を満たした環境で使う、ということになります。なおコンテナイメージのリンク先情報によると、2022/01/18 時点で特にバージョンを指定せずにこのコンテナを利用しようとすると、最新版である v11.5.7.0 が使われるようです(以下の内容はこのバージョンで動作確認しています):
2022011803



【IBM Db2 を k8s にデプロイするための yaml ファイル】
色々試行錯誤してできあがった IBM Cloud の 30 日間無料 k8s クラスタにデプロイできるよう調整した yaml ファイルはこちらです:
https://github.com/dotnsf/yamls_for_iks/blob/main/db2_deployment_nodeport.yaml

このファイルを指定して、
$ kubectl apply -f https://raw.githubusercontent.com/dotnsf/yamls_for_iks/main/db2_deployment_nodeport.yaml

とすることでデプロイできます(その場合は db2inst1 ユーザーのパスワードは db2inst1 、サンプル(SAMPLE)データベースは作成、それとは別に db2inst1 ユーザーから使える mydb という空のデータベースも作成する、というオプションが初期設定されています)。

あるいは以下のように一度 wget コマンドでローカルにダウンロードしてから内容をカスタマイズして、その後に改めて kubectl コマンドでデプロイすることも可能です:
$ wget https://raw.githubusercontent.com/dotnsf/yamls_for_iks/main/db2_deployment_nodeport.yaml

(ダウンロードした db2_deployment_nodeport.yaml ファイルをカスタマイズ)

$ kubectl apply db2_deployment_nodeport.yaml


例えば db2inst1 ユーザーのパスワードを変えたい場合は 38 行目を変更、サンプルデータベースを作る必要がなければ 39, 40 行目を削除、mydb データベースもこの時点で作る必要がなければ 41, 42 行目を削除、といった具合です。

なお後者のカスタマイズをする場合に指定可能なオプション内容については公式ページ内"Advanced Configuration Options" 欄を参考に編集してください。

"kubectl get all" コマンドでデプロイ後のクラスタの様子を確認してみます:
$ kubectl get all

NAME                            READY   STATUS    RESTARTS   AGE
pod/db2-54ff649944-w7d24        1/1     Running   0          2d14h
pod/hostname-7b4f76fd59-c8b2l   1/1     Running   0          8d

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)           AGE
service/db2          NodePort    172.21.54.211           50000:30500/TCP   2d14h
service/hostname     NodePort    172.21.105.49           8080:30080/TCP    8d
service/kubernetes   ClusterIP   172.21.0.1              443/TCP           8d

NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/db2        1/1     1            1           2d14h
deployment.apps/hostname   1/1     1            1           8d

NAME                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/db2-54ff649944        1         1         1       2d14h
replicaset.apps/hostname-7b4f76fd59   1         1         1       8d

↑のように Db2 関連の pod, service, deployment, replicaset が1つずつ追加されていればコマンドは成功しています。 また service を見ると 50000 番ポート(Db2 の標準動作ポート)が 30500 番で公開されていることも確認できます。つまり Db2 は
 (ワーカーノードのIPアドレス※):30500
で公開されて動いていることがわかります(※ワーカーノードの IP アドレス確認方法はこちらを参照してください)。


【動作確認】
では実際に Db2 サーバーが正しく動作していることを動作確認してます。。。 と、実はここが大きな問題でした。Db2 サーバーは正しくデプロイされて動作しているのですが、Db2 サーバーに接続試験を行おうとすると、その環境準備がちょっと面倒だったりするのです。

Db2 サーバーに CLI でアクセスしようとすると Db2 クライアントライブラリのダウンロード&インストールが必要です。Node.js などのプログラムから接続するにもクライアントライブラリが必要になります。この Db2 クライアントライブラリをインストールするには、無料版の Db2 Community Edition をダウンロードしてインストールする必要があり、ここで急にハードルが上がってしまいます。

そこでこれらの手間を省くために別の動作確認方法を考えました。それは「Db2 のコンテナインスタンスをもう1つ作って、そこからリモートサーバーにアクセスする」という方法です。マネージドサービスと異なり、Db2 サーバーのコンテナイメージからはライブラリセットアップ済みの CLI も使えるのです。そのための Db2 コンテナをもう1つ追加で作ってクライアントとして使うことで(手間という意味では)比較的容易に動作確認用クライアント環境が用意できると思いました。

というわけで、先程の yaml ファイルを少し変更(サンプルDB 作らず、mydb DBも作らず、ポート番号は 30501 に変更、コンテナの名称も db2 から db2cli に変更)した yaml ファイルを使って、(機能的にはサーバー機能もインストール済みですが)新しい Db2 クライアントコンテナを作成します:
$ kubectl apply -f https://raw.githubusercontent.com/dotnsf/yamls_for_iks/main/db2cli_deployment_nodeport.yaml

作成後にクラスタ内の様子を kubectl コマンドで確認すると、新しい db2cli インスタンスが起動しているはずです:
$ kubectl get all
NAME                            READY   STATUS    RESTARTS   AGE
pod/db2-54ff649944-w7d24        1/1     Running   0          2d14h
pod/db2cli-86d476659d-m7c6d     1/1     Running   0          9s
pod/hostname-7b4f76fd59-c8b2l   1/1     Running   0          8d

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)           AGE
service/db2          NodePort    172.21.54.211           50000:30500/TCP   2d14h
service/db2cli       NodePort    172.21.112.13           50000:30501/TCP   11s
service/hostname     NodePort    172.21.105.49           8080:30080/TCP    8d
service/kubernetes   ClusterIP   172.21.0.1              443/TCP           8d

NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/db2        1/1     1            1           2d14h
deployment.apps/db2cli     1/1     1            1           11s
deployment.apps/hostname   1/1     1            1           8d

NAME                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/db2-54ff649944        1         1         1       2d14h
replicaset.apps/db2cli-86d476659d     1         1         1       11s
replicaset.apps/hostname-7b4f76fd59   1         1         1       8d

ここからは db2cli コンテナからの作業となります。まずは db2cli コンテナ上のシェルにログインする必要があります。まずは IBM Cloud の k8s サービスからダッシュボードにアクセスします:
2022011801


ダッシュボード画面左メニューから「ポッド」を選び、ポッド一覧から "db2cli" で始まる名前のポッドを探し、画面右のメニューから「実行」を選択します:
2022011802


これで該当 Pod のシェルをブラウザからリモート操作できるようになります:
2022011803


以下の手順で(最初に作った方の)Db2 サーバーに接続して SQL を実行する、という動作確認をします。

まずは Db2 を利用可能なユーザー(db2inst1)にスイッチします(プロンプトが # から $ へ切り替わります):
# su - db2inst1
$

次に Db2 コマンドをインタラクティブに実行できるシェルに切り替えます(プロンプトが $ から db2 => に切り替わります):
$ db2
db2 =>

この状態から Db2 サーバーに接続したり、ログインしたり、SQL を実行したりできます。まずは Db2 サーバーへの接続が必要です。Db2 ではリモートサーバーやデータベースを「カタログ」という単位で管理するので、まず最初にリモート Db21 サーバーを db2onk8s という名前でカタログに登録します。以下のコマンドを実行します(1.2.3.4 部分はワーカーノードの IP アドレスに置き換えてください):
db2 => catalog tcpip node db2onk8s remote 1.2.3.4 server 30500

次にこのサーバー上の SAMPLE データベースをカタログに登録します:
db2 => catalog database sample at node db2onk8s

これで Db2 クライアントから Db2 サーバー上の SAMPLE データベースに接続するためのカタログができました。

ではこのデータベースカタログを使って Db2 サーバー上の SAMPLE データベースに接続します。このコマンドを入力した後に db2inst1 ユーザーのパスワードを聞かれるので、Db2 サーバーのコンテナを作成した時に指定した db2inst1 ユーザーのパスワード(変更していない場合は db2inst1)を入力してください:
db2 => connect to sample user db2inst1
Enter current password for db2inst1:


正しいパスワードを入力すると目的のデータベースに接続します。この状態で Db2 クライアントから Db2 サーバーに接続しています:
db2 => connect to sample user db2inst1
Enter current password for db2inst1:

   Database Connection Information

 Database server        = DB2/LINUXX8664 11.5.7.0
 SQL authorization ID   = DB2INST1
 Local database alias   = SAMPLE

db2 => 

SQL を使って Db2 サーバーの SAMPLE データベースのテーブルからレコードを取り出したり、追加・変更・削除といった操作が可能です:
db2 => select * from employee;

EMPNO  FIRSTNME     MIDINIT LASTNAME        WORKDEPT PHONENO HIREDATE   JOB      EDLEVEL SEX BIRTHDATE  SALARY      BONUS       COMM       
------ ------------ ------- --------------- -------- ------- ---------- -------- ------- --- ---------- ----------- ----------- -----------
000010 CHRISTINE    I       HAAS            A00      3978    01/01/1995 PRES          18 F   08/24/1963   152750.00     1000.00     4220.00
000020 MICHAEL      L       THOMPSON        B01      3476    10/10/2003 MANAGER       18 M   02/02/1978    94250.00      800.00     3300.00
000030 SALLY        A       KWAN            C01      4738    04/05/2005 MANAGER       20 F   05/11/1971    98250.00      800.00     3060.00
000050 JOHN         B       GEYER           E01      6789    08/17/1979 MANAGER       16 M   09/15/1955    80175.00      800.00     3214.00
000060 IRVING       F       STERN           D11      6423    09/14/2003 MANAGER       16 M   07/07/1975    72250.00      500.00     2580.00
000070 EVA          D       PULASKI         D21      7831    09/30/2005 MANAGER       16 F   05/26/2003    96170.00      700.00     2893.00
000090 EILEEN       W       HENDERSON       E11      5498    08/15/2000 MANAGER       16 F   05/15/1971    89750.00      600.00     2380.00
000100 THEODORE     Q       SPENSER         E21      0972    06/19/2000 MANAGER       14 M   12/18/1980    86150.00      500.00     2092.00
000110 VINCENZO     G       LUCCHESSI       A00      3490    05/16/1988 SALESREP      19 M   11/05/1959    66500.00      900.00     3720.00
000120 SEAN                 O'CONNELL       A00      2167    12/05/1993 CLERK         14 M   10/18/1972    49250.00      600.00     2340.00
000130 DELORES      M       QUINTANA        C01      4578    07/28/2001 ANALYST       16 F   09/15/1955    73800.00      500.00     1904.00
000140 HEATHER      A       NICHOLLS        C01      1793    12/15/2006 ANALYST       18 F   01/19/1976    68420.00      600.00     2274.00
000150 BRUCE                ADAMSON         D11      4510    02/12/2002 DESIGNER      16 M   05/17/1977    55280.00      500.00     2022.00
000160 ELIZABETH    R       PIANKA          D11      3782    10/11/2006 DESIGNER      17 F   04/12/1980    62250.00      400.00     1780.00
000170 MASATOSHI    J       YOSHIMURA       D11      2890    09/15/1999 DESIGNER      16 M   01/05/1981    44680.00      500.00     1974.00
000180 MARILYN      S       SCOUTTEN        D11      1682    07/07/2003 DESIGNER      17 F   02/21/1979    51340.00      500.00     1707.00
000190 JAMES        H       WALKER          D11      2986    07/26/2004 DESIGNER      16 M   06/25/1982    50450.00      400.00     1636.00
000200 DAVID                BROWN           D11      4501    03/03/2002 DESIGNER      16 M   05/29/1971    57740.00      600.00     2217.00
000210 WILLIAM      T       JONES           D11      0942    04/11/1998 DESIGNER      17 M   02/23/2003    68270.00      400.00     1462.00
000220 JENNIFER     K       LUTZ            D11      0672    08/29/1998 DESIGNER      18 F   03/19/1978    49840.00      600.00     2387.00
000230 JAMES        J       JEFFERSON       D21      2094    11/21/1996 CLERK         14 M   05/30/1980    42180.00      400.00     1774.00
000240 SALVATORE    M       MARINO          D21      3780    12/05/2004 CLERK         17 M   03/31/2002    48760.00      600.00     2301.00
000250 DANIEL       S       SMITH           D21      0961    10/30/1999 CLERK         15 M   11/12/1969    49180.00      400.00     1534.00
000260 SYBIL        P       JOHNSON         D21      8953    09/11/2005 CLERK         16 F   10/05/1976    47250.00      300.00     1380.00
000270 MARIA        L       PEREZ           D21      9001    09/30/2006 CLERK         15 F   05/26/2003    37380.00      500.00     2190.00
000280 ETHEL        R       SCHNEIDER       E11      8997    03/24/1997 OPERATOR      17 F   03/28/1976    36250.00      500.00     2100.00
000290 JOHN         R       PARKER          E11      4502    05/30/2006 OPERATOR      12 M   07/09/1985    35340.00      300.00     1227.00
000300 PHILIP       X       SMITH           E11      2095    06/19/2002 OPERATOR      14 M   10/27/1976    37750.00      400.00     1420.00
000310 MAUDE        F       SETRIGHT        E11      3332    09/12/1994 OPERATOR      12 F   04/21/1961    35900.00      300.00     1272.00
000320 RAMLAL       V       MEHTA           E21      9990    07/07/1995 FIELDREP      16 M   08/11/1962    39950.00      400.00     1596.00
000330 WING                 LEE             E21      2103    02/23/2006 FIELDREP      14 M   07/18/1971    45370.00      500.00     2030.00
000340 JASON        R       GOUNOT          E21      5698    05/05/1977 FIELDREP      16 M   05/17/1956    43840.00      500.00     1907.00
200010 DIAN         J       HEMMINGER       A00      3978    01/01/1995 SALESREP      18 F   08/14/1973    46500.00     1000.00     4220.00
200120 GREG                 ORLANDO         A00      2167    05/05/2002 CLERK         14 M   10/18/1972    39250.00      600.00     2340.00
200140 KIM          N       NATZ            C01      1793    12/15/2006 ANALYST       18 F   01/19/1976    68420.00      600.00     2274.00
200170 KIYOSHI              YAMAMOTO        D11      2890    09/15/2005 DESIGNER      16 M   01/05/1981    64680.00      500.00     1974.00
200220 REBA         K       JOHN            D11      0672    08/29/2005 DESIGNER      18 F   03/19/1978    69840.00      600.00     2387.00
200240 ROBERT       M       MONTEVERDE      D21      3780    12/05/2004 CLERK         17 M   03/31/1984    37760.00      600.00     2301.00
200280 EILEEN       R       SCHWARTZ        E11      8997    03/24/1997 OPERATOR      17 F   03/28/1966    46250.00      500.00     2100.00
200310 MICHELLE     F       SPRINGER        E11      3332    09/12/1994 OPERATOR      12 F   04/21/1961    35900.00      300.00     1272.00
200330 HELENA               WONG            E21      2103    02/23/2006 FIELDREP      14 F   07/18/1971    35370.00      500.00     2030.00
200340 ROY          R       ALONZO          E21      5698    07/05/1997 FIELDREP      16 M   05/17/1956    31840.00      500.00     1907.00

  42 record(s) selected.


この時点で k8s ダッシュボード画面はこのようになっています。必要に応じて続けてコマンドを実行することもできます:
2022011800


操作を終了して接続を切るには quit コマンドを実行します:
db2 => quit

$ exit

# 


改めて k8s 上にデプロイした Db2 サーバーコンテナ(とクライアントコンテナ)が期待通りに動いていることが確認できました。


IBM Cloud から提供されている Db2 on Cloud を、2021/05/23 時点では最新となる v4 API を使ってアクセスするまでを実現した Node.js のサンプルアプリケーションを作りました。アクセストークンを取得して SQL を実行し、その結果を取得するまでの一連の流れを紹介します。


Db2 on Cloud は IBM 製リレーショナルデータベース製品である Db2 をマネージドサービスとして IBM Cloud から提供しているサービスです。IBM Cloud のライトアカウントを作成し、フリープランを選択することで、データは 200MB までなどの制約はありますが無料で利用することも可能です:
2021052301


この Db2 は製品としての経緯もあり、専用(ネイティブ)クライアントライブラリをインストールした上で JDBC/ODBC などから利用することが多かったのですが、近年は Node.js 向けのライブラリなども提供されるようになり、各種プログラミング言語からの利用もできるようになっていました。その API の最新版(v4)では REST API 対応が行われ、(ラズベリーパイなど)専用クライアントライブラリが存在しなかった環境からの利用も可能になりました。

というわけで、今回のブログエントリではこの v4 API を使って Db2 on Cloud のインスタンスにアクセスして SQL を実行し、その実行結果を取得するまでの一連の手順をサンプルアプリケーションとそのコードを参照しつつ紹介します。


【サンプルアプリケーション】
以下で紹介するサンプルアプリケーションの(Node.js 向け)ソースコードはこちらで公開しています:
https://github.com/dotnsf/node-db2


Node.js がインストールされていれば Windows でも Mac でも Linux でも動きます。特にこのアプリケーションは v4 API で作っているので、これまでは(クライアントライブラリが提供されていないため)Db2 にアクセスできなかったラズベリーパイなどの環境からでも利用できる点が特徴になっています。なのでラズパイ環境をお持ちだったらぜひラズパイから利用してみていただきたいです。

サンプルアプリを利用するには、まず IBM Cloud 側の準備が必要です。大まかに以下2段階の準備を行います:
(1)IBM Cloud にログインして Db2 on Cloud サービスインスタンスを作成
(2)作成したインスタンスの接続情報を取得


まず(1)を行います。IBM Cloud に(必要であればアカウントを作成して)ログインし、Db2 サービスインスタンスを作成します:
2021052302


この際に "Lite" プランを選択しておくとデータ量 200MB 上限や、同時接続数 15 などの制約がありますが、無料で利用することができます:
2021052303


(1)のインスタンスを作成したら(2)の準備を行います。作成したインスタンスの「サービス資格情報」タブを選択し、「新規資格情報」ボタンで「サービス資格情報」を1つ追加して、その中身を確認します:
2021052304


以下のような JSON フォーマットの情報を確認することができます:
{
  "db": "BLUDB",
  "dsn": "DATABASE=BLUDB;HOSTNAME=dashdb-xxx-xxxxx-xxxxxx.services.dal.bluemix.net;PORT=50000;PROTOCOL=TCPIP;UID=username;PWD=password;",
  "host": "dashdb-xxx-xxxxx-xxxxxx.services.dal.bluemix.net",
  "hostname": "dashdb-xxx-xxxxx-xxxxxx.services.dal.bluemix.net",
  "https_url": "https://dashdb-xxx-xxxxx-xxxxxx.services.dal.bluemix.net",
  "jdbcurl": "jdbc:db2://dashdb-xxx-xxxxx-xxxxxx.services.dal.bluemix.net:50000/BLUDB",
  "parameters": {
    "role_crn": "crn:v1:bluemix:public:iam::::serviceRole:Manager"
  },
  "password": "password",
  "port": 50000,
  "ssldsn": "DATABASE=BLUDB;HOSTNAME=dashdb-xxx-xxxxx-xxxxxx.services.dal.bluemix.net;PORT=50001;PROTOCOL=TCPIP;UID=username;PWD=password;Security=SSL;",
  "ssljdbcurl": "jdbc:db2://dashdb-xxx-xxxxx-xxxxxx.services.dal.bluemix.net:50001/BLUDB:sslConnection=true;",
  "uri": "db2://username:password@dashdb-xxx-xxxxx-xxxxxx.services.dal.bluemix.net:50000/BLUDB",
  "username": "username"
}

ここで必要になるのは以下の3つの値です:

username
password
hostname


加えて deployment id を取得します。この ID はサービス固有の ID で、すべての REST API 実行時に必要な値です。取得方法はサービスを表示しているブラウザ画面の URL を確認します:
2021052305


おそらくこのようなフォーマットの URL 文字列になっています:
https://cloud.ibm.com/services/dashdb-for-transactions/crn%3Av1%3Abluemix%3Apublic%3Adashdb-for-transactions%3Aus-south%3Aa%2Fxxxxxxxxxxxx%3Axxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx%3A%3A?paneId=manage

この中の "crn" で始まる文字列(? が含まれる場合はその手前まで)を URL デコードした値が deployment id です。URL デコードといってもパターンは2つに決まっていて、"%3A" を ":" に、"%2F" を "/" に変換するだけです。例えば該当の Db2 on Cloud サービスを表示している時の URL 内文字列がこの内容だった場合、
https://cloud.ibm.com/services/dashdb-for-transactions/crn%3Av1%3Abluemix%3Apublic%3Adashdb-for-transactions%3Aus-south%3Aa%2Fxxxxxxxxxxxx%3Axxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx%3A%3A?paneId=manage

deployment id は crn で始まる青字部分を URL デコードした値ということになり、具体的には以下の値となります:
crn:3v1:bluemix:public:dashdb-for-transactions:us-south:a/xxxxxxxxxxxx:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx::

以上、ここまでの作業で Db2 on Cloud のサービスインスタンスを作成し、その username, password, hostname, deployment id の4つの情報を取得することができました。この4つの値が取得できれば、実際にサンプルアプリケーションを動かすことができます。


上述のリポジトリ URL から git clone やダウンロード&展開するなどしてソースコード一式を取得します。そして settings.js をテキストエディタで開いて、先程取得した4つの値を入力して保存します:
2021052306


これでソースコード側に必要な変更も完了です。では実際に Node.js で動かしてみましょう:
$ cd node-db2

$ npm install

$ node app

ここまでのコマンドを実行すると、サンプルのウェブアプリケーションは 8080 番ポートで待ち受ける形で起動します。ウェブブラウザ(別 PC からでも可)からサンプルの HTTP リクエストを送信して、Db2 on Cloud で SQL を実行し、その結果を取得します:
http://(上記の $ node app を実行したマシンの IP アドレス):8080/ping

なお、この GET /ping リクエストは Db2 on Cloud インスタンスに対して以下の SQL を実行した結果のシステム情報を取得するように作られたものです:
select TABNAME, TABSCHEMA, OWNER from syscat.tables fetch first 5 rows only;

実際にウェブブラウザでこの URL にアクセスするとこのような結果になります。上述の SQL を実行した結果が JSON で返ってきました。仮にアプリケーションをラズベリーパイ上で動かしていても同様の結果が取得できているはずです。これまでは Db2 のクライアントライブラリが導入できる環境からでないと実行できなかった SQL を、v4 API では(サーバー上のもの以外には)クライアントライブラリを使わない環境でも実行して結果を取得することができる、ということがわかります:
2021052307


【ソースコード解説】
ではソースコードを見ながら v4 API の解説をします。上述のオペレーションで使っているファイルは変数設定以外は app.js のみなので、全容を確認したい場合はこのファイルを参照ください。

上述で行ったのは1つの SQL を実行して、その結果を取得する、というごく普通のオペレーションですが、v4 API では大きく3つのパートに分かれて処理されています((2)と(3)が別れて処理されている点に注目):

(1)アクセストークン取得
(2)SQL 実行
(3)SQL 結果取得


まず(1)について。これまでの Db2 API では認証時にユーザー名とパスワードがあればログインして SQL を実行することができましたが、v4 API では(今どきらしく)まずアクセストークンを取得して、アクセストークンを付与しながら SQL を実行する必要があります。というわけでアクセストークンの取得手順を紹介します。

具体的には以下のようなコードを実行しているのですが、settings.js に設定した username と password を https://(hostname)/dbapi/v4/auth/tokens に POST しています。またその際の HTTP リクエストヘッダ内で deployment id の値を送付しています(HTTP リクエストヘッダに deployment id を含める、というのは以下すべての REST API で共通です)。成功した場合、返されるオブジェクトの token キーにアクセストークンが付与されて返ってくるので、この値を保存しています(実際のアプリではセッション等に保存しておくべきです):
var access_token = null;
var option = {
  url: 'https://' + settings.hostname + '/dbapi/v4/auth/tokens',
  json: { userid: settings.username, password: settings.password },
  headers: { 'content-type': 'application/json', 'x-deployment-id': settings.deployment_id },
  method: 'POST'
};
request( option, async function( err, res0, body ){
  if( err ){
    console.log( { err } );
  }else{
    if( body && body.token ){
      access_token = body.token;
      console.log( { access_token } );
    }
  }
});


GET /ping にリクエストがあると、このアクセストークンを使って(2)SQL を実行します。app.js では以下のように実行しています:
app.get( '/ping', function( req, res ){
  res.contentType( 'application/json; charset=utf-8' );
  if( access_token ){
    var sql0 = 'select TABNAME, TABSCHEMA, OWNER from syscat.tables fetch first 5 rows only;';
    var option0 = {
      url: 'https://' + settings.hostname + '/dbapi/v4/sql_jobs',
      json: { commands: sql0, limit: 10, separator: ';', stop_on_error: 'no' },
      headers: { 'content-type': 'application/json', 'Authorization': 'Bearer ' + access_token, 'x-deployment-id': settings.deployment_id },
      method: 'POST'
    };
    request( option0, async function( err0, res0, body0 ){
      if( err0 ){
        console.log( { err0 } );
        res.status( 400 );
        res.write( JSON.stringify( { error: err0 }, null, 2 ) );
        res.end();
      }else{
        if( body0 && body0.id ){
            :
            :

GET /ping リクエストへのハンドラとして、まず "select TABNAME, TABSCHEMA, OWNER from syscat.tables fetch first 5 rows only;" という SQL を https://(hostname)/dbapi/v4/sql_jobs に POST して実行しています。この処理が成功すると、返されるオブジェクトに id というキー値が含まれています。

そして(3)では、実行した SQL の結果を取得します。その際には(2)で取得した id キー値を指定して GET https://(hostname)/dbapi/v4/sql_jobs/(id) を実行して、その結果が先程のブラウザ画面のようなフォーマットで取得されていたのでした:
            :
            :
        if( body0 && body0.id ){
          console.log( { body0 } );
          var option1 = {
            url: 'https://' + settings.hostname + '/dbapi/v4/sql_jobs/' + body0.id,
            headers: { 'content-type': 'application/json', 'Authorization': 'Bearer ' + access_token, 'x-deployment-id': settings.deployment_id },
            method: 'GET'
          };
          request( option1, async function( err1, res1, body1 ){
            if( err1 ){
              console.log( { err1 } );
              res.status( 400 );
              res.write( JSON.stringify( { error: err1 }, null, 2 ) );
              res.end();
            }else{
              //. body1 は string
              body1 = JSON.parse( body1 );
              console.log( { body1 } );
              res.write( JSON.stringify( body1, null, 2 ) );
              res.end();
            }
          });
        }else{
          res.status( 400 );
          res.write( JSON.stringify( { error: body0 }, null, 2 ) );
          res.end();
        }
      }
    });
  }else{
    res.status( 400 );
    res.write( JSON.stringify( { error: 'no access_token' }, null, 2 ) );
    res.end();
  }
});


NoSQL とは違って、トランザクションを含む(時間のかかる)処理を実行する可能性もあるため、その間で処理をブロックしないようにこのような仕様で API が用意されているのだと思います。上の例では SQL の実行と結果の取得を続けて行って実行結果を返していますが、(途中に取得できる id をいったんクライアントに返すことで)これら2つの処理を別の REST API で分けて実行させることも可能になります。シングルスレッドの Node.js での実装を考慮すると、こちらのほうがより正しいといえるかもしれません。


【良い点・悪い点】
なんといっても「ラズベリーパイなどの、Db2 クライアントライブラリが提供されていないシステムから Db2 サーバーに接続してクエリーを実行できる」ようになったことが大きな改善点であると感じました。また時間のかかる処理を実行する際にも、まとめて実行して、その間の他のリクエストをブロックすることなく、後から結果を確認できるようになっている点もクラウド時代らしいといえます。

唯一残念な点は「プレースホルダー型の SQL に未対応」な点です。SQL を比較的安全に実行する上でよく使われるプレースホルダー型の SQL("SELECT * from xxxxx where id = ?" で、パラメーターの id を分けて送って実行する SQL)には現時点ではこの REST API では未対応のようで、現時点では開発者が気をつけて実装するか、(クライアントライブラリが提供されているシステムから)従来の専用ライブラリを使って実行する必要がありそうでした。


【参考】
IBM Db2 on Cloud REST API


先日、コマンドラインツールで IBM Cloud 上の Db2 サービスインスタンスに接続する、というエントリを書きました:
Db2 コマンドラインインターフェースから IBM Cloud 上のリモート Db2 インスタンスに接続する


接続するまでの設定項目は上記エントリに書いてあるのですが、実際に接続したあとに SQL を実行する上でコマンドを実行する際のチートシート的なまとめを書いておきます。

まずは前回も書いた DB2 のスタート。db2inst1 ユーザーになってから db2start コマンドを実行します(青字は実行結果です):
$ su - db2inst1
$ db2start
05/27/2018 20:13:33     0   0   SQL1063N  DB2START processing was successful.
SQL1063N  DB2START processing was successful.

データベースの一覧を確認する場合は list db directory を実行します:
$ db2 list db directory

 System Database Directory

 Number of entries in the directory = 3

Database 1 entry:

 Database alias                       = REMOTEDB
 Database name                        = BLUDB
 Node name                            = DASHDB
 Database release level               = 14.00
 Comment                              =
 Directory entry type                 = Remote
 Catalog database partition number    = -1
 Alternate server hostname            =
 Alternate server port number         =

Database 2 entry:

 Database alias                       = JSONDB
 Database name                        = JSONDB
 Local database directory             = /home/db2inst1
 Database release level               = 14.00
 Comment                              =
 Directory entry type                 = Indirect
 Catalog database partition number    = 0
 Alternate server hostname            =
 Alternate server port number         =

Database 3 entry:

 Database alias                       = MYDB
 Database name                        = MYDB
 Local database directory             = /home/db2inst1
 Database release level               = 14.00
 Comment                              =
 Directory entry type                 = Indirect
 Catalog database partition number    = 0
 Alternate server hostname            =
 Alternate server port number         =

上記コマンドでデータベースの一覧を確認した上でどこかのデータベース(下の例では mydb)に接続します:
$ db2 connect to mydb

   Database Connection Information

 Database server        = DB2/LINUXX8664 11.1.2.2
 SQL authorization ID   = DB2INST1
 Local database alias   = MYDB

データベースに接続した上で、テーブルの一覧を照会する場合は list tables を実行します:
$ db2 list tables

Table/View                      Schema          Type  Creation time
------------------------------- --------------- ----- --------------------------
GOKON                           DB2INST1        T     2018-05-23-19.09.07.748477

  1 record(s) selected.


DB2 コマンドをそのまま実行するとインタラクティブモードになります:
$ db2
(c) Copyright IBM Corporation 1993,2007
Command Line Processor for DB2 Client 11.1.2.2

You can issue database manager commands and SQL statements from the command
prompt. For example:
    db2 => connect to sample
    db2 => bind sample.bnd

For general help, type: ?.
For command help, type: ? command, where command can be
the first few keywords of a database manager command. For example:
 ? CATALOG DATABASE for help on the CATALOG DATABASE command
 ? CATALOG          for help on all of the CATALOG commands.

To exit db2 interactive mode, type QUIT at the command prompt. Outside
interactive mode, all commands must be prefixed with 'db2'.
To list the current command option settings, type LIST COMMAND OPTIONS.

For more detailed help, refer to the Online Reference Manual.

db2 =>

インタラクティブモードでは接続中のデータベースに対して、SQL を直接実行することができます:
db2 => select * from gokon

GIRL_ID     GNAME      AGE         GOKON_DATE
----------- ---------- ----------- ----------
          2 Beth                19 2016-01-01
          3 Karmen              34 1990-10-01
          4 Hanako              69 2009-05-01

  3 record(s) selected.

インタラクティブモードから抜けるには quit を実行します:
db2 => quit
DB20000I  The QUIT command completed successfully.


最後に DB2 を停止します:
$ db2stop
2018-05-27 20:10:25     0   0   SQL1064N  DB2STOP processing was successful.
SQL1064N  DB2STOP processing was successful.

管理系コマンドについてはノータッチでしたが、とりあえずデベロッパーである自分が最低限使いそうなコマンドはこんなもんでしょうかね。。

 

以前に Linux 版 Db2 を導入した時の手順を紹介したブログがありました:
http://dotnsf.blog.jp/archives/2960284.html


3年以上前のこの時の仮想環境が奇跡的に残っていたので久しぶりに使ってみました。で、折角の Db2 コマンドライン環境(?)なので、このコマンドラインインターフェースから IBM Cloud 上の DBaaS である Db2 に接続して使ってみました。以下、その手順の紹介です。

まずは IBM Cloud にログインして Db2 インスタンスを作成します。無料のライトアカウントでも使えるサービスが用意されているので、派手に使わない限りは無料で試すこともできます:
2018052302


無料のライトプランを使う場合はデプロイ先ロケーションを「米国南部」に設定します。加えて自分のメールアドレスを指定します:
2018052303


デプロイ先ロケーションが米国南部の場合、無料の Lite プランが選択可能になります(もちろん他のプランでも構いません)。プラン設定後に「作成」ボタンでインスタンスが作成されます:
2018052304



インスタンス作成後、「サービス資格情報」メニューから「資格情報の表示」を選択します(「資格情報の表示」が存在しない場合は、最初に「新規資格情報」をクリックして作成し、その後に改めて「資格情報の表示」を選択します)。すると画面下部に JSON フォーマットで接続先サーバー名やユーザー、パスワードといった情報を確認できます:
2018052301


この中で、今回使うのは以下の5つの情報です:
 - hostname(接続先のサーバー名)
 - password(接続時のパスワード)
 - port(接続先のポート番号)
 - db(データベース名)
 - username(接続時のユーザー名)


以下では、これら5つの値がこのような内容になっていたと仮定して説明を続けます:
{
  "hostname": "dashdb-txn-sbox-yp-dal09-03.services.dal.bluemix.net",
  "password": "xxxxxxxx",
  "port": 50000,
  "db": "BLUDB",
  "username": "lrz77612",
    :
}



ではこの DBaaS 上のデータベース(BLUDB)にコマンドラインから接続するための手順を紹介します。


db2inst1 ユーザーへの変更

ここから下のコマンドはすべて db2 インストール時に指定したユーザー(今回の例では db2inst1)に切り替えて行う必要があります。というわけでターミナル上でのユーザーを切り替えます:
$ su - db2inst1

ノードカタログの確認

接続先となる Db2 サーバーはサーバーノードとしてカタログに記録されている必要があります。というわけで、まず現在のノードカタログを確認します(青字は出力結果):
$ db2 list node directory
SQL1037W  The node directory is empty.  SQLSTATE=01606

この出力結果によるとノードカタログは空で何も登録されていないようです。


ノードのカタログ登録

というわけで今回の接続先となる IBM Cloud 上の Db2 サーバーをカタログに登録します。以下のように接続先のサーバー名とポート番号を指定し、今回は "dashdb" という名前でカタログに登録しています(太字部分は各自の環境や希望に併せて変更してください):
$ db2 catalog tcpip node dashdb remote dashdb-txn-sbox-yp-dal09-03.services.dal.bluemix.net server 50000
DB20000I  The CATALOG TCPIP NODE command completed successfully.
DB21056W  Directory changes may not be effective until the directory cache is
refreshed.
成功したようです。この状態で再度ノードカタログを確認すると、今度は dashdb という名前のカタログが確認できるはずです:
$ db2 list node directory

 Node Directory

 Number of entries in the directory = 1

Node 1 entry:

 Node name                      = DASHDB
 Comment                        =
 Directory entry type           = LOCAL
 Protocol                       = TCPIP
 Hostname                       = dashdb-txn-sbox-yp-dal09-03.services.dal.bluemix.net
 Service name                   = 50000



ノードカタログを削除

今回は作業しませんが、登録したカタログを削除する場合はカタログ名を指定して以下のように実行します:
$ db2 uncatalog node dashdb


エイリアスの確認

DB2 でデータベースに接続するにはデータベースをエイリアスとして登録する必要があります。というわけで次に接続先となるリモートデータベースのエイリアスを作成します。まずは現在登録されているエイリアスの一覧を確認します:
$ db2 list db directory

 System Database Directory

 Number of entries in the directory = 2

Database 1 entry:

 Database alias                       = JSONDB
 Database name                        = JSONDB
 Local database directory             = /home/db2inst1
 Database release level               = 14.00
 Comment                              =
 Directory entry type                 = Indirect
 Catalog database partition number    = 0
 Alternate server hostname            =
 Alternate server port number         =

Database 2 entry:

 Database alias                       = MYDB
 Database name                        = MYDB
 Local database directory             = /home/db2inst1
 Database release level               = 14.00
 Comment                              =
 Directory entry type                 = Indirect
 Catalog database partition number    = 0
 Alternate server hostname            =
 Alternate server port number         =


この例では(いずれもローカルサーバー内の)JSONDB と MYDB という2つのデータベースエイリアスが登録されていました。この例ではリモートサーバーのエイリアスは登録されていません。


エイリアスの登録

では先程作成した dashdb ノード上の接続先データベース(BLUDB)を "remotedb" という名前でエイリアス登録します:
$ db2 catalog database BLUDB as remotedb at node dashdb
DB20000I  The CATALOG DATABASE command completed successfully.
DB21056W  Directory changes may not be effective until the directory cache is
refreshed.

成功したようです。念の為もう1回エイリアス一覧を確認します:
$ db2 list db directory

 System Database Directory

 Number of entries in the directory = 3

Database 1 entry:

 Database alias                       = REMOTEDB
 Database name                        = BLUDB
 Node name                            = DASHDB
 Database release level               = 14.00
 Comment                              =
 Directory entry type                 = Remote
 Catalog database partition number    = -1
 Alternate server hostname            =
 Alternate server port number         =

Database 2 entry:

 Database alias                       = JSONDB
 Database name                        = JSONDB
 Local database directory             = /home/db2inst1
 Database release level               = 14.00
 Comment                              =
 Directory entry type                 = Indirect
 Catalog database partition number    = 0
 Alternate server hostname            =
 Alternate server port number         =

Database 3 entry:

 Database alias                       = MYDB
 Database name                        = MYDB
 Local database directory             = /home/db2inst1
 Database release level               = 14.00
 Comment                              =
 Directory entry type                 = Indirect
 Catalog database partition number    = 0
 Alternate server hostname            =
 Alternate server port number         =


エイリアスが2つから3つに増え、REMOTEDB が新たに登録されました。


エイリアスを削除

この作業も今回は不要ですが、登録したエイリアスを削除する場合はエイリアス名を指定して次のように実行します:
$ db2 uncatalog db remotedb


エイリアスを指定して接続

では改めてエイリアスを作ったデータベースに接続します。接続時にはユーザー名とパスワードが必要になるので、以下のように指定します:
$ db2 connect to remotedb user lrz77612 using xxxxxxxx

   Database Connection Information

 Database server        = DB2/LINUXX8664 11.1.2.2
 SQL authorization ID   = LRZ77612
 Local database alias   = REMOTEDB

IBM Cloud 上のデータベースに接続できました。後はこのリモートデータベースに対して各種 SQL を実行してテーブルやデータの作成/更新/削除/検索といったコマンドが実行できます。


接続しているエイリアスから切断

なお、接続しているエイリアスから切断する場合は以下のコマンドを実行します:
$ db2 terminate




IBM Bluemix からも提供されている IBM の DBaaS サービスである dashDB に Node.js からアクセスする方法を紹介します。実際には dashDB だけでなく、DB2 のサービスやオンプレミスデータベースへも同様に応用できますが、今回は Bluemix 上の DB2/dashDB 関連サービスを例に紹介します:
2017063002


dashDB は行指向/列指向型のテーブルをどちらも作成することができるリレーショナル・データベースのサービスですが、そのデータベースシステムとしての実体は IBM DB2 です。というわけで、このライブラリを使ってアクセスします:
https://www.npmjs.com/package/ibm_db

2017063001


まず以下のコマンドを実行して ibm_db をインストールします(このコマンドだけで DB2 ODBC Driver ごとインストールされます):
$ npm install ibm_db


そして以下のようなコードを用意して dashDB にアクセスします:

(settings.js)
exports.db_host = 'dashdb-entry-yp-XXXXXXXX.services.dal.bluemix.net';
exports.db_port = 50000;
exports.db_name = 'BLUDB';
exports.db_username = 'dashNNNN';
exports.db_password = 'PASSWORD';

(sample.js)
var ibm_db = require( 'ibm_db' );
var settings = require( './settings' );

var db_str = "DATABASE=" + settings.db_name
  + ";HOSTNAME=" + settings.db_host
  + ";UID=" + settings.db_username
  + ";PWD=" + settings.db_password
  + ";PORT=" + settings.db_port
  + ";PROTOCOL=TCPIP";
var sql = "select OBJECTID, NAME from SAMPLES.GEO_CUSTOMER limit 10";

ibm_db.open( db_str, function( err, conn ){
  if( err ) return console.log( err );

  conn.query( sql, function( err, data ){
    if( err ) console.log( err );
    else console.log( data );

    conn.close( function(){
      console.log( 'done.' );
    });
  });
});

settings.js の中身はユーザー名やパスワードといった dashDB に接続するためのサービス資格情報です。IBM Bluemix の画面から取得できる値を使って、実際の値で書き換えて使ってください:

2017063003


アプリケーションの実体は sample.js です。今回の例ではシンプルに接続して、サンプルデータとして GEO_CUSTOMER テーブルから OBJECTID と NAME の値を 10 件だけ取得する、という SQL (青字部分)を実行しました。また settings.js で定義した情報を取り出して接続文字列(赤字部分)を生成しています。

node コマンドで sample.js を実行して、以下のような結果が表示されれば成功です:
$ node sample.js
[ { OBJECTID: 1322, NAME: 'Kami Labarbera' },
  { OBJECTID: 1323, NAME: 'Johnathon Tunney' },
     :
  { OBJECTID: 1587, NAME: 'Althea Alcazar' } ]
done.







 

このページのトップヘ