1、概述
我们知道在 Kubernetes 容器编排平台中, 我们可以非常方便的进行应用的扩容缩, 同时也能非常方便的进行业务的迭代,本章主要讲解在Kubernetes1.25搭建Redis单实例和Redis集群主从同步的环境流程步骤, 如果是高频访问重要的线上业务我们最好是部署在物理机器上;
2、Kubernetes环境说明
# 集群信息
[root@k8s-master ~]# kubectl cluster-info
Kubernetes control plane is running at https://10.211.55.11:6443
CoreDNS is running at https://10.211.55.11:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
[root@k8s-master ~]#
# 集群节点
[root@k8s-master ~]# kubectl get nodes -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-master Ready control-plane 18h v1.25.0 10.211.55.11 <none> CentOS Stream 8 4.18.0-408.el8.x86_64 docker://20.10.22
k8s-node1 Ready <none> 18h v1.25.0 10.211.55.12 <none> CentOS Stream 8 4.18.0-408.el8.x86_64 docker://20.10.22
k8s-node2 Ready <none> 18h v1.25.0 10.211.55.13 <none> CentOS Stream 8 4.18.0-408.el8.x86_64 docker://20.10.22
# 动态卷
[root@k8s-master ~]# kubectl get sc -n dev
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-storage storage-nfs Delete Immediate false 6s
动态卷制作如果不会的朋友可以参考这篇文章:https://blog.csdn.net/u011837804/article/details/128692744
3、单例Redis部署
本次我们采用两种方式部署单例Redis
hostPath 方式
警告 ⚠️ 这种方式不推荐
HostPath 卷存在许多安全风险,最佳做法是尽可能避免使用 HostPath。 当必须使用 HostPath 卷时,它的范围应仅限于所需的文件或目录,并以只读方式挂载。
如果通过 AdmissionPolicy 限制 HostPath 对特定目录的访问,则必须要求 volumeMounts 使用 readOnly 挂载以使策略生效。
configMap + 动态卷方式 这种方式是推荐的方式
3.1、准备工作
Redis配置文件/root/redis/redis.conf
# 绑定任意接口、服务端口、后台运行。
bind 0.0.0.0
port 6379
# 非常大的巨坑在使用k8s中的container作为redis容器时其daemonize no一定要设置为no
daemonize no
supervised no
# redis服务pid进程文件名
pidfile "/var/run/redis.pid"
# 关闭保护模式,并配置使用密码访问
protected-mode no
requirepass 123456
# 数据文件保存路径,rdb/AOF文件也保存在这里
dir "/data"
# 日志文件记录文件(notice / verbose)
# /var/log/redis/redis.log
loglevel verbose
logfile "/logs/redis.log"
# 最大客户端连接数
maxclients 10000
# 客户端连接空闲多久后断开连接,单位秒,0表示禁用
timeout 300
tcp-keepalive 60
# 内存初始化
maxmemory 1gb
maxmemory-policy volatile-lru
slowlog-max-len 128
lua-time-limit 5000
# Redis 数据持久化(rdb/aof)配置
# 数据自动保存脚本条件例如300s中有10key发生变化
save 300 100
save 60 10000
# RDB 文件名
dbfilename "dump.rdb"
# 对RDB文件进行压缩,建议以(磁盘)空间换(CPU)时间。
rdbcompression yes
# 版本5的RDB有一个CRC64算法的校验和放在了文件的最后。这将使文件格式更加可靠。
rdbchecksum yes
# RDB自动触发策略是否启用,默认为yes
rdb-save-incremental-fsync yes
# AOF开启
appendonly yes
# AOF文件名
appendfilename "appendonly.aof"
# 可选值 always, everysec,no,建议设置为everysec
appendfsync everysec
# Redis风险命令重命名
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
rename-command FLUSHDB b840fc02d524045429941cc15f59e41cb7be6c53
rename-command FLUSHALL b840fc02d524045429941cc15f59e41cb7be6c54
rename-command EVAL b840fc02d524045429941cc15f59e41cb7be6c55
rename-command DEBUG b840fc02d524045429941cc15f59e41cb7be6c56
# rename-command SHUTDOWN SHUTDOWN
在master中配置Redis相关目录
# 数据与日志存储目录
mkdir /root/redis/{data,logs}
# 配置文件目录已创建好
[root@k8s-master redis]# pwd
/root/redis
[root@k8s-master redis]# ls
data logs redis.conf
[root@k8s-master redis]#
3.2、hostpath卷方式
创建redis-single.yaml
这里通过StatefulSet 部署有状态Redis,生产环境需要通过k8s服务发现机制连接redis,必须用到StatefulSet
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
namespace: dev
spec:
serviceName: redis-single-service
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 6379
name: server
command: [ "redis-server", "/conf/redis.conf" ]
# 单个文件与目录挂载
volumeMounts:
- name: conf
mountPath: /conf/redis.conf
readOnly: true
- name: data
mountPath: /data
- name: logs
mountPath: /logs
# 时区设置
- name: timezone
mountPath: /etc/localtime
volumes:
- name: conf
# 采用hostPath卷,只映射配置文件到pod中
hostPath:
type: FileOrCreate
path: /root/redis/redis.conf
- name: data
# 采用hostPath卷
hostPath:
type: DirectoryOrCreate
path: /root/redis/data
- name: logs
# 采用hostPath卷
hostPath:
type: DirectoryOrCreate
path: /root/redis/logs
# 时区定义
- name: timezone
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
---
apiVersion: v1
kind: Service
metadata:
name: redis-single-service
namespace: dev
spec:
type: ClusterIP
ports:
- port: 6379
targetPort: 6379
name: server
selector:
app: redis
执行效果
# 创建
[root@k8s-master ~]# kubectl apply -f redis-single.yaml
statefulset.apps/redis created
service/redis-single-service created
[root@k8s-master ~]#
# 查看sts
[root@k8s-master ~]# kubectl get sts -n dev
NAME READY AGE
redis 1/1 6s
# 查看svc
[root@k8s-master ~]# kubectl get svc -n dev
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
redis-single-service ClusterIP 10.9.64.181 <none> 6379/TCP 10s
# 查看pod 发现pod被部署在k8s-node1上了
[root@k8s-master ~]# kubectl get pod -n dev -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
redis-0 1/1 Running 0 45s 172.17.36.77 k8s-node1 <none> <none
>
# 查看redis启动日志
[root@k8s-master ~]# kubectl logs redis-0 -n dev
1:C 15 Jan 2023 13:51:13.138 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 15 Jan 2023 13:51:13.138 # Redis version=7.0.7, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 15 Jan 2023 13:51:13.138 # Configuration loaded
1:M 15 Jan 2023 13:51:13.139 * monotonic clock: POSIX clock_gettime
1:M 15 Jan 2023 13:51:13.140 * Running mode=standalone, port=6379.
1:M 15 Jan 2023 13:51:13.140 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
1:M 15 Jan 2023 13:51:13.140 # Server initialized
1:M 15 Jan 2023 13:51:13.141 * Loading RDB produced by version 7.0.7
1:M 15 Jan 2023 13:51:13.141 * RDB age 54 seconds
1:M 15 Jan 2023 13:51:13.141 * RDB memory usage when created 0.82 Mb
1:M 15 Jan 2023 13:51:13.141 * Done loading RDB, keys loaded: 0, keys expired: 0.
1:M 15 Jan 2023 13:51:13.141 * DB loaded from disk: 0.000 seconds
1:M 15 Jan 2023 13:51:13.141 * Ready to accept connections
# 进入容器确认配置文件是否生效 发现我们挂载的配置文件存在,但是是空的 这是为什么呢?
[root@k8s-master ~]# kubectl exec -it redis-0 -n dev /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@redis-0:/data#
root@redis-0:/data# cd /conf/
root@redis-0:/conf# ls
redis.conf
root@redis-0:/conf# cat redis.conf
root@redis-0:/conf#
# 连接redis 发现不需要密码也可以连上,再次确认配置文件未生效
root@redis-0:/conf# redis-cli
127.0.0.1:6379>
127.0.0.1:6379> set test test
OK
127.0.0.1:6379> get test
"test"
127.0.0.1:6379>
问题:在master上创建了配置文件,通过hostpath模式挂载,未生效
原因是,hostpath挂载的是当前pod部署节点上的文件
解决方式:通过定向调度将pod部署在存放配置文件的那台节点上
给指定nodes增加label(我这里选择k8s-node2)
# 查看各个节点当前拥有的label
[root@k8s-master ~]# kubectl get nodes --show-labels=true
NAME STATUS ROLES AGE VERSION LABELS
k8s-master Ready control-plane 24h v1.25.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
k8s-node1 Ready <none> 24h v1.25.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node1,kubernetes.io/os=linux
k8s-node2 Ready <none> 24h v1.25.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node2,kubernetes.io/os=linux
[root@k8s-master ~]#
# 给k8s-node2节点增加 redis=single label
[root@k8s-master ~]# kubectl label nodes k8s-node2 redis=single
node/k8s-node2 labeled
[root@k8s-master ~]#
# 再次查看label 发现已增加
[root@k8s-master ~]# kubectl get nodes --show-labels=true
NAME STATUS ROLES AGE VERSION LABELS
k8s-master Ready control-plane 24h v1.25.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
k8s-node1 Ready <none> 24h v1.25.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node1,kubernetes.io/os=linux
k8s-node2 Ready <none> 24h v1.25.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node2,kubernetes.io/os=linux,redis=single
将配置文件挪动至k8s-node2节点上
修改配置文件定向调度只k8s-node2上
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
namespace: dev
spec:
serviceName: redis-single-service
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
# 通过node选择器,定向调度到k8s-node2节点上,当然也可以nodeName直接设置
nodeSelector:
redis: single
containers:
- name: redis
image: redis:7.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 6379
name: server
command: [ "redis-server", "/conf/redis.conf" ]
# 单个文件与目录挂载
volumeMounts:
- name: conf
mountPath: /conf/redis.conf
readOnly: true
- name: data
mountPath: /data
- name: logs
mountPath: /logs
# 时区设置
- name: timezone
mountPath: /etc/localtime
volumes:
- name: conf
# 采用hostPath卷,只映射配置文件到pod中
hostPath:
type: FileOrCreate
path: /root/redis/redis.conf
- name: data
# 采用hostPath卷
hostPath:
type: DirectoryOrCreate
path: /root/redis/data
- name: logs
# 采用hostPath卷
hostPath:
type: DirectoryOrCreate
path: /root/redis/logs
# 时区定义
- name: timezone
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
---
apiVersion: v1
kind: Service
metadata:
name: redis-single-service
namespace: dev
spec:
type: ClusterIP
ports:
- port: 6379
targetPort: 6379
name: server
selector:
app: redis
执行并查看效果
# 进入容器,查看配置文件并校验
root@redis-0:/conf# ls
redis.conf
root@redis-0:/conf#
# 配置文件已挂载成功
root@redis-0:/conf# more -n 3 redis.conf
# 绑定任意接口、服务端口、后台运行。
bind 0.0.0.0
port 6379
root@redis-0:/conf#
root@redis-0:/conf# redis-cli
127.0.0.1:6379> get test
(error) NOAUTH Authentication required.
127.0.0.1:6379> AUTH 123456
OK
127.0.0.1:6379> set test test
OK
127.0.0.1:6379> get test
"test"
127.0.0.1:6379>
# 进入k8s-node2节点查看log\data文件夹是否已有数据
[root@k8s-node2 redis]# ls
data logs redis.conf
[root@k8s-node2 redis]#
[root@k8s-node2 redis]# ls ./data/
appendonlydir
[root@k8s-node2 redis]# ls ./logs/
redis.log
[root@k8s-node2 redis]#
至此通过hostpath部署单实例redis已部署成功,大家可以看出通过hostpath部署有局限性还是比较多的,这种方式不推荐,下篇文章,我们讲解通过confmap部署单实例redis