docker
kubernetes
node-red
ibmcloud

Node-REDが動作するコンテナをビルドして Kubernetes で実行するまでを解説 (3/3)

この記事は、Node-REDのコンテナをビルドして、Kubernetesの上で他のサービスと連携させるまでの道のり解説の最終回です。 前回までに作ったNode-REDのコンテナをKubernetesにデプロイして、Cloudant、MySQL、REST APIの動作について、進めていきます。

Node-REDのコンテナのビルド、DockerHubへの登録は、Node-RED v0.18が動作するコンテナをビルドして Kubernetes で実行するまでを解説 (1/3)に解説しました。

そして、Node-REDコンテナから、IBM Cloudのサービスや、同じコンテナの CloudantやMySQLサーバーとの連携は、第2回目 Node-REDが動作するコンテナをビルドして Kubernetes で実行するまでを解説 (2/3) で解説しました。

第3回目は、無料で利用できるIBM Cloud Container Service (Kubernetes)のライトプランでの利用方法です。

無料で利用できるKubernetesのデプロイ

IBM Cloud にログインして、Container Serviceをクリックして、Kubernetesのクラスタのオーダー画面を開きます。

無料で利用できるk8sクラスタのオーダー

Regionによっては、無料プランを利用できない場所もある様です。 この例では米国南部を選択して、クラスタ・タイプに無料を選択しました。

スクリーンショット 2018-03-12 0.14.50.png

Cluster name に名前をセットして、「クラスターの作成」をクリックして先へ進めます。 無料プランでは、ノードは1個に制限されています。また、ロードバランサーや永続ストレージも利用できないので、お試し用という位置づけです。 しかし、Node-REDの開発であれば十分利用できますので、無料プランで進めていきます。

デプロイ中画面

Kubernetesを利用できる様セットアップするには、ユーザー専用のマスタとノードを起動する必要があり、およそ20分〜30分くらい時間がかかります。 準備作業中は、プロビジョニング中と表示されていますので、待ちます。

スクリーンショット 2018-03-12 0.17.00.png

準備完了状態

準備が完了したら次の画面の様に、状態欄に「準備完了」と表示されます。

スクリーンショット 2018-03-12 7.43.41.png

kubectl コマンドのセットアップ

これで、Kubernetesを利用するクラウド側の準備が完了しました。 Kubernetesの利用には、コマンド・ライン・インタフェースが必須になりますので、以下2つのコマンドをインストールして、ログインします。

k8sの利用には必須のプラグインをインストールします。 このプラグインのサブコマンドで、k8sより下層部分の設定を行います。

bx plugin install container-service -r Bluemix

IBM Cloudにログインして、米国南部(us-south)のリージョンをセットします。

bx login -a https://api.ng.bluemix.net
bx cs region-set us-south

kubectlコマンドの認証情報をダウンロードするために、次のコマンドを実行します。 コマンドが正常終了すると、KUBECONFIG=から始まる環境変数の雛形を表示しますので、コピペして環境変数にセットします。

bx cs cluster-config mycluster1

上記の操作で、kubectlが利用できる様になりました。 IBM Cloud 上の k8sマスタと接続ができるか、確認してみます。 次のコマンドでノードのリストを表示できます。 ライトプランですから、1個しかありません。 IPアドレスは、旧SoftLayerで良く知られた、プライベート側IPアドレスで、ユーザー専用のネットワークになります。 このIPを公開しても、他のユーザーは、一般のルートから、このアドレスへ到達できません。

kubectl get node
NAME            STATUS    ROLES     AGE       VERSION
10.76.193.109   Ready     <none>    8h        v1.8.8-2+9d6e0610086578

Node-REDコンテナ を k8s上にデプロイ

ここまでの作業で、kubectlコマンドが利用できる様になりましたので、k8sへコンテナをデプロイするためのYAMLのファイルを作成して、適用していきます。

YAMLファイルの作成

次は、Node-REDのコンテナをデプロイするためのYAMLです。 image項目のフィールに、DockerHubに登録したコンテナのイメージを入れます。それ以外は、そのまま、利用します。

node-red-depoy.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: node-red
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: node-red
    spec:
      containers:
      - name: node-red
        image: maho/node-red:1.0
        ports:
        - containerPort: 1880

kubectl create -f ファイル名 でファイルを適用します。 これでNode-REDコンテナを動作させるポッドが1個起動します。

kubectl create -f node-red-depoy.yaml

起動の確認には、kubectl get deploy node-red を利用します。 AVAILABLEの値が1になれば、起動完了です。

$ kubectl get deploy node-red
NAME       DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
node-red   1         1         1            1           1h

ここまでの状態では、k8sのクラスタネットワーク上だけに、コンテナを内包するポッドが繋がった状態ですから、どこからもアクセスできません。そこで、次のYAMLファイルを利用して、ポッドをホストしているノードにアクセスポートを開きます。 nodePortの値で 31880 が外部に解放されるNode-REDのポート番号になります。

node-red-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: node-red
spec:
  type: NodePort
  selector:
    app: node-red
  ports:
  - protocol: TCP
    port: 1880
    nodePort: 31880

次のコマンドで、YAMLファイルを適用して、NodePortサービスを開始します。

kubectl create -f node-red-nodeport.yaml

公開先IPアドレスの確認

NodePortは、コンテナをホストするノードのIPアドレスを利用して、ポートを開いて、アクセスを提供するというものです。 そこで、ノードのパブリックIPアドレスを調べます。 これには、プラグインとして追加した bx cs サブコマンドを利用していきます。 はじめに、k8sのクラスターの名前を取得します。

imac:k8s maho$ bx cs clusters
OK
Name         ID                                 State    Created        Workers   Location   Version   
mycluster1   890f1e136a2f4054854059fa70ea0fca   normal   10 hours ago   1         hou02      1.8.8_1507   

次に、クラスタ名を指定して、workersで、ノードのリストを表示します。 k8sのプロジェクトでは、コンテナをホストするサーバーを単なるノードと読んでいるのですが、IBM Cloudeでは、同じノードを Worker node という呼び方をしているので、混乱しない様に覚えていると良いでしょう。

Public IPの欄にあるIPアドレスが、外部のインターネットからアクセスできるIPアドレスになります。

imac:k8s maho$ bx cs workers mycluster1
OK
ID                                                 Public IP        Private IP      Machine Type   State    Status   Zone    Version   
kube-hou02-pa890f1e136a2f4054854059fa70ea0fca-w1   173.193.xxx.yyy   10.76.193.109   free           normal   Ready    hou02   1.8.8_1507   

k8s上のNode-REDコンテナへアクセス

ここまでで、ノードのIPアドレス、ポート番号が解りましたので、ブラウザからアクセスしてみます。 次の様なログイン画面が出てくれば成功です。
ユーザーIDとパスワードは、第一回目に記述していますので、参照願います。ログインして、先へ進めていきます。

スクリーンショット 2018-03-12 10.25.31.png

現在のところ、ユーザーIDやパスワードを変更するには、設定ファイルにユーザーIDとパスワードのハッシュが書き込まれているため、コンテナの再ビルドが必要になります。 プロジェクトで利用する場合などは、Node-REDコンテナの再ビルドを検討してください。

k8s上のCloudantなど他のサービスと連動

ここまでで、Node-REDのコンテナが、k8sで動作する事が確認できましたので、次は、Node-REDとサービスと連携させていきます。 具体的なイメージは、次の図の様になります、 前章で立ち上げたのが、図中真ん中付近の、Node-REDコンテナとNodePortサービスになります。次に、ここから、CoudantのコンテナとClusterIPサービスを起動して、連携させます。

スクリーンショット 2018-03-12 10.58.52.png

Cloudantコンテナのデプロイ

Cloudantのコンテナをk8sの上にデプロイして、他のデプロイメント(コンテナ)と連携できる様に、ClusterIPのサービスを起動します。

次のYAMLがCloudantのサーバーを起動するための定義です。 spec.containes.imageの値であるibmcom/cloudant-developer:2.0.1は、DockerHubに登録されているコンテナのイメージです。

cloudant-deploy.yml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: cloudant
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: cloudant
    spec:
      containers:
      - name: cloudant
        image: ibmcom/cloudant-developer:2.0.1
        ports:
        - containerPort: 80

Node-REDのコンテナと同様に、YAMLを提供して起動します。

$ kubectl create -f cloudant-deploy.yml 

次のコマンドで起動を書くにします。 前回同様にAVAILABLEが 1 になれば、起動完了です。

$ kubectl get deploy cloudant
NAME       DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
cloudant   1         1         1            1           1h

そして、Node-REDのコンテナからCloudantoをアクセスできる様にサービスを立ち上げます。 前回は外部に公開するものでしたが、今回は、spec.typeの値が ClusterIPとなっており、内部に公開するためのサービスです。

cloudant-service.yml
apiVersion: v1
kind: Service
metadata:
  name: cloudant
spec:
  type: ClusterIP
  selector:
    app: cloudant
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 80

次のコマンドでk8sクラスタに適用します。 この適用によって、k8s内で動作するDNSに登録され、CloudantのDNS名でアクセスできる様になりますので、Node-REDに設定する場合は、k8sのDNS名で登録します。

$ kubectl create -f cloudant-service.yml 

サービスの起動は、次のコマンドで確認できます。 元のコンテナが解放するポート番号は80番でしたが、サービスで8080番に変換して提供します。

$ kubectl get svc cloudant
NAME       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
cloudant   ClusterIP   172.21.175.93   <none>        8080/TCP   28m

疎通確認

ここでNode-REDのコンテナ(ポッド)にログインして、curlコマンド、Cloudantへアクセスできるか確認してみます。 必須の作業ではありませんから、参考程度に見てください。 興味があれば、kubectl get nodesでCloudantのポッド名を調べて、ポッド名を置き換えて実行します。そして、curlコマンドで、http://cloudant:8080/ で Welcomeが帰ってくれば、疎通確認完了です。

$ kubectl exec -it node-red-64d45cfd95-nzx57 sh
/node-red # curl http://cloudant:8080/
{"couchdb":"Welcome","version":"2.0.0","vendor":{"name":"IBM Cloudant","version":"1.1.0","variant":"local"},"features":["geo"]}

Cloudantノードへの設定

k8sのNode-REDコンテナをアクセスして、フローエディタで、次の様にCloudantのノードを配置します。 TimestampノードとCloudantノードに空のFunctionノードを置く理由は、Cloudantにデータベースが作成されていない場合、自動的にFunctionがデータベースを作成してくれるためです。

Cloudantのノードをダブルクリックして、プロパティを設定していきます。 Serverの行の「えんぴつ」マークをクリックして、ホスト名などを設定します。 パスワードなどは、第2回目で記載していますので参照をお願いします。

スクリーンショット 2018-03-12 12.58.33.png

ここで、ホスト名は、http://cloudant:8080/ とします。CloudantがRESTサービスであるので、URLのインプットが想定されているためです。 cloudantは、先に起動したcludantのサービス名で、Node-REDのコンテナからkube-dnsを介して、アドレスが解決されます。

スクリーンショット 2018-03-12 12.58.46.png

Node-REDとCloudantの連携テスト

ここまでで、Node-REDコンテナとCloudantコンテナの連携の設定が完了したので、テストします。 次のフローは、Timestampノードをクリックして、デバック・ウィンドに、タイムスタンプの値が表示されると同時に、Cloudantへ登録されるものです。

スクリーンショット 2018-03-12 13.08.47.png

Cloudant 管理画面を見るための設定

上記の操作で、正しく、Cloudantへデータが登録されているか、Cloudantの管理コンソールにアクセスして確かめたいと思います。 インターネット越しにアクセスできる様するには、次のYAMLでNodePortの設定を加えます。 これによって、nodePortの値、31080で Cloudantの管理画面のポートが開きます。

cloudant-nodeport.yml
cloudant-nodeport.yml 
apiVersion: v1
kind: Service
metadata:
  name: cloudant-nodeport
spec:
  type: NodePort
  selector:
    app: cloudant
  ports:
  - protocol: TCP
    port: 80
    nodePort: 31080

次のコマンドで適用します。

$ kubectl create -f cloudant-nodeportyml 

設定の確認を実施ます。

$ kubectl get svc cloudant-nodeport
NAME                TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
cloudant-nodeport   NodePort   172.21.182.158   <none>        80:31080/TCP   38m

$ kubectl get node
NAME            STATUS    ROLES     AGE       VERSION
10.76.193.109   Ready     <none>    12h       v1.8.8-2+9d6e0610086578

$ bx cs workers mycluster1
OK
ID                                                 Public IP        Private IP      Machine Type   State    Status   Zone    Version   
kube-hou02-pa890f1e136a2f4054854059fa70ea0fca-w1   173.193.xx.yyy   10.76.193.109   free           normal   Ready    hou02   1.8.8_1507   

それでは、ブラウザでアクセスします。 上記のアドレス http://173.193.xx.yyy:31080/となり、認証情報は、第2目に記載した通り、username: admin, password: pass です。

次の様にデータベース testdb1が作成され、3個のデータが登録されている事が確認できます。

スクリーンショット 2018-03-12 13.09.02.png

最初の1個を開いて、登録されたデータとデバックウインドの表示値があっているか確認します。

スクリーンショット 2018-03-12 13.09.28.png

注意

無料枠内で利用できる事、解りやすさ、目的への到達の早さを考慮して、下記の点を省略していますので、ご注意をお願いします。

  • この例では、永続ストレージをマウントしていないので、ポッドが再起動されたり、削除されると、データを失います。
  • コンテナのパスワードは、プロジェクト等で利用する場合は、変更が必要です。

k8s上のMySQLのサービスと連動

次は、MySQLとの連携を確認していきます。 Cloudantの様に確認用のコンソールが無いので、コマンドラインが利用できるポッド(コンテナ)を起動してMySQLクライアントを実行して、設定や確認を進めていきます。

今回は、最初に Node-REDコンテナとMySQLコンテナの連携をフローエディタで描いてから、進めます。function-2には、データをテーブルにインサートするためのSQL文を書く必要があります。 ノードの設定内容は、詳しくは第2回目を参照してください。

スクリーンショット 2018-03-12 14.19.55.png

次は、MySQLサーバーのコンテナを起動するためのYAMLです。 DockerHubに登録された公式MySQLイメージを取得して、K8s上にデプロイします。このコンテナの詳しい説明は、DockerHub mysqlの説明を参照願います。 YAMLに環境変数を設定する事で、パスワード設定やcreate databaseを実行してくれる良くできたコンテナです。

mysql-deploy.yml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: mysql
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        ports:
        - containerPort: 3306
        env:
        - name: MYSQL_DATABASE
          value: "testdb2"
        - name: MYSQL_ROOT_PASSWORD
          value: "password"

同じ要領で、デプロイの実行と、起動の確認をおこないます。

$ kubectl create -f mysql-deploy.yml


$ kubectl get deploy mysql
NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
mysql     1         1         1            1           16m

これまで同様に、サービスを起動して、他のデプロイメント(コンテナ)からkube-dnsの名前解決でアクセスできる様にします。

mysql-service.yml
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  type: ClusterIP
  selector:
    app: mysql
  ports:
  - protocol: TCP
    port: 3306

同様に適用と起動の確認をします。

$ kubectl create -f mysql-service.yml

$ kubectl get svc mysql
NAME      TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
mysql     ClusterIP   172.21.247.189   <none>        3306/TCP   17m

MySQLサーバーには、testdb2というデータベースが作成されていますが、データを格納するテーブルがありません。そこで、コマンドライン用のポッド(コンテナ)を起動して、テーブルを作成します。

$ kubectl run -it --image mysql my-client bash
If you don't see a command prompt, try pressing enter.

上記で Enter キーを押すと、以下の様にmy-clientコンテナの中に入り、mysqlコマンドで、mysqlコンテナのMySQLサーバーへログインして、テーブルを作ります。

root@my-client-65bbd59569-x4v8t:/# mysql -h mysql -u root -ppassword testdb2
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.7.21 MySQL Community Server (GPL)

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.


mysql> show tables;
Empty set (0.00 sec)


mysql> CREATE TABLE payload (id MEDIUMINT NOT NULL AUTO_INCREMENT, msg CHAR(30) NOT NULL, PRIMARY KEY (id) );
Query OK, 0 rows affected (0.00 sec)


mysql> show tables;
+-------------------+
| Tables_in_testdb2 |
+-------------------+
| payload           |
+-------------------+
1 row in set (0.00 sec)


mysql> desc payload;
+-------+--------------+------+-----+---------+----------------+
| Field | Type         | Null | Key | Default | Extra          |
+-------+--------------+------+-----+---------+----------------+
| id    | mediumint(9) | NO   | PRI | NULL    | auto_increment |
| msg   | char(30)     | NO   |     | NULL    |                |
+-------+--------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)

mysql> 

Node-REDの設定

次の図の様に、フリーエディタのMySQLノードをクリックして、MySQLのコンテナと接続するための設定を入力していきます。

スクリーンショット 2018-03-12 14.10.31.png

IPアドレスではなく、サービス名を設定します。 コンテナのIPアドレスは、再起動すると再割り当てされるため、一定しません。このためmysqlというDNS名で設定が必要になるのです。

スクリーンショット 2018-03-12 14.11.04.png

動作テスト

timestampノードをクリックして、タイムスタンプの値が、MySQLノードにセットされるか確認してみましょう。

スクリーンショット 2018-03-12 14.12.17.png

先にログインしたmysqlクライアントで、select文を実行すると、デバックウインドに表示されたデータと同じ値が登録されている事がわかります。

スクリーンショット 2018-03-12 14.12.46.png

これで、k8s上のNode-REDコンテナとMySQLコンテナの連携の解説は完了です。 dockerコマンドの代わりに、yamlを作成して適用する点、必ずサービスを起動する点など多少の差がありますが、コンテナを理解していれば、大きな違いが無い事が判ったと思います。

RESTサービスの雛形

最後にK8s上のNode-REDが提供するRESTサービスの設定方法とアクセス方法について、簡単に確認します。

次のフローは、RESTサービスで簡単な文字列を返すフローです。 このフローの作成は、第2回目の記事を参照願います。/recvをGETでアクセスすると、次のフローがコールバックされ、functionでセットされる文字列が返されます。

スクリーンショット 2018-03-12 14.24.42.png

k8sではNodePortで開いていますから、URLのディレクトリ部分を前述の/recvに変更する事で、次の結果を得る事がきます。

スクリーンショット 2018-03-12 14.36.44.png

まとめ

Node-REDは、コードを書かない人にも、プログラムが出来そうな気にさせる、凄く優れたツールだと思います。 そして、プログラミングの敷居を下げ、IoTなどの高速開発の道を開いた様に思います。 この優れたNode-REDをKubernetesのコンテナ上で動かして、他のコンテナと関連付けて、コンテナの再利用の効果によって、さらなる高い生産性を達成していく事ができる様に思います。 是非、試して体験して頂きと思います。