https://segmentfault.com/a/1190000039196137
1、redis启动配置文件,使用CofigMap来管理比较方便,redis-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: redis-config
namespace: default
data:
update-node.sh: |
#!/bin/sh
REDIS_NODES="/data/nodes.conf"
sed -i -e "/myself/ s/[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/${MY_POD_IP}/" ${REDIS_NODES}
exec "$@"
redis.conf: |+
port 7001
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
#cluster-announce-ip ${MY_POD_IP}
#cluster-announce-port 7001
#cluster-announce-bus-port 17001
logfile "/data/redis.log"
说明:2个文件,node-update.sh用来redis启动时执行脚本,具体后面再介绍为何要增加一个启动脚本;redis.conf为redis启动配置文件。
2、redis持久化存储pv,pv使用nfs服务存储,集群6个节点分别创建6个pv不同存储,静态创建pv文件redis-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv0
labels:
pv: nfs-pv0
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
nfs:
server: 192.168.11.242
path: /root/nfs/redis-cluster0
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv1
labels:
pv: nfs-pv1
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
nfs:
server: 192.168.11.242
path: /root/nfs/redis-cluster1
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv2
labels:
pv: nfs-pv2
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
nfs:
server: 192.168.11.242
path: /root/nfs/redis-cluster2
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv3
labels:
pv: nfs-pv3
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
nfs:
server: 192.168.11.242
path: /root/nfs/redis-cluster3
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv4
labels:
pv: nfs-pv4
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
nfs:
server: 192.168.11.242
path: /root/nfs/redis-cluster4
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv5
labels:
pv: nfs-pv5
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
nfs:
server: 192.168.11.242
path: /root/nfs/redis-cluster5
3、使用StatefulSet创建redis-cluster集群节点和headless service
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
app: redis-cluster
name: redis-cluster
namespace: default
spec:
replicas: 6
selector:
matchLabels:
app: redis-cluster
serviceName: redis-cluster
template:
metadata:
labels:
app: redis-cluster
spec:
containers:
- command:
["/bin/bash", "/usr/local/etc/redis/update-node.sh", "redis-server", "/usr/local/etc/redis/redis.conf"]
#args:
# - /usr/local/etc/redis/redis.conf
# - --cluster-announce-ip
# - "$(MY_POD_IP)"
env:
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: TZ
value: Asia/Shanghai
image: 'redis:6.0.10'
imagePullPolicy: IfNotPresent
name: redis
ports:
- containerPort: 7001
hostPort: 7001
name: redis-port
protocol: TCP
volumeMounts:
- mountPath: /data
name: redis-cluster-data
subPath: data
readOnly: false
- mountPath: /usr/local/etc/redis
name: redis-config
readOnly: false
dnsPolicy: ClusterFirst
volumes:
- name: redis-config
configMap:
name: redis-config
volumeClaimTemplates: #PVC模板
- metadata:
name: redis-cluster-data
namespace: default
spec:
accessModes: [ "ReadWriteMany" ]
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
labels:
app: redis-cluster
name: redis-cluster
namespace: default
spec:
ports:
- name: redis-port
port: 7001
protocol: TCP
targetPort: 7001
selector:
app: redis-cluster
type: ClusterIP
clusterIP: None
说明2个点:第一,update-node.sh脚本需要加上bash环境变量,否则脚本启动执行时提示没有权限,这也是网上很多文章并没有提到的;
第二,env环境变量中加了2个,${MY_POD_IP}是节点重启时更新pod的ip地址,TZ就是时区更改;
4、初始化集群
redis-cluster从4.0开始支持命令行直接初始化,不再需要安装ruby了。
kubectl exec -it redis-cluster-0 -- redis-cli -p 7001 --cluster create --cluster-replicas 1 $(kubectl get pods -l k8s.kuboard.cn/name=redis-cluster -o jsonpath='{range.items[*]}{.status.podIP}:7001 ')
5、验证集群
kubectl exec -it redis-cluster-0 -- redis-cli cluster info
redis-cluster集群部署完毕。
问题1,集群初始化时,一直等待 Waiting for the cluster to join
解决:最开始部署时,从使用docker-comopose部署的方法套用过来,由于redis.conf配置文件中参数cluster-announce-ip配置了宿主机的ip,当初始化时集群节点之间需要通讯,但是再k8s中宿主机ip已经不适用,导致无法通讯一致卡住在那个位置。
禁用#cluster-announce-ip
问题2,集群创建时,[ERR] Node 10.244.7.224:7001 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
解决:由于前面初始化集群时卡住,导致部分节点的nodes.conf文件中更新了新节点数据,需要删除数据。可以删除文件,也可以通过如下命令
redis-cli -p 7001 -c 登录每个redis节点重置:
flushdb
cluster reset
问题3,pvc如何和pv一对一绑定?
说明:分静态和动态绑定
首先静态,之前一直没想明白,写好了pv的yaml文件,service里面定义好pvc之后,如何让pv和pvc进行绑定?只要我们定义的pv存储空间大小和pvc申请大小一致就会匹配绑定bound,当然也可以通过lebel标签来关联pvc到特定的pv。
另外,redis集群多个节点,持久化存储目录肯定不能一样,如果yaml中直接指定PVC的名字,只能指定一个名字,这样是办不到关联到多个不同的PV,于是需要volumeClaimTemplates(PVC模板)。
volumeClaimTemplates:
- metadata:
name: redis-cluster-data
namespace: default
spec:
accessModes: [ "ReadWriteMany" ]
resources:
requests:
storage: 1Gi
动态,因为NFS不支持动态存储,所以我们需要借用这个存储插件StorageClass,关联pvc,动态创建pv。分3个步骤,1,定义storage;2,部署授权,因为storage自动创建pv需要经过kube-apiserver,所以要进行授权;3,部署自动创建pv的服务nfs-client-provisioner;4,部署redis服务。
参考链接地址:
https://blog.csdn.net/qq_2561...
以上动态创建pv确实是个好办法,后续有时间再实践操作下。
当然,如果嫌麻烦推荐使用kuboard,手动点点体验也很不错,完全不用自己这么麻烦了哈。
问题4,测试一个节点重启,发现节点重启后,nodes.conf中自己的pod ip 不会更新,倒是其他节点之间通讯会更新pod ip。
解决:上面也提到过,添加一个启动脚本update-node.sh ,每次启动查找podIP后替换nodes.conf文件中myself节点的ip地址就可以解决。注意,网上很多都是通过容器启动时在参数args里面添加pod ip来更新,但我实践过并不行,他们说5.0可以,但是我换5.0也试过并不行。如果有可以的请留言,也有可能是我配置写的不对吧。
最后,以上内容虽然不多,但绝对自己手敲的,希望能分享给大家,这也是年前的最后一篇文章,欢迎留言。