「DeNA IPプラットフォーム事業部 Advent Calendar 2017」15日目の記事です
はじめに
GoogleKubernetesEngineなどKubernetes環境を採用している場合、ローカルの開発環境においてもKubernetes+minikubeを採用することがあるかと思います
今回はそのminikube上でのNode.js開発環境の構築手順とポイントをかんたんに解説します
※Mac前提で進めます、その他のOSをご利用の方ごめんなさい!🙇
必要なもの
- minikube
- kubectl
- docker
- nodejs(Mac上)
基本的なインストール手順はこちらを参考にしてください
https://kubernetes.io/docs/tutorials/stateless-application/hello-minikube/
Node.js(npm)を利用するのでインストールしてください
https://nodejs.org/ja/download/
※バイナリ以外の方法でも問題ありません
環境構築
hyperkitドライバーでminikubeを起動する
hyperkitはvirtualboxなどと比べ動作が高速でした
※参考nodejs起動時間 virtualbox:3sec hyperkit:1sec
# hyperkitドライバーをインストール
$ curl -LO https://storage.googleapis.com/minikube/releases/latest/docker-machine-driver-hyperkit && chmod +x docker-machine-driver-hyperkit && sudo mv docker-machine-driver-hyperkit /usr/local/bin/ && sudo chown root:wheel /usr/local/bin/docker-machine-driver-hyperkit && sudo chmod u+s /usr/local/bin/docker-machine-driver-hyperkit
# minikubeを起動
$ minikube start --vm-driver=hyperkit --cpus 4 --memory 8192
# dockerのホストを設定する
$ eval $(minikube docker-env)
cpu,memoryは必要に応じて変えてください
Dockerfile
FROM node:8.6.0
ENV APP_ROOT /opt/node
WORKDIR $APP_ROOT
RUN npm install pm2 -g
EXPOSE 3000 3002
CMD ["npm", "run", "start"]
pm2をインストールしていますが目的は後ほど
アプリケーションコード
npmスクリプトを使用するため以下のようなファイルにします
{
"name": "k8s-node-dev",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "pm2-docker start ./pm2.json"
},
"dependencies": {
},
"devDependencies": {
"gulp": "^3.9.1"
}
}
起動設定はpm2.jsonでおこないます
{
"apps": [
{
"name": "k8s-node-dev",
"script": "./app.js",
"node_args": "--inspect=0.0.0.0:3002"
}
]
}
node_args
にデバッグポートの設定をしています
ソースコードNFSマウントする
mac上のソースコードをminikube上にマウントし、mac上で編集→kubernetes上で実行させます
minikube mount
ではなくnfsを利用したほうが高速なため、nfsを使います
※参考 minikube mount
の場合、nodeの起動に10秒以上要しました
$ cd project_dir
$ echo "$(pwd) -network 192.168.0.0 -mask 255.255.0.0 -alldirs -maproot=root:wheel" | sudo tee -a /etc/exports
$ sudo nfsd restart
$ minikube ssh -- sudo busybox mount -v -t nfs 192.168.99.1:$(pwd) /home/docker/shared_volumes/ -o rw,async,noatime,rsize=32768,wsize=32768,proto=tcp
podを作成する
apiVersion: v1
kind: Service
metadata:
name: k8s-node-dev
spec:
selector:
app: k8s-node-dev
role: app
env: local
ports:
- protocol: TCP
name: app
port: 8081
targetPort: 3000
nodePort: 30082
- name: debug
port: 3002
targetPort: 3002
nodePort: 30089
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: k8s-node-dev
spec:
replicas: 1
template:
metadata:
labels:
app: k8s-node-dev
role: app
env: local
spec:
containers:
- name: k8s-node-dev
image: "node-dev:v1"
tty: true
stdin: true
ports:
- containerPort: 3000
- containerPort: 3002
volumeMounts:
- mountPath: "/opt/node"
name: "node-src-volume"
volumes:
- name: "node-src-volume"
hostPath:
path: "/home/docker/shared_volumes/project_dir"
Dockerイメージをビルドしpodを起動します
$ docker build -f ./Dockerfile -t node-dev:v1 .
$ kubectl create -f ./k8s-node.yaml
動作の確認を行います
$ minikube service k8s-node-dev
ここまでで準備は完了です
ファイルの変更を即時に反映する
nodejsは再起動しないと変更を反映させることができません
毎回手動で実行するのは辛いのでファイルの変更を監視し自動で再起動するようにしたいところ
通常、nodemonやnode-devなどで起動すればいいだけなのですが、今回の環境ではnfsマウント押している関係上ファイルの更新を検知することができません
(ポーリングで解決もできますがちょっと…
mac上で監視を行う
pod上でだめなら大元のmac側で監視しましょう
今回はgulpを使います
mac上でgulpをインストール
$ npm install -g gulp
$ npm install gulp
監視と再起動を行う
let gulp = require('gulp');
let exec = require('child_process').exec;
gulp.task('watch', function(){
gulp.watch('./**/*.*', ['reload']);
});
gulp.task('reload', function(){
console.log('reload');
exec('kubectl exec -it $(kubectl get pod | grep node | awk -F" " \'{print $1}\') -- pm2 reload all', {shell: '/bin/bash'}, function(error, stdout, stderr) {
console.log(stdout);
});
});
$ gulp watch
何をしているのか
-
gulp.watch
でファイルを監視し、exec
でbashに処理を渡す -
$(kubectl get pod | grep node | awk -F" " \'{print $1}\')
でpodのIDを取得 -
kubectl exec -it $ID -- $script
で$scriptを実行 -
pm2 reload all
で再起動
pm2を採用したのはこのように外部から再起動を実行可能なためです
これで、スムーズに修正を反映する環境が整いました
デバッグがしたい
すでにpm2.jsonにデバッグポート3002を指定し、k8s-node.yamlに3002にアクセスするnodePort:30089を開けているためかんたんにデバッグが可能です
Chromeでデバッグ
-
minikube service tama-bff-service --format "{{.IP}}"
でIPを確認する - chrome://inspect/#devicesを開く
- Open dedecated ...をクリック
- Connectionタブを開き、
${1で取得したIP}:30089
を登録する - 2の画面のRemote Targetにinspect対象が現れるので開く
これで、デバッグ可能になりました
まとめ
minikubeを使ったnodejs環境構築ついてまとめました
NFSやgulpを組み合わせることで、ローカルでNode.jsを起動した場合と大差ないスムーズな開発が実現できました
また、Dockerfileやyamlに設定がまとまっているので他のメンバーへの導入も非常にかんたんにできます
現在エブリスタの開発において手探りで運用している環境なのでご質問・ご意見等ございましたらよろしくお願いします!
宣伝
エブリスタでは一緒に働くメンバーを熱烈に募集しています
- アーキテクチャ設計や言語選定から関わるエンジニアリングをしたい方
- 最新技術に触れたい方
- 小説やUGCに関わる仕事に興味がある方
- 出版業界・コンテンツ業界に変革を起こしたい方
などなど、「ちょっと興味ありそう」「もっと色々聞いてみたい」という方も
是非こちらから応募頂くか、 @daponta まで気軽にご連絡ください!