概要
シングルノード、Sentinel、Cluster のそれぞれを k8s 上でコンテナとして起動しアクセスする方法を考えます
k8s 環境は minikube
を使います
環境
- macOS 10.14.5
- minikube v0.28.2
minikube 起動
minikube start
シングルノードで起動
まずは redis
1 台で起動させてみます
Deployment 作成
Pod 直接ではなく Deploment を使います
vim redis_deployment.yml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: redis-master
spec:
replicas: 1
template:
metadata:
labels:
app: redis
role: master
spec:
containers:
- name: master
image: redis
ports:
- containerPort: 6379
特にポイントはないです
labels
に関しては好きなラベルを設定してください
あとで Service と紐付けるのに使います
kubectl apply -f redis_deployment.yml
kubectl get po
NAME READY STATUS RESTARTS AGE
redis-master-86f6bffc7f-xrzht 1/1 Running 0 7m
デプロイして Pod が起動すれば OK です
redis-cli
コマンドを使ってコンテナが起動しているか確認しましょう
kubectl exec redis-master-86f6bffc7f-xrzht redis-cli info replication
# Replication
role:master
connected_slaves:0
master_replid:695cd5de82eb682d3ebd2f20dc39dc1cb3ee05a6
master_replid2:0000000000000000000000000000000000000000
Service 作成
ホストマシンからアクセスできるように Service を作ります
vim redis_service.yml
apiVersion: v1
kind: Service
metadata:
name: redis-single
spec:
type: NodePort
selector:
role: single
ports:
- protocol: TCP
port: 6379
targetPort: 6379
Ingress
は面倒なので type: NodePort
を使います
minikube -> VirtualBox -> コンテナという経路でアクセスすることになります
kubectl apply -f redis_service.yml
redis-cli -h 192.168.99.100 -p 31267 info replication
で先ほどと同じ結果が得られると思います
ちなみにこれらの IP アドレスとポートは Mac から見える minikube
用の Virtualbox のIP とポートになります
minikube ip
minikube service redis-single --format "{{.Port}}"
ちなみにこの状態で Deployment の replicas: 1
を replicas: 3
などにすると Pod が 3 台になります
そして上記の redis-cli
でアクセスすると各コンテナに分散してアクセスしているので確認できると思います
Sentinel で起動
次に Sentinel 環境を考えます
戦略として master, slave, sentinel それぞれで Deployment と Serivce を作ってお互いを通信する感じです
master Deployment 作成
まず master 用のコンテナを作成するための Deployment を作成します
vim redis_master_deployment.yml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: redis-master
spec:
replicas: 1
template:
metadata:
labels:
app: redis
role: master
spec:
containers:
- name: master
image: redis
ports:
- containerPort: 6379
kubectl apply -f redis_master_deployment.yml
これは先程とほぼ変わりません
kubectl get po
NAME READY STATUS RESTARTS AGE
redis-master-86f6bffc7f-kx4sc 1/1 Running 0 3m
kubectl exec redis-master-86f6bffc7f-kx4sc redis-cli info replication
role:master
connected_slaves:0
master Service 作成
次に master 用のコンテナに他のコンテナからアクセスできるように Service を定義します
vim redis_master_service.yml
apiVersion: v1
kind: Service
metadata:
name: redis-master
spec:
type: NodePort
selector:
role: master
ports:
- protocol: TCP
port: 6379
targetPort: 6379
kubectl apply -f redis_master_service.yml
kubectl get ep redis-master
これで master にアクセスするためのエンドポイントが表示されます
NAME ENDPOINTS AGE
redis-master 172.17.0.7:6379 3s
slave Deplyment 作成
次に slave コンテナ用の Deployment を作成します
vim redis_slave_deployment.yml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: redis-slave
spec:
replicas: 1
template:
metadata:
labels:
app: redis
role: slave
spec:
containers:
- name: slave
image: redis
ports:
- containerPort: 6379
command: ["redis-server"]
args: ["--slaveof", "172.17.0.7", "6379"]
master の Deployment に command
を追加しています
--slaveof
オプションを使って master のエンドポイントを指定することで slave として redis-server
が立ち上がるようにしています
これで起動し redis-cli
でレプリケーションの状態を確認してみましょう
kubectl apply -f redis_slave_deployment.yml
kubectl get po
NAME READY STATUS RESTARTS AGE
redis-master-86f6bffc7f-kx4sc 1/1 Running 0 6m
redis-slave-5556967686-l7t58 1/1 Running 0 4m
kubectl exec redis-slave-5556967686-l7t58 redis-cli info replication
role:slave
master_host:172.17.0.7
master_port:6379
こんな感じで master のエンドポイントを参照し slave になっていれば OK です
slave Service 作成
failover した際に slave にアクセスすることになるので slave も Service を作成しておきます
vim redis_slave_service.yml
apiVersion: v1
kind: Service
metadata:
name: redis-slave
spec:
type: NodePort
selector:
role: slave
ports:
- protocol: TCP
port: 6379
targetPort: 6379
kubectl apply -f redis_slave_service.yml
kubectl get ep redis-slave
NAME ENDPOINTS AGE
redis-slave 172.17.0.8:6379 17s
sentinel Deployment 作成
作成した master/slave を Sentinel で監視し自動 failover できるようにします
まず Sentinel 用のイメージを作成します
mkdir sentinel
cd sentinel
vim sentinel.conf
port 26379
dir /tmp
sentinel monitor mymaster 172.17.0.7 6379 1
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 5000
sentinel monitor
で指定する IP は master のエンドポイントを指定します
vim Dockerfile
FROM redis
ADD sentinel.conf /etc/redis/sentinel.conf
RUN chown redis:redis /etc/redis/sentinel.conf
CMD ["redis-server", "/etc/redis/sentinel.conf", "--sentinel"]
eval $(minikube docker-env)
docker build -t sentinel:v1 .
これでイメージが minikube で起動した Virtualbox 上に作成されます
このイメージを使って Sentinel の Deloyment を定義します
vim redis_sentinel_deployment.yml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: redis-sentinel
spec:
replicas: 1
template:
metadata:
labels:
app: redis
role: sentinel
spec:
containers:
- name: sentinel
image: sentinel:v1
ports:
- containerPort: 26379
containerPort
は sentinel.conf で指定したポートに合わせます
また image
も先程作成したイメージに書き換えます
バージョンの指定も忘れずに行いましょう
kubectl apply -f redis_sentinel_deployment.yml
kubectl get po
NAME READY STATUS RESTARTS AGE
redis-master-86f6bffc7f-kx4sc 1/1 Running 0 18m
redis-sentinel-6d775867b9-pqtpj 1/1 Running 0 9s
redis-slave-5556967686-l7t58 1/1 Running 0 16m
これで master, slave, sentinel の必要なコンテナが揃いました
sentinel Service 作成
Sentinel API を叩くので一応 Service 登録しておきます
vim redis_sentinel_service.yml
apiVersion: v1
kind: Service
metadata:
name: redis-sentinel
spec:
type: NodePort
selector:
role: sentinel
ports:
- protocol: TCP
port: 26379
targetPort: 26379
kubectl apply -f redis_sentinel_service.yml
ホストから Sentinel API にアクセスできるか確認します
minikube ip
minikube service redis-sentinel --format "{{.Port}}"
でホストからアクセスする IP とポートを確認し redis-cli
を実行します
redis-cli -h $(minikube ip) -p 31293 sentinel get-master-addr-by-name mymaster
1) "172.17.0.7"
2) "6379"
こんな感じでちゃんと master が見えていれば OK です
動作確認
failover させてちゃんと master が切り替わるか確認します
k8s には Pod を停止する方法はないので Deployment を削除します
kubectl delete deploy redis-master
このときの Sentinel のログは以下の通りです
kubectl logs -f redis-sentinel-6d775867b9-pqtpj
1:X 28 May 2019 07:17:12.368 # +failover-state-reconf-slaves master mymaster 172.17.0.7 6379
1:X 28 May 2019 07:17:12.428 # +failover-end master mymaster 172.17.0.7 6379
1:X 28 May 2019 07:17:12.429 # +switch-master mymaster 172.17.0.7 6379 172.17.0.8 6379
1:X 28 May 2019 07:17:12.431 * +slave slave 172.17.0.7:6379 172.17.0.7 6379 @ mymaster 172.17.0.8 6379
1:X 28 May 2019 07:17:17.449 # +sdown slave 172.17.0.7:6379 172.17.0.7 6379 @ mymaster 172.17.0.8 6379
ちゃんと failover していることが確認できます
slave の Service にアクセスすると master に昇格していることがわかると思います
redis-cli -h $(minikube ip) -p 32109 info replication
role:master
connected_slaves:0
slave は 0 台になっています
これは元 master がまだダウンしているためです
再度 master を Deployment してみましょう
kubectl apply -f redis_master_deployment.yml
Sentinel のログを見ていると以下のようなログが流れると思います
1:X 28 May 2019 07:24:34.164 # -sdown slave 172.17.0.7:6379 172.17.0.7 6379 @ mymaster 172.17.0.8 6379
1:X 28 May 2019 07:24:44.133 * +convert-to-slave slave 172.17.0.7:6379 172.17.0.7 6379 @ mymaster 172.17.0.8 6379
これで再度 slave の数を確認すると connected_slaves:1
になっていることが確認できると思います
実際に master と slave に対して redis-cli
で get/set
してみると更に挙動を確認できると思います
$ redis-cli -h $(minikube ip) -p 32582 set a a
(error) READONLY You can't write against a read only replica.
$ redis-cli -h $(minikube ip) -p 32109 set a a
OK
$ redis-cli -h $(minikube ip) -p 32582 get a
"a"
Cluster で起動
ちょっと長くなってしまったので別記事で紹介したいと思います
どうやら Redis Cluster の場合はステートフルなので StatefulSets を使ったほうが良いみたいです
最後に
k8s 上に Redis のシングルノード環境と Sentinel 環境を構築してみました
どちらも Deployment と Service を使えば構築できることがわかりました
特に Sentinel の方は Service を使わないと各ロール間で通信できないので必須になると思います
ネットでいろいろ調べると他にも方法がありそうでした
Pod だけでやる方法も頑張ればできるかなと思います (ConfigMap を使った方法もあるかなと思います)
結局は docker 上にコンテナを立てるのが目的でそれを実現するのに k8s のどの機能を使うのかという話になるかなと思います
今回は Deployment と Serivce を使った方法を紹介しましたが、それ以外を使っても実現することはできるということです
この辺りは k8s の経験がものを言うかなと思っています
0 件のコメント:
コメントを投稿