Node.js
mariadb
kubernetes

Node.jsからMariadbに繋ぐサンプルプログラムをKubernetesにデプロイする

いや、Kubernetes難しいですよね。
流行っているような気がする割りには、Node.jsからKubernetesのServiceリソースを経由してMariadbに接続する確認用のサンプルプログラムを作ることすら、普通のITエンジニアではなかなかできない。Webの解説を探しても、詳しいことはGithubでとか、面倒くさすぎてついていけない。しかして首題を実現するミニマルな手順をまとめてみました。

1. Mariadbコンテナを作る

何はともあれMariadbのコンテナを作らないことにははじまらないです。
手順はミニマルにが記事のモットーなので出来る限り簡単に。
なので、とりあえず、以下のコマンドを実行。

# kubectl run my-db --image=mariadb --env="MYSQL_ROOT_PASSWORD=secret"
# kubectl expose deployment my-db --port=3306

パスワードがsecretで簡単ですが、Kubernetesの外からはMariadb見えないのでまあ問題ないでしょう。
Mariadbが起動したらデータベースを作りましょう。
コマンドは以下。

# cat > my-db.sql << 'EOF'
CREATE DATABASE sampledb;
CREATE TABLE sampledb.sampletable (name VARCHAR(10));
INSERT INTO sampledb.sampletable VALUES ('Success!');
CREATE USER test@'%' identified by 'secret';
GRANT SELECT ON sampledb.* TO test@'%';
EOF
# POD=$(kubectl get pod --selector "run=my-db" -o custom-columns=NAME:.metadata.name --no-headers)
# kubectl cp my-db.sql $POD:.
# kubectl exec $POD -- mysql -psecret -e "source my-db.sql"

へい、データベース一丁上がり。
期待した通りに構成されているかは一応以下のコマンドで確認できる。

# kubectl exec $POD -- mysql -utest -psecret -e "SELECT * FROM sampledb.sampletable"
(実行結果)
name
Success!

2. Node.jsコンテナを作る

Node.jsはですね、Dockerfile使ってベースのコンテナを拡張しなくちゃいけないもので、若干面倒くさい。
まずは、動かすjsのプログラム作ります。
以下のコマンドを実行。

# cat > my-node.js << 'EOF'
var mysql      = require('mysql');
var connection = mysql.createConnection({
  host     : process.env.DBADDR,
  port     : "3306",
  user     : "test",
  password : "secret"
});
var http = require("http");
var os = require('os');

http.createServer((request, response) => {
  var date = new Date();
  var hostname =  os.hostname();
  var remoteAddress = request.connection.remoteAddress;
  console.log(date + ' - ' + hostname + ' - ' + remoteAddress);

  connection.query("SELECT * FROM sampledb.sampletable;", function (e, r, f) {
    response.writeHead(200, {'Content-Type': 'text/html'});
    response.write('<html><body>\n');
      response.write('date: ' + date + '<br/>\n');
      response.write('hostname: ' + hostname + '<br/>\n');
      response.write('remoteAddress: ' + remoteAddress + '<br/>\n');
      if (e != null) {
        response.write('db:error: ' + e + '<br/>\n');
      } else {
        response.write('db:record: ' + r[0].name + '<br/>\n');
      }
    response.write('</html></body>\n');
    response.end();
  });
}).listen(80);
EOF

で、Dockerfileを作ってbuild。
mysqlのライブラリをinstallするのを忘れずに。
以下のコマンドを実行。

# cat > Dockerfile << 'EOF'
FROM node
RUN npm install mysql
COPY my-node.js /root
EXPOSE  80
CMD node /root/my-node
EOF
# docker build . -t my-node

で、それをプライベートDockerレジストリにプッシュ。
まあ、ここできっと躓く人がいるでしょうが、ごめんなさい、それは救えない。ほんと申し訳ない。
以下のコマンドを実行。

# REG=<レジストリ:ポート番号/namespace>
# docker tag my-node $REG/my-node
# docker push $REG/my-node

して、my-nodeコンテナを実行する。
DBへの接続はIPアドレスで行う。ServiceのDNS名で接続するとkube-dns(Masterノード)がSPOFになるかMaster HA(通常すこぶる不安定)が必要になって良くない。
以下のコマンドを実行。

# IP=$(kubectl get service my-db -o custom-columns=IP:.spec.clusterIP --no-headers)
# kubectl run my-node --image=$REG/my-node --image-pull-policy=true --env="DBADDR=$IP" --replicas=3
# kubectl expose deployment my-node --type=NodePort --port=80

この時点で、いわゆるkube-proxyが動作しているノードに対して以下のコマンドを実行すれば、node.js->mariadb接続ができているかどうかを確認できるはず。

# PROXYIP=<kube-proxyが動作するサーバのIPアドレス>
# NODEPORT=$(kubectl get service my-node -o custom-columns=NODEPORT:.spec.ports[0].nodePort --no-headers)
# curl $PROXYIP:$NODEPORT

(実行結果)
<html><body>
date: Sun May 13 2018 16:21:42 GMT+0000 (UTC)<br/>
hostname: my-node-778bbb4c8-ng2fp<br/>
remoteAddress: ::ffff:10.1.44.0<br/>
db:record: Success!<br/>
</html></body>

実行結果に「db:record: Success!」とあればnode.jsからmariadbへの接続は成功。