投稿日:2020年10月10日
この記事ではKubernetesのDeployment、Serviceについてredisのレプリケーションを実装する実例を交えつつ解説しています。
この記事ではKubernetesのDeployment、Serviceについてredisのレプリケーションを実装する実例を交えつつ解説しています。
この記事は以下の環境で実践・確認されました。
レプリケーションとは、データベースなどに対して同じデータを保持するものを複数用意することで、高可用性を実現することを言います。このときメインで利用されるサーバーを稼働系(マスター)、稼働系に障害があった際に利用されるサーバーを待機系という。
稼働系と待機系は物理的な障害に強くするために離れた距離に置くことが多い(例えばクラウドならそれぞれのリージョンを違うものに設定)。
Kubernetesで
ReplicationControllerは複数のPodのレプリカを一度に実行・管理することのできるKubernetesのリソースです。このリソースを利用すると常に指定した数のPodを起動させておくことができます。
これにより、障害やホストのカーネルのアップデートなどの際にもPodの存在を維持できます。
以前はこちらが利用されていましたが、Version1.12以降は後述のDeploymentを利用したReplicaSetによる管理が推奨されています。
Deploymentは状態を指定すると、その状態を実現するPodとReplicaSetを維持します。
今回この記事でレプリケーション実装のために作成するのはこちらのDeploymentです。
DeploymentによるPodの作成・管理は自動的におこなわれるため、以下のような問題があります。
これらの問題を解決するのがServiceです。
ServiceはPodへの接続を解決してくれる抽象的なオブジェクトです。これを使用することでPodが再作成などされても、そのPodへの接続を実際のIPアドレスではなく常に同じDNS名でアクセスできます。
Serviceには以下のタイプがあります。
この内今回使用するのはLoadBalancerです。
これを使用することで複数のPodへのアクセスを上手くバランシングすることができます。
この記事で使用するKubernetes環境はMinikubeのシングルノードクラスタです。
すでにMinikubeは起動しているものとします。もし、これの前にそのクラスタで作業していた場合には一度削除して再度起動したほうが良いかも知れません。
まずDeploymentを作成する前に確認しなければいけないことがあります。
$ kubectl cluster-info
Kubernetes master is running at https://192.168.39.7:8443
KubeDNS is running at https://192.168.39.7:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
上のようにKubeDNSが起動していることが確認できればOKです。今回作成するyamlファイルでは待機系から稼働系への参照でこのKubeDNSを使用します。
まずはRedisのマスターを起動させます。
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-redis-master
labels:
name: deployment-redis-master
spec:
replicas: 1
selector:
matchLabels:
name: redis-master
template:
metadata:
labels:
name: redis-master
spec:
subdomain: master
containers:
- name: redis
image: redis:3.2.0-alpine
command:
- "redis-server"
args:
- "--protected-mode"
- "no"
ports:
- containerPort: 6379
yamlからリソースを作成します。
$ kubectl apply -f deployment-redis-master.yml
deployment.apps/deployment-redis-master created
リソースが正しく作成されたかをkubectl getコマンドで確認します。ちなみに通常渡す引数はreplicasetなのですが、rsと省略することができます。
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
deployment-redis-master 1/1 1 1 32m
(base) ogihara@ubuntu:~/kubernetes_sample/redis_replication$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
deployment-redis-master 1/1 1 1 32m
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
deployment-redis-master-5b97f7fd5 1 1 1 32m
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
deployment-redis-master-5b97f7fd5-n8m2b 1/1 Running 0 33m
つぎにこのRedisのマスタへの参照を管理するServiceを作成します。
apiVersion: v1
kind: Service
metadata:
name: service-redis-master
spec:
type: LoadBalancer
ports:
- protocol: TCP
port: 6379
targetPort: 6379
name: redis
selector:
name: redis-master
今回作成するServiceにはLoadBarancerタイプを指定します。
.spec.selecter.nameの値が先程作成したDeploymentで作成されるPodのlabelsのnameの値になるようにします。deployment-redis-master.ymlの.spec.template.metadata.labels.nameの値でredis-masterと設定したので、こちらも同じ値を設定しています。
ではyamlからServiceを起動させます。
$ kubectl apply -f service-redis-master.yml
service/service-redis-master created
リソースの作成を確認してみましょう。
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 46m
service-redis-master LoadBalancer 10.104.249.53 <pending> 6379:31584/TCP 19s
問題なく作成できています。ちなみにkubernetesと名前のついたServiceはデフォルトのServiceで、Kubernetesのマスターへのアクセスを管理しています。我々がいつも使用しているkubectlコマンドはこのServiceを通ってKubernetesのマスターのAPIを叩いていたりします。
それでは次に、同様の方法でスレイブ用のDeploymentを作成しましょう。
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-redis-replica
labels:
name: deployment-redis-replica
spec:
replicas: 2
selector:
matchLabels:
name: redis-replica
template:
metadata:
labels:
name: redis-replica
spec:
subdomain: replica
containers:
- name: redis
image: redis:3.2.0-alpine
command:
- "redis-server"
args:
- "--slaveof"
- "service-redis-master.default.svc.cluster.local"
- "6379"
- "--protected-mode"
- "no"
ports:
- containerPort: 6379
apiVersion: v1
kind: Service
metadata:
name: service-redis-replica
spec:
type: LoadBalancer
ports:
- protocol: TCP
port: 6379
targetPort: 6379
name: redis
selector:
name: redis-replica
applyさせます。
$ kubectl apply -f deployment-redis-replica.yml
deployment.apps/deployment-redis-replica created
$ kubectl apply -f service-redis-replica.yml
service/service-redis-replica created
Serviceの方はredisマスターで定義したときとほとんど同じなので説明する必要はないと思います。
注目するべきはDeployment側のymlファイルです。起動されるコンテナで以下のようなコマンドが実行されるような設定になっています。
$ redis-server \
--slaveof service-redis-master.default.svc.cluster.local \
6379 \
--protected-mode no \
--slaveof オプションでレプリケーションする対象のDNS名を指定します。
"通常の"(Headlessでない)Serviceは、my-svc.my-namespace.svc.cluster.local
という形式のDNSのA(AAAA)レコードを、ServiceのIPバージョンに応じて割り当てられます。
現在作RedisマスターのPodが一つ、ReplicaSetのRedisレプリカのPodが2つ存在している状態です。
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
deployment-redis-master-5b97f7fd5-n8m2b 1/1 Running 0 94m
deployment-redis-replica-89f5664db-vgtrg 1/1 Running 0 2m56s
deployment-redis-replica-89f5664db-zx5kl 1/1 Running 0 2m57s
最後に正しくレプリケーションを実装できているかどうか確認しましょう。
ちなみにServiceへの接続先の確認方法については【Kubernetes】ServiceのIPアドレスとポートについてにまとめてあるので、詳しく知りたい方は読んでみてください。
$ minikube service --url service-redis-master
http://192.168.39.220:31584
$ $ redis-cli -h 192.168.39.220 -p 31584 info replication
# Replication
role:master
connected_slaves:2
slave0:ip=172.17.0.4,port=6379,state=online,offset=17585,lag=0
slave1:ip=172.17.0.5,port=6379,state=online,offset=17585,lag=1
master_repl_offset:17585
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:17584
connected_slaves:2となっているため、きちんとレプリケーションできていることが確認できました。
一応replicaの方も確認してみます。
$ minikube service --url service-redis-replica
http://192.168.39.220:30251
$ redis-cli -h 192.168.39.220 -p 30251 info replication
# Replication
role:slave
master_host:service-redis-master.default.svc.cluster.local
master_port:6379
master_link_status:up
master_last_io_seconds_ago:4
master_sync_in_progress:0
slave_repl_offset:17739
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
今回はDeploymentとServiceについて勉強しました。