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

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

タグ:mongodb

IBM Cloud から提供されている 30 日間無料 Kubernetes サービスIBM Kubernetes Service 、以下 "IKS")環境を使って利用することのできるコンテナイメージを1日に1個ずつ 30 日間連続で紹介していきます。

環境のセットアップや制約事項については Day0 のこちらの記事を参照してください。

Day 6 からはデータベース系コンテナとその GUI ツールを中心に紹介してます。Day 10 では NoSQL データベースを代表する MongoDB イメージをデプロイする例を紹介します。
mongodb



【イメージの概要】
高速なデータ格納処理を得意とする分散データベース環境です。RDB の SQL のような高度な検索や結合処理を苦手とする一方で、追加・更新・削除といった変更系作業を非常に高速に行うことができるため、IoT などの短時間で大量の書き込み処理を行うケースに向いています。

開発および製品サポートは MongoDB Inc. が行っています。


【イメージのデプロイ】
まずはこちらのファイルを自分の PC にダウンロードしてください:
https://raw.githubusercontent.com/dotnsf/yamls_for_iks/main/mongodb.yaml


次にこのファイルをテキストエディタで開いてパラメータを編集します。具体的には "MONGO_" で始まる3箇所の env.name の value 値を変更してください。それぞれの具体的な意味は以下の通りです(初期値として指定されている値のまま動かすことも可能ですが、安全のためなるべく変更してください):
・MONGO_INITDB_ROOT_USERNAME : 管理者ID(初期値 root)
・MONGO_INITDB_ROOT_PASSWORD : 管理者パスワード(初期値 P@ssw0rd)
・MONGO_INITDB_DATABASE : デプロイと同時に作成するデータベース(初期値 mydb)

ではこのダウンロード&編集した mongodb.yaml ファイルを指定してデプロイします。以下のコマンドを実行する前に Day 0 の内容を参照して ibmcloud CLI ツールで IBM Cloud にログインし、クラスタに接続するまでを済ませておいてください。

そして以下のコマンドを実行します:
$ kubectl apply -f mongodb.yaml

以下のコマンドで MongoDB 関連の Deployment, Service, Pod, Replicaset が1つずつ生成されたことと、サービスが 30017 番ポートで公開されていることを確認します:
$ kubectl get all

NAME                         READY   STATUS    RESTARTS   AGE
pod/mongo-65cb95c444-xkgx9   1/1     Running   0          2m48s

NAME                  TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)           AGE
service/kubernetes    ClusterIP   172.21.0.1      <none>        443/TCP           27d
service/mongoserver   NodePort    172.21.93.229   <none>        27017:30017/TCP   2m49s

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/mongo   1/1     1            1           2m49s

NAME                               DESIRED   CURRENT   READY   AGE
replicaset.apps/mongo-65cb95c444   1         1         1       2m49s

この後に実際にサービスを利用するため、以下のコマンドでワーカーノードのパブリック IP アドレスを確認します(以下の例であれば 161.51.204.190):
$ ibmcloud ks worker ls --cluster=mycluster-free
OK
ID                                                       パブリック IP    プライベート IP   フレーバー   状態     状況    ゾーン   バージョン
kube-c3biujbf074rs3rl76t0-myclusterfr-default-000000df   169.51.204.190   10.144.185.144    free         normal   Ready   mil01    1.20.7_1543*

つまりこの時点で(上述の結果であれば)アプリケーションは 169.51.204.190:30017 で稼働している、ということになります。これまでの例と同様、動作確認は次回の GUI ツールのインストール後に行うことにするので、今回はこのデプロイ作業までとします。



【YAML ファイルの解説】
YAML ファイルはこちらを使っています(編集する前の状態です):
apiVersion: v1
kind: Service
metadata:
  name: mongoserver
spec:
  selector:
    app: mongo
  ports:
  - port: 27017
    protocol: TCP
    targetPort: 27017
    nodePort: 30017
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mongo
  template:
    metadata:
      labels:
        app: mongo
    spec:
      containers:
      - name: mongo
        image: mongo
        env:
        - name: MONGO_INITDB_ROOT_USERNAME
          value: "root"
        - name: MONGO_INITDB_ROOT_PASSWORD
          value: "Passw0rd"
        - name: MONGO_INITDB_DATABASE
          value: "mydb"
        ports:
        - containerPort: 27017

Deployment 1つと、Service 1つのごくごくシンプルな YAML ファイルですが、一応解説を加えておきます。アプリケーションそのものは 27017 番ポートで動作するように作られているため、NodePort 30017 番を指定して、外部からは 30017 番ポートでアクセスできるようにしています(NodePort として指定可能な番号の範囲は 30000 ~ 32767 です、指定しない場合は空いている番号がランダムに割り振られます)。また ReplicaSet は1つだけで作りました(データベースなので、別途クラスタ構成の準備をしない限りはこの数値だけを増やしてもあまり意味ないと思います)。


デプロイしたコンテナイメージを削除する場合はデプロイ時に使った YAML ファイルを再度使って、以下のコマンドを実行します。不要であれば削除しておきましょう(ちなみにこの MongoDB コンテナは明日の Day 11 でも使う予定なので、削除するのはそのあとの方がいいかもしれません):
$ kubectl delete -f mongodb.yaml


【紹介したイメージ】
https://hub.docker.com/_/mongo


【紹介記録】
Dayカテゴリーデプロイ内容
0準備準備作業
1ウェブサーバーhostname
2Apache HTTP
3Nginx
4Tomcat
5Websphere Liberty
6データベースMySQL
7phpMyAdmin
8PostgreSQL
9pgAdmin4
10MongoDB
11Mongo-Express
12Redis
13RedisCommander
14ElasticSearch
15Kibana
16CouchDB
17CouchBase
18HATOYA
19プログラミングNode-RED
20Scratch
21Eclipse Orion
22Swagger Editor
23R Studio
24Jenkins
25アプリケーションFX
262048
27DOS Box
28VNC Server(Lubuntu)
29Drupal
30WordPress

IBM DB2 V10.5 ではテクノロジープレビューという正式サポート前の扱いですが、NoSQL 機能が使えるようになっています。

これは MongoDB のような JSON オブジェクトストア機能であり、実際に MongoDB のコマンドラインクライアントからも利用することができます。

このテクノロジープレビュー機能を有効にして、実際に使ってみるまでの手順を紹介します。なお環境は CentOS 6(64bit) 版を前提とします。


まず IBM DB2 V10.5 を導入します。DB2 は無償版の Express-C エディションが提供されているのでそれを使います。詳しい手順はこちらのエントリを参照ください(エントリはバージョン10.1での説明ですが、2015年1月5日現在、同じ手順で最新のバージョン10.5がダウンロード&導入できます):
DB2 Express-C (10.1) を CentOS にインストール&セットアップする


併せて MongoDB を導入します。詳しい手順はこちらを参照ください(この手順では MongoDB サーバーも導入されますが、今回はクライアントのみ使います):
mongoDB を CentOS 上にインストールする


最後に DB2 の NoSQL 機能を有効化する手順の中で JRE が必要になるため、Java 実行環境を導入します:
# yum install java-1.7.0-openjdk


ここまでの準備ができたら実際に DB2 の NoSQL 機能のセットアップを行います。システム上で db2inst1 ユーザーに切り替えて、NoSQL 用のデータベース jsondb をコードセット UTF-8、テリトリー jp で作成します(異なる内容で作成する場合はコマンドの赤字部分を該当内容に合わせて変更してください):
# su - db2inst1
$ db2 create database jsondb automatic storage yes using codeset utf-8 territory jp collate using system

しばらく待つと NoSQL データベース jsondb が作成されます。プロンプトが戻ったら続けて DB2 のポートを開きます。そして DB2 を再起動(ストップ&スタート)して、この内容を反映させます:
$ db2set DB2COMM=TCPIP
$ db2 update dbm cfg using svcename 50000
$ db2stop
$ db2start

そして db2inst1 ユーザーの ~/.bashrc を開いて編集し、環境変数の設定を行います:
$ vi ~/.bashrc
  :
  :
(最後に以下を追加して保存)
export JAVA_HOME=/usr/lib/jvm/jre-1.7.0-openjdk.x86_64
export PATH=$PATH:/opt/ibm/db2/V10.5/json/bin
export CLASSPATH=$CLASSPATH:/opt/ibm/db2/V10.5/json/lib/nosqljson.jar:/opt/ibm/db2/V10.5/json/lib/mongo-2.8.0.jar:/opt/ibm/db2/V10.5/json/lib/js.jar:/opt/ibm/db2/V10.5/json/lib/db2NoSQLWireListener.jar

上記で作成した jsondb データベースは初期状態では無効になっているので、コマンドラインから有効になるよう指定します。改めて db2inst1 ユーザーでログインし(或いは上記の ~/.bashrc の変更を反映し)、以下のコマンドを実行します:
# su - db2inst1
$ cd /opt/ibm/db2/V10.5/json/bin
$ ./db2nosql.sh -user db2inst1 -hostName localhost -port 50000 -db jsondb -setup enable -password (db2inst1ユーザーのパスワード)

最後に通信リスナーを MongoDB と同じ 27017 番ポートで起動します(db2inst1 ユーザーで、/opt/ibm/db2/V10.5/json/bin ディレクトリ上で実行する必要があります):
$ cd /opt/ibm/db2/V10.5/json/bin
$ ./wplistener.sh -start -mongoPort 27017 -userid db2inst1 -password (db2inst1ユーザーのパスワード) -dbName jsondb -logPath /tmp

   :
--- The wire listener is being started ---
Starting the channel listener on port 27017

上記のように、画面に "Starting the chennel listener on port 27017" と表示されれば DB2 の NoSQL データベース機能の起動に成功しています。


最後に動作確認の意味で、この DB2 上で動いている NoSQL データベース jsondb に、MongoDB クライアントから接続してみましょう。同じシステム上の別端末を開いて、mongo コマンド(MongoDB クライアント)を実行してみます(青字はシステムからの出力結果です):
# mongo
MongoDB shell version: 2.6.6
connecting to: test
>

エラーが表示されていなければ接続できたことになります。続けて jsondb データベースに接続して、myfirstcollection コレクションに "_id" = 100 の JSON 文書を作成/更新/検索してみます:
> use jsondb (DB変更)
switched to db jsondb
> db.myfirstcollection.insert( { "_id":100, "name":"K.Kimura" } ) (文書作成)
Cannot use commands write mode, degrading to compatibility mode
WriteResult({ "nInserted" : 1 })
> db.myfirstcollection.findOne() (検索)
{ "_id" : 100, "name" : "K.Kimura" } (成功)
> db.myfirstcollection.update( { "_id":100 }, {"name":"Kei KIMURA" } ) (更新)
WriteResult({ "nMatched" : 1, "nUpserted" : 0 }) (成功)
> db.myfirstcollection.findOne() (再検索)
{ "_id" : 100, "name" : "Kei KIMURA" } (成功)
  :
  :
> quit()
#

MongoDB クライアントからの一通りのコマンドは全て成功しているようです。


mongo の基本的なコマンドに関しては全て動いているようですが、どの程度の互換性があるのか/ないのか、MongoDB のライブラリが使えるのか/使えないのか、まだちょっとわかりません。 でもこれが使えるようであれば、PHP から MongoDB ライブラリを経由して DB2 にアクセスする、といった、これまでできなかったような使い方も広がってくると思います。この機能が正式サポートされるのが楽しみです。




(参考)
http://www.ibm.com/developerworks/jp/data/library/techarticle/dm-1306nosqlforjson4/
 

謎だった Power 版 RHEL(RedHat Enterprise Linux) での MongoDB の動かし方が分かりました!

これまでは「CPU のエンディアンの違いにより MongoDB が動かなかった」と思っていたのですが、IBM のダウンロードサイトで Power 版 RHEL 向けビルド済み rpm パッケージの存在を確認しました。これを使います。


まず準備段階として Power 版 RHEL 環境を用意します。・・・といっても普通の人はそんな環境持ってないですよね(苦笑)。 2週間のお試し程度であれば、開発者向けサービスである IBM Power Development Cloud を利用して環境を構築することも可能です。 その場合の手順はこちらのブログエントリを参照ください:


Power 版 RHEL の準備ができたら早速 MongoDB を導入しましょう。といっても特別な作業ではなく、必要な rpm パッケージを IBM からダウンロードしてインストールするだけです。Intel 版 RHEL と異なるのはファイル名のアーキテクチャ部分が i686 とか x86_64 とかではなく、ppc64 になっていることくらいです。あと現在用意されている MongoDB はバージョン 2.4.9(RC0) のようです:
# cd /tmp
# yum install wget boost-devel
# wget ftp://ftp.software.ibm.com/linux/rpms/redhat/6.5/v8-3.14.5.10-2.el6.ppc64.rpm
# wget ftp://ftp.software.ibm.com/linux/rpms/redhat/6.5/libmongodb-2.4.9-1.el6.ppc64.rpm
# wget ftp://ftp.software.ibm.com/linux/rpms/redhat/6.5/mongodb-server-2.4.9-1.el6.ppc64.rpm
# wget ftp://ftp.software.ibm.com/linux/rpms/redhat/6.5/mongodb-2.4.9-1.el6.ppc64.rpm
# rpm -ivh v8-3.14.5.10-2.el6.ppc64.rpm
# rpm -ivh libmongodb-2.4.9-1.el6.ppc64.rpm
# rpm -ivh mongodb-server-2.4.9-1.el6.ppc64.rpm
# rpm -ivh mongodb-2.4.9-1.el6.ppc64.rpm

これで MongoDB のインストールは完了です。念のため、導入先を確認しておきましょう:
# which mongod
/usr/bin/mongod
# which mongo
/usr/bin/mongo

MongoDB の起動はコマンドラインから、以下の内容を実行します:
# mongod --dbpath /var/lib/mongodb

実行するとサーバーコンソールのようにメッセージがずらずらと・・・出てくればサービスの起動成功です。ちなみにサービスの終了は CTRL + C です。
2014121001


Mongo クライアントは何の違いも感じずに使えます:
2014121002


この Power 版 RHEL 向け MongoDB はいつから用意されてたんだろう? ともあれ、これで Power 版の RHEL でも MongoDB が動くことが確認できました。本当に Intel 版との違いがなくなりつつあることを実感します。


そして、これはつまり MongoDB に対応したフレームワーク(cakePHPとか)を Power 版 RHEL で動かすことができるようになったのかな?? とも思っているのですが、実際 cakePHP で使ってみると Intel 版では見たことのないエラーメッセージに遭遇したりして、まだもう少し待った方がいいのかな、とも思ってたりします。要はちゃんと動かして調べましょう、ということで。


最後に、自分が業務で開発に携わっている公開済みサービスがこの Power 版 RHEL 環境でもある程度動いたので記念アップ!
2014121003

 

PHP で MongoDB を使っていると、「その中身を簡単に確認したい!」と思うことがままあります。

MySQL であれば phpMyAdmin など、有名なツールがいくつかありますが、MongoDB の場合は数が限られてい(るように思い)ます。

そんな中で自分が使っているのが phpMoAdmin です。phpMyAdmin と名前が似ていますが、おそらく意識しているのでしょう。

phpMoAdmin はダウンロード&展開するとわかりますが、 moadmin.php という1つの .php ファイルから作られている MongoDB 管理用GUIツールです。ファイル1つなので、このファイルをドキュメントルート以下におくだけで設置完了です。

なお、接続先の MongoDB サーバーの情報もこのファイルの中に直書きします(何も指定しないとローカルホスト状の MongoDB を参照しに行きます)。
例えば MongoDB サーバーがリモートの mongo.test.com というサーバーで、デフォルトの 27017 番ポートで稼働している場合、この moadmin.php ファイルをエディタで開いて 'MONGO_CONNECTION' の値として以下のように記述して保存します:
  define( 'MONGO_CONNECTION', 'mongodb://mongo.test.com:27017' );

これでウェブブラウザからこの moadmin.php を開けば、目的の MongoDB サーバーにアクセスして、コレクションやレコードの状態を参照することができるようになります。


ところで、MongoDB を使っていると大量のデータを扱うことが少なくありません(そのための No-SQL だと思っています)。コレクション(RDB でいう所のテーブル)を指定して、そのレコードの一覧を参照することは簡単ですが、特定の条件を満たすレコードだけを取り出して見ることはできないでしょうか? それが今から紹介するクエリー(Query)機能です。

クエリーを実行するには、コレクションのレコード一覧の画面から "[query]" と書かれた箇所をクリックします:
2014101601

するとクエリーを指定するフィールドが開きます。ここに目的のレコードに絞り込むクエリーを記述して "Query" をクリックすることでレコードを選別することができます。
2014101602


さて、意外と戸惑ったのが、このクエリーの指定方法です。例えば「item_id の値が'14'のレコード」を探したい場合、どのように指定すればいいのでしょうか?意外と資料や情報が少なくて難儀しました。

結論としては CakePHP の find の中で指定するような感覚で、以下のように記載します:
 array('item_id'=>'14')
2014101603

無事見つかりました。同様にして「item_id が '14' で、category_id が '10' のレコード」であればこんな感じになります:
 array('item_id'=>'14','category_id'=>'10')


注意が必要な点として、どうやらこのクエリーで数値を指定する場合、そのデータが数値文字列なのか、数値なのかを意識して指定する必要がありそう、ということです。例えば先程の例を
 array('item_id'=>14)
のように 14 を数値文字列ではなく数値として指定した場合、レコードは見つかりませんでした。
2014101604


要するにデータがどのような型で格納されているのかをちゃんと意識して指定する必要があるのだと思います。

このあたりを気をつけていれば軽量で使える便利なツールといえそうです。


 

NoSQL データベースの1つで、非構造データを JSON 形式で保持できる mongoDB を「レプリカセット」と呼ばれる方法でクラスタリングします。

今回は3台の CentOS マシンによるクラスタ構成を行います。1台がプライマリ、1台がスレーブ、そして1台がアービターと呼ばれるフェイルオーバー時のマスター選択専用ノード(データは保持しない)で構成します。


プライマリ/スレーブ/アービターそれぞれのマシンの IP アドレスは P.P.P.P / S.S.S.S / A.A.A.A であると仮定して以下を記載します。


まず、3台のマシンそれぞれに MongoDB をインストールします。MongoDB の導入手順にそのものについては以下を参照してください:
mongoDB を CentOS 上にインストールする

上記手順最後のコマンド "chkconfig mongod on" までが実行されていれば、3台のマシン上それぞれで MongoDB が(独立して)稼働している状態になっています。


ここからがレプリカセット環境構築のための設定になります。まずそれぞれのマシン上で /etc/mongod.conf を編集します。編集内容は2点で (1) bind_ip 行をコメントアウト、 (2) replSet 行を追加 します:
# vi /etc/mongod.conf
  :
  :
# bind_ip=127.0.0.1 (コメントアウト)
  :
  :
replSet=testRS (この1行を追加)
  :
  :
なお、replSet=XXX で追加する行の XXX 部分は同じ文字列(上記例では testRS )を指定します。これによって3台の mongoDB サーガーが同一のレプリカセット環境上にあることを指定します。

bind_ip 行は接続を受け付ける元のアドレス範囲を指定する行です。127.0.0.1 が指定されていると localhost のみが指定されたことになり、他のマシンからの接続を受け付けなくなってしまうのでコメントアウトします。

ここまで出来た所で、3台のマシンそれぞれで mongoDB を再起動します:
# /etc/init.d/mongod restart


次にプライマリサーバー(P.P.P.P) 上で、各マシンの役割を指定します。プライマリサーバー上でコンソールにログインします:
# mongo

> 

コンソール画面内で以下を実行します:
> config = { _id:"testRS", 
  members:[
    { _id:0, host:"A.A.A.A:27017", arbiterOnly:true }, 
    { _id:1, host:"P.P.P.P:27017" },
    { _id:2, host:"S.S.S.S:27017" }
  ]
}
 :
:
> rs.initiate( config ) :
:
>

上記コマンドで testRS(replSet に指定した文字列値)に属する3台のマシンの IP アドレスとポート番号を指定し、A.A.A.A のマシンについてはアービターのノードであることも指示しています。 そしてその内容を rs.initiate コマンドで実行して初期化しています。

これが成功するとレプリカセットの完成です。rs.status() コマンドでレプリカセットの設定状況を確認することもできます:
> rs.status()
{
  "set": "testRS",
  "date": ISODate("2014-06-02T12:34:56Z"),
  "myState": 1,
  "members": [
    {
      "_id": 0,
      "name": "A.A.A.A:27017",
      "health": 1,
      "state": 7,
      "stateStr": "ARBITER",
      "uptime": 30,
      "lastHeartbeat": ISODate("2014-06-02T12:34:56Z"),
      "pingMs": 1
    },
    {
      "_id": 1,
      "name": "P.P.P.P:27017",
      "health": 1,
      "state": 1,
      "stateStr": "PRIMARY",
      "uptime": 80,
      "optime": Timestamp(1357209986000, 1),
      "optimeDate" : ISODate("2014-06-02T12:34:56Z"),
      "self": true
    },
    {
      "_id": 2,
      "name": "S.S.S.S:27017",
      "health": 1,
      "state": 2,
      "stateStr": "SECONDARY",
      "uptime": 30,
      "optime": Timestamp(1357209986000, 1),
      "optimeDate" : ISODate("2014-06-02T12:34:56Z"),
      "lastHeartbeat": ISODate("2014-06-02T12:34:56Z"),
      "pingMs": 1
    }
  ],
  "ok": 1 
}

> 

_id = 0 のマシンがアービター、1 のマシンがプライマリ、2 のマシンがスレーブになっていることを確認します。


一応これでレプリカセット環境としては動くようになりました。が、このままだとスレーブサーバーはプライマリサーバー以外のマシンからの接続を許可しないため色々不便です。というわけで、最後にスレーブサーバーにプライバリサーバー以外からも接続できるよう設定します。

スレーブサーバー上でコンソールにログインし、db.getMongo().setSlaveOk() コマンドを実行します:
# mongo

> db.getMongo().setSlaveOk()

>

これでスレーブサーバーに他のマシンから接続して状況を確認することもできるようになりました。




このページのトップヘ