概要
前回の「初めてのkubernetes(Minikube) Windows環境でチュートリアル+α」に続き、アプリケーションサーバ用PodとDBサーバ用Podの連携をやってみたので理解したことをメモとして残したいと思います
※minikubeコマンドを実行する際は管理者権限で実行してください
実行環境
- Windows 10 pro
- Minikube v0.28.0
- Docker Version 18.06.1-ce-win73 (19507)
さっそく手順
1. サンプルアプリケーションの取得
今回はNode.jsのアプリケーションからRedisのデータを取得して表示する簡単なサンプルアプリケーションを使っていきますので、ソースをローカルにクローンしてください
ローカルで事前に動作確認できるようにdocker-compose
も用意していますので、適宜に活用してください
const http = require('http');
const redis = require('redis');
let redis_host = 'redis';
let redis_port = 6379;
// k8s環境の場合は、redisの接続先とポートは環境変数から取得
if (process.env.MODE && process.env.MODE == 'k8s') {
redis_host = process.env.SAMPLE_REDIS_SERVICE_HOST;
redis_port = process.env.SAMPLE_REDIS_SERVICE_PORT;
}
const client = redis.createClient({
host: redis_host,
port: redis_port
});
// 表示用の変数をredisに保存する
client.set('sample', 'hello world');
client.set('sample2', 'hello Qiita');
// 表示用の変数
let redis_val = '';
client.get('sample', function (err, data) {
redis_val += '<li>' + data + '</li>';
});
client.get('sample2', function (err, data) {
redis_val += '<li>' + data + '</li>';
});
const handleRequest = function (request, response) {
console.log('Received request for URL: ' + request.url);
response.writeHead(200);
response.end('<h1>redis value:</h1><ul>' + redis_val + '</ul>');
};
// echo env
const envs = process.env;
console.log(envs);
const www = http.createServer(handleRequest);
www.listen(3000);
2. Dockerクライアントの接続先の変更
前回同様Dockerクライアントの向き先を予めMinikubeに変更してください
> minikube docker-env --shell powershell | Invoke-Expression
> docker images
# kubernetes関連のイメージが表示されればOK
3. イメージのビルド
サンプルアプリケーションのDockerイメージをMinikubeにビルドします
> docker build -t sample-app:v1 --no-cache ./app
4. Deployment
Minikubeにデプロイします
> kubectl apply -f ./deployment_k8s_sample_app.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-redis
labels:
app: sample-redis
type: db
spec:
replicas: 1
selector:
matchLabels:
app: sample-redis
type: db
template:
metadata:
labels:
app: sample-redis
type: db
spec:
containers:
- name: sample-redis
image: redis:4
ports:
- containerPort: 6379
# redis-volumeボリュームとredisのデータ領域の/data
volumeMounts:
- mountPath: /data
name: redis-volume
# データ永続化するためのボリューム
volumes:
- name: redis-volume
# ボリュームの種別はhostPath
hostPath:
path: /home/docker/redis-data
# ディレクトリがなければ作る
type: DirectoryOrCreate
---
apiVersion: v1
kind: Service
metadata:
name: sample-redis
labels:
app: sample-redis
type: db
spec:
type: LoadBalancer
selector:
app: sample-redis
type: db
ports:
- port: 6379
targetPort: 6379
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-app
labels:
app: sample-app
type: app
spec:
replicas: 1
selector:
matchLabels:
app: sample-app
type: app
template:
metadata:
labels:
app: sample-app
type: app
spec:
containers:
- name: sample-app
image: sample-app:v1
ports:
- containerPort: 3000
# k8s環境用で稼働しているかどうかの環境変数
env:
- name: MODE
value: k8s
---
apiVersion: v1
kind: Service
metadata:
name: sample-app
labels:
app: sample-app
type: app
spec:
type: LoadBalancer
selector:
app: sample-app
type: app
ports:
- port: 3000
5. 確認
Podの確認
> kubectl get po
NAME READY STATUS RESTARTS AGE
sample-app-694d9bf49f-66b7b 1/1 Running 0 37m
sample-redis-55c5b46859-n7pnt 1/1 Running 0 42m
Serviceの確認
> kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 20d
sample-app LoadBalancer 10.101.237.112 <pending> 3000:32482/TCP 43m
sample-redis LoadBalancer 10.111.4.116 <pending> 6379:32400/TCP 43m
アプリケーションの確認
> minikube service sample-app
ブラウザで以下のように表示されればOKです
redis value:
hello world
hello Qiita
説明
Dockerと同じようにDB Pod(redis)接続情報を記す環境変数を取得することができる
その代わりにServiceとして公開しないといけないようです
Serviceを利用することにより、トラフィックの負荷分散、サービスディスカバリー、クラスタ内のDNSを利用できるようになります
なので、アプリケーションのredisの接続先を環境変数から取得しています
server.js
// k8s環境の場合は、redisの接続先とポートは環境変数から取得
// MODEはDeploymentで環境変数として設定しています
if (process.env.MODE && process.env.MODE == 'k8s') {
redis_host = process.env.SAMPLE_REDIS_SERVICE_HOST;
redis_port = process.env.SAMPLE_REDIS_SERVICE_PORT;
}
環境変数を確認してみましょう
kubectl logs sample-app-694d9bf49f-66b7b
{ KUBERNETES_SERVICE_PORT: '443',
KUBERNETES_PORT: 'tcp://10.96.0.1:443',
SAMPLE_APP_PORT_3000_TCP_ADDR: '10.97.74.141',
NODE_VERSION: '6.9.2',
HOSTNAME: 'sample-app-565db6587d-xtblr',
MODE: 'k8s',
SAMPLE_APP_PORT_3000_TCP_PORT: '3000',
SAMPLE_APP_PORT_3000_TCP_PROTO: 'tcp',
HOME: '/root',
SAMPLE_REDIS_SERVICE_HOST: '10.103.205.192',
SAMPLE_APP_PORT_3000_TCP: 'tcp://10.97.74.141:3000',
SAMPLE_APP_SERVICE_HOST: '10.97.74.141',
SAMPLE_REDIS_PORT: 'tcp://10.103.205.192:6379',
SAMPLE_REDIS_SERVICE_PORT: '6379',
SAMPLE_REDIS_PORT_6379_TCP_ADDR: '10.103.205.192',
KUBERNETES_PORT_443_TCP_ADDR: '10.96.0.1',
PATH: '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
SAMPLE_REDIS_PORT_6379_TCP_PORT: '6379',
KUBERNETES_PORT_443_TCP_PORT: '443',
SAMPLE_REDIS_PORT_6379_TCP_PROTO: 'tcp',
SAMPLE_APP_PORT: 'tcp://10.97.74.141:3000',
SAMPLE_APP_SERVICE_PORT: '3000',
NPM_CONFIG_LOGLEVEL: 'info',
KUBERNETES_PORT_443_TCP_PROTO: 'tcp',
SAMPLE_REDIS_PORT_6379_TCP: 'tcp://10.103.205.192:6379',
KUBERNETES_PORT_443_TCP: 'tcp://10.96.0.1:443',
KUBERNETES_SERVICE_PORT_HTTPS: '443',
KUBERNETES_SERVICE_HOST: '10.96.0.1',
PWD: '/' }
データの永続化
データの永続化するために、ボリュームをhostPathとして定義しています
hostPathはNode上の任意のパスをボリュームとして作ることができます
MinikubeのようにシングルNodeの場合は問題ないが、複数Node構成の場合は、データの整合性を考慮しなければならないため、他のボリューム種別を利用すること
以下ではデータの永続化の動作検証手順になります
1. Deployment、サービスの削除
データが永続化しているかどうかを確認するために、一度削除します
> kubectl delete -f ./deployment_k8s_sample_app.yml
2. server.jsを修正
redisに値を保存するコードをコメントアウトします
// 表示用の変数をredisに保存する
// client.set('sample', 'hello world');
// client.set('sample2', 'hello Qiita');
3. イメージをリビルド
タグはv2
でビルド
> docker build -t sample-app:v2 --no-cache ./app
4. deployment_k8s_sample_app.ymlを編集
デプロイするイメージをv2に変更
~中略~
containers:
- name: sample-app
image: sample-app:v2
~中略~
5. 再Deployment
> kubectl apply -f ./deployment_k8s_sample_app.yml
deployment.apps "sample-redis" created
service "sample-redis" created
deployment.apps "sample-app" created
service "sample-app" created
5. 動作確認
前述と同様に値を確認できる
> minikube service sample-app