文章目录
1. 创建NFS存储
创建NFS存储主要是为了给Redis提供稳定的后端存储,当Redis的Pod重启或迁移后,依然能获得原先的数据。这里,我们先要创建NFS,然后通过使用PV为Redis挂载一个远程的NFS路径。
安装NFS
#将需要在挂载的服务器中安装NFS
yum -y install nfs-utils(主包提供文件系统)
yum -y install rpcbind(提供rpc协议)
新增/etc/exports文件,用于设置需要共享的路径:
vim /etc/exports
/home/nfs/pv1 *(rw,sync,no_subtree_check,no_root_squash)
/home/nfs/pv2 *(rw,sync,no_subtree_check,no_root_squash)
/home/nfs/pv3 *(rw,sync,no_subtree_check,no_root_squash)
/home/nfs/pv4 *(rw,sync,no_subtree_check,no_root_squash)
/home/nfs/pv5 *(rw,sync,no_subtree_check,no_root_squash)
/home/nfs/pv6 *(rw,sync,no_subtree_check,no_root_squash)
创建相应目录
mkdir -p /home/nfs/pv{1..6}
启动NFS和rpcbind服务
systemctl enable rpcbind.service
systemctl enable nfs-server.service
systemctl start rpcbind.service
systemctl start nfs-server.service
exportfs -r
systemctl reload nfs-server
查看存储端共享
showmount -e [IP]
2. 创建PV
每一个Redis Pod都需要一个独立的PV来存储自己的数据,因此可以创建一个pv.yaml文件,包含6个PV:
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv1
spec:
capacity:
storage: 200M
accessModes:
- ReadWriteMany
nfs:
server: 192.168.1.23
path: "/home/nfs/pv1"
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv2
spec:
capacity:
storage: 200M
accessModes:
- ReadWriteMany
nfs:
server: 192.168.1.23
path: "/home/nfs/pv2"
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv3
spec:
capacity:
storage: 200M
accessModes:
- ReadWriteMany
nfs:
server: 192.168.1.23
path: "/home/nfs/pv3"
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv4
spec:
capacity:
storage: 200M
accessModes:
- ReadWriteMany
nfs:
server: 192.168.1.23
path: "/home/nfs/pv4"
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv5
spec:
capacity:
storage: 200M
accessModes:
- ReadWriteMany
nfs:
server: 192.168.1.23
path: "/home/nfs/pv5"
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv6
spec:
capacity:
storage: 200M
accessModes:
- ReadWriteMany
nfs:
server: 192.168.1.23
path: "/home/nfs/pv6"
创建PV
kubectl create -f pv.yaml
3. 创建Configmap
这里,我们可以直接将Redis的配置文件转化为Configmap,这是一种更方便的配置读取方式。配置文件redis.conf如下
appendonly yes
cluster-enabled yes
cluster-config-file /var/lib/redis/nodes.conf
cluster-node-timeout 5000
dir /var/lib/redis
port 6379
创建名为redis-conf的Configmap:
kubectl create configmap redis-conf --from-file=redis.conf
4. 创建Headless service
Headless service是StatefulSet实现稳定网络标识的基础,我们需要提前创建。准备文件headless-service.yml如下:
apiVersion: v1
kind: Service
metadata:
name: redis-service
labels:
app: redis
spec:
ports:
- name: redis-port
port: 6379
clusterIP: None
selector:
app: redis
appCluster: redis-cluster
创建
kubectl create -f headless-service.yml
服务名称为redis-service,其CLUSTER-IP为None,表示这是一个“无头”服务。
5. 创建Redis集群节点(v=6.2.6)
创建好Headless service后,就可以利用StatefulSet创建Redis 集群节点,这也是本文的核心内容。我们先创建redis.yml文件:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis-app
spec:
serviceName: "redis-service"
replicas: 6
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
appCluster: redis-cluster
spec:
terminationGracePeriodSeconds: 20
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- redis
topologyKey: kubernetes.io/hostname
containers:
- name: redis
image: redis
command:
- "redis-server"
args:
- "/etc/redis/redis.conf"
- "--protected-mode"
- "no"
resources:
requests:
cpu: "100m"
memory: "100Mi"
ports:
- name: redis
containerPort: 6379
protocol: "TCP"
- name: cluster
containerPort: 16379
protocol: "TCP"
volumeMounts:
- name: "redis-conf"
mountPath: "/etc/redis"
- name: "redis-data"
mountPath: "/var/lib/redis"
volumes:
- name: "redis-conf"
configMap:
name: "redis-conf"
items:
- key: "redis.conf"
path: "redis.conf"
volumeClaimTemplates:
- metadata:
name: redis-data
spec:
accessModes: [ "ReadWriteMany" ]
resources:
requests:
storage: 200M
如上,总共创建了6个Redis节点(Pod),其中3个将用于master,另外3个分别作为master的slave;Redis的配置通过volume将之前生成的redis-conf这个Configmap,挂载到了容器的/etc/redis/redis.conf;Redis的数据存储路径使用volumeClaimTemplates声明(也就是PVC),其会绑定到我们先前创建的PV上。
创建
kubectl apply -f redis.yaml
另外,根据StatefulSet的规则,我们生成的Redis的6个Pod的hostname会被依次命名为 [statefulset名称]-[序号]
如图所示:可以看到这些Pods在部署时是以{0…N-1}的顺序依次创建的。注意,直到redis-app-0状态启动后达到Running状态之后,redis-app-1 才开始启动。
同时,每个Pod都会得到集群内的一个DNS域名,格式为[podname].[service name].[namespace].svc.cluster.local
,也即
redis-app-0.redis-service.default.svc.cluster.local
redis-app-1.redis-service.default.svc.cluster.local
...以此类推...
在K8S集群内部,这些Pod就可以利用该域名互相通信。我们可以使用ubuntu镜像的nslookup检验这些域名:
另外可以发现,我们之前创建的pv都被成功绑定了:
6. 初始化Redis集群
创建好6个Redis Pod后,我们还需要利用常用的Redis-tribe工具进行集群的初始化
由于Redis集群必须在所有节点启动后才能进行初始化,而如果将初始化逻辑写入Statefulset中,则是一件非常复杂而且低效的行为。我们可以在K8S上创建一个额外的容器,专门用于进行K8S集群内部某些服务的管理控制。
这里,我们专门启动一个Ubuntu的容器,可以在该容器中安装Redis-tribe,进而初始化Redis集群.
因为官方的ubuntu
镜像里面的redis初始化的工具是没有的,我已经将初始化时需要的环境都打好了
https://download.csdn.net/download/zxc_123_789/80630356
下载此tar包后将其加载为镜像,然后运行此镜像
kubectl run -it ubuntu --image=ubuntu --restart=Never /bin/bash
初始化集群:
可以使用nslookup redis-app-0.redis-service
命令查看每个节点对应的IP
然后,创建只有Master节点的集群:
redis-trib.py create 10.244.4.16:6379 10.244.1.66:6379 10.244.6.14:6379
其次,为每个Master添加Slave
redis-trib.py replicate --master-addr 10.244.4.16:6379 --slave-addr 10.244.3.25:6379
redis-trib.py replicate --master-addr 10.244.1.66:6379 --slave-addr 10.244.5.27:6379
redis-trib.py replicate --master-addr 10.244.6.14:6379 --slave-addr 10.244.2.71:6379
至此,我们的Redis集群就真正创建完毕了,连到任意一个Redis Pod中检验一下:
kubectl exec -it redis-app-0 bash
另外,还可以在NFS上查看Redis挂载的数据:
7. 创建用于访问Service
前面我们创建了用于实现StatefulSet的Headless Service,但该Service没有Cluster Ip,因此不能用于外界访问。所以,我们还需要创建一个Service,专用于为Redis集群提供访问和负载均衡:
apiVersion: v1
kind: Service
metadata:
name: redis-access-service
labels:
app: redis
spec:
ports:
- name: redis-port
protocol: "TCP"
port: 6379
targetPort: 6379
selector:
app: redis
appCluster: redis-cluster
如上,该Service名称为 redis-access-service
,在K8S集群中暴露6379端口,并且会对labels name为app: redis
或appCluster: redis-cluster
的pod进行负载均衡。
至此,k8s中的3主3从的redis集群环境就搭建好了.