1 环境说明

主机名

系统版本

IP地址

cpu/内存/磁盘

用途

软件版本

k8s_nfs

CentOS7.5

172.16.1.60

2核/2GB/60GB

nfs存储

nfs-utils-1.3.0-0.68

k8s-master1

CentOS7.5

172.16.1.81

2核/2GB/60GB

kubernetes master1节点

k8s v1.20.0

k8s-master2

CentOS7.5

172.16.1.82

2核/2GB/60GB

kubernetes master2节点

k8s v1.20.0

k8s-node1

CentOS7.5

172.16.1.83

4核/8GB/60GB

kubernetes node1节点

k8s v1.20.0

k8s-node2

CentOS7.5

172.16.1.84

4核/8GB/60GB

kubernetes node2节点

k8s v1.20.0

​补充: kubernetes集群的控制节点我打了污点不能被pod调度使用。​

1 nfs服务部署
节点: k8s_nfs
用途: k8s pod 数据持久化存储
说明: nfs服务的搭建过程不再赘述
验证:
[root@k8s_nfs ~]# showmount -e 172.16.1.60
Export list for 172.16.1.60:
/ifs/kubernetes *

2 nfs-subdir-external-provisioner插件部署
节点: kubernetes集群
用途: 为中间件pod提供pvc自动供给
说明: nfs pvc自动供给插件的部署过程不再赘述。修改"deployment.yaml"文件中连接nfs服务的地址和nfs共享目录参数;修改"class.yaml"
文件中"archiveOnDelete"(删除时是否存档)参数为 archiveOnDelete: "true",删除pod时保留pod数据,默认为false时为不保留数据。
注意: 在部署前需要在k8s各个节点上部署nfs的客户端(yum install nfs-utils -y),否则无法部署成功。

补充:
(1) gitlab项目地址: https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
(2) 下载 deploy 目录如下文件
class.yaml、deployment.yaml、rbac.yaml

查看:
[root@k8s-master1 nfs-subdir-external-provisioner-master]# ls | xargs -i kubectl apply -f {}
[root@k8s-master1 nfs-subdir-external-provisioner-master]# kubectl get deployment,pod,svc,sc -n default

在k8s中部署rabbitmq镜像集群_centos

2 rabbitmq集群部署(镜像)

2.1 rabbitmq介绍
1 简介
RabbitMQ是一个开源的消息代理的队列服务器,用来通过普通协议在完全不同的应用之间共享数据。支持异步处理、流量削峰、日志处理、应用解耦。

2 RabbitMQ集群节点之间的认证方式
(1) 通过Erlang Cookie,相当于共享秘钥的概念,长度任意,只要所有节点都一致即可。
(2) rabbitmq server在启动的时候,erlang VM会自动创建一个随机的cookie文件。
cookie文件的位置是/var/lib/rabbitmq/.erlang.cookie 或者 /root/.erlang.cookie,为保证cookie的完全一致,采用从一个节点
copy的方式。
(3) Erlang Cookie是保证不同节点可以相互通信的密钥,要保证集群中的不同节点相互通信必须共享相同的Erlang Cookie。具体的目录存放
在/var/lib/rabbitmq/.erlang.cookie。
(4) 从rabbitmqctl命令的工作原理说起,RabbitMQ底层是通过Erlang架构来实现的,所以rabbitmqctl会启动Erlang节点,并基于Erlang
节点来使用Erlang系统连接RabbitMQ节点,在连接过程中需要正确的Erlang Cookie和节点名称,Erlang节点通过交换Erlang Cookie以获得
认证。

3 RabbitMQ集群模式
(1) 单机模式
(2) 普通集群模式(无高可用性)
(3) 镜像集群模式(高可用性),最常用的集群模式

4 RabbitMQ节点类型
(1) RAM node
只保存状态到内存。内存节点将所有的队列、交换机、绑定、用户、权限和vhost的元数据定义存储在内存中,好处是可以使得像交换机和队列声明等操
作更加的快速。
(2) Disk node
将元数据存储在磁盘中。单节点系统只允许磁盘类型的节点,防止重启RabbitMQ的时候,丢失系统的配置信息。
(3) 内存节点虽然不写入磁盘,但是它执行比磁盘节点要快。RabbitMQ集群中,只需要一个磁盘节点来保存状态就足够了;如果集群中只有内存节点,
那么不能停止它们,否则所有的状态,消息等都会丢失。
(4) RabbitMQ要求在集群中至少有一个磁盘节点,所有其他节点可以是内存节点,当节点加入或者离开集群时,必须要将该变更通知到至少一个磁盘
节点。如果集群中唯一的一个磁盘节点崩溃的话,集群仍然可以保持运行,但是无法进行其他操作(增删改查),直到节点恢复。解决方案:设置两个磁
盘节点,至少有一个是可用的,可以保存元数据的更改。
(5) 为保证数据持久性,当前实验所有node节点跑在disk模式。
2.2 yaml配置文件
1 说明
rabbitmq集群运行在rabbitmq-cluster命名空间下,采用StatefulSet与Headless Service模式部署有状态的RabbitMQ集群。
[root@k8s-master1 ~]# mkdir -p rabbitmq-cluster
[root@k8s-master1 ~]# cd rabbitmq-cluster/
[root@k8s-master1 rabbitmq-cluster]# ls -l
total 0
# rabbitmq集群部署文件
-rw-r--r-- 1 root root 0 Feb 16 14:38 rabbitmq-cluster.yml

2 rabbitmq-cluster.yml
[root@k8s-master1 rabbitmq-cluster]# cat rabbitmq-cluster.yml
---
apiVersion: v1
kind: Service
metadata:
name: rabbitmq-cluster-management
namespace: rabbitmq-cluster
labels:
app: rabbitmq
spec:
ports:
- port: 15672
name: http
nodePort: 30072
selector:
app: rabbitmq
type: NodePort
---
apiVersion: v1
kind: Service
metadata:
name: rabbitmq-cluster
namespace: rabbitmq-cluster
labels:
app: rabbitmq
spec:
ports:
- port: 5672
name: amqp
- port: 4369
name: epmd
- port: 25672
name: rabbitmq-dist
clusterIP: None
selector:
app: rabbitmq
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
namespace: rabbitmq-cluster
name: rabbitmq-cluster
spec:
serviceName: rabbitmq-cluster
replicas: 3
selector:
matchLabels:
app: rabbitmq
template:
metadata:
labels:
app: rabbitmq
spec:
containers:
- name: rabbitmq
image: rabbitmq:3.7.26-management
lifecycle:
postStart:
exec:
command:
- /bin/sh
- -c
- >
if [ -z "$(grep rabbitmq-cluster.rabbitmq-cluster.svc.cluster.local /etc/resolv.conf)" ]; then
cp -a /etc/resolv.conf /etc/resolv.conf.bak;
sed "s/^search \([^ ]\+\)/search rabbitmq-cluster.\1 \1/" /etc/resolv.conf > /etc/resolv.conf.new;
cat /etc/resolv.conf.new > /etc/resolv.conf;
rm /etc/resolv.conf.new;
fi;
until rabbitmqctl node_health_check; do sleep 1; done;
if [ -z "$(rabbitmqctl cluster_status | grep rabbitmq-cluster-0)" ]; then
touch /gotit
rabbitmqctl stop_app;
rabbitmqctl reset;
rabbitmqctl join_cluster rabbit@rabbitmq-cluster-0;
rabbitmqctl start_app;
else
touch /notget
fi;
env:
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: RABBITMQ_ERLANG_COOKIE
value: "YZSDHWMFSMKEMBDHSGGZ"
- name: RABBITMQ_NODENAME
value: "rabbit@$(MY_POD_NAME)"
ports:
- name: http
protocol: TCP
containerPort: 15672
- name: amqp
protocol: TCP
containerPort: 5672
livenessProbe:
tcpSocket:
port: amqp
initialDelaySeconds: 5
timeoutSeconds: 5
periodSeconds: 10
readinessProbe:
tcpSocket:
port: amqp
initialDelaySeconds: 15
timeoutSeconds: 5
periodSeconds: 20
volumeMounts:
- name: rabbitmq-data
mountPath: /var/lib/rabbitmq
volumeClaimTemplates:
- metadata:
name: rabbitmq-data
#annotations:
# volume.beta.kubernetes.io/storage-class: "rabbitmq-nfs-storage"
spec:
storageClassName: "managed-nfs-storage"
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi

(1) rabbitmq端口号说明
4369 # erlang 发现端口
5672 # client 端通信端口
15672 # 管理界面 ui 端口
25672 # server 间内部通信端口
访问 RabbitMQ 管理界面: http://IP:15672/
连接 RabbitMQ 用client端通信端口: amqp://guest:guest@localhost:5672/

(2) yml文件中的脚本说明
1) 修改域名解析
if [ -z "$(grep rabbitmq-cluster.rabbitmq-cluster.svc.cluster.local /etc/resolv.conf)" ]; then
cp -a /etc/resolv.conf /etc/resolv.conf.bak;
sed "s/^search \([^ ]\+\)/search rabbitmq-cluster.\1 \1/" /etc/resolv.conf > /etc/resolv.conf.new;
cat /etc/resolv.conf.new > /etc/resolv.conf;
rm /etc/resolv.conf.new;
fi;

说明:
因为rabbitmq节点加入集群需要使用主机名,添加rabbitmq集群所在svc的域名配置,方便rabbitmq直接使用主机名进行访问,/etc/resolv.conf
文件修改前后变化如下图:

图示: ​

在k8s中部署rabbitmq镜像集群_erlang_02

2) 将rabbitmq节点加入集群
until rabbitmqctl node_health_check; do sleep 1; done;
if [ -z "$(rabbitmqctl cluster_status | grep rabbitmq-cluster-0)" ]; then
touch /gotit
rabbitmqctl stop_app;
rabbitmqctl reset;
rabbitmqctl join_cluster rabbit@rabbitmq-cluster-0;
rabbitmqctl start_app;
else
touch /notget
fi;

说明:
rabbitmq服务启动并且健康检查通过后,将该rabbitmq节点以rabbitmq-cluster-0主机名为基准加入集群中。
2.3 部署
1 创建命名空间
[root@k8s-master1 rabbitmq-cluster]# kubectl create namespace rabbitmq-cluster

2 应用配置文件
[root@k8s-master1 rabbitmq-cluster]# kubectl apply -f rabbitmq-cluster.yml
service/rabbitmq-cluster-management created
service/rabbitmq-cluster created
statefulset.apps/rabbitmq-cluster created
3 查看 rabbitmq 集群 pod
[root@k8s-master1 rabbitmq-cluster]# kubectl get pod -n rabbitmq-cluster

图示: ​

在k8s中部署rabbitmq镜像集群_主机名_03

4 查看 rabbitmq 集群 pvc、pv
[root@k8s-master1 rabbitmq-cluster]# kubectl get pvc -n rabbitmq-cluster
[root@k8s-master1 rabbitmq-cluster]# kubectl get pv

图示: ​

在k8s中部署rabbitmq镜像集群_erlang_04

5 查看 rabbitmq 集群 svc
[root@k8s-master1 rabbitmq-cluster]# kubectl get svc,ep -n rabbitmq-cluster

图示: ​

在k8s中部署rabbitmq镜像集群_erlang_05

6 查看 rabbitmq 集群 nfs 共享存储
[root@k8s_nfs ~]# ls -l /ifs/kubernetes/
[root@k8s_nfs ~]# ls -l /ifs/kubernetes/*/

# RabbitMQ的三个容器节点的.erlang.cookie内容是一致的
[root@k8s_nfs ~]# cat /ifs/kubernetes/*/.erlang.cookie

图示: ​

在k8s中部署rabbitmq镜像集群_主机名_06

7 验证RabbitMQ集群
登录 rabbitmq-0|1|2 容器查看集群状态
[root@k8s-master1 rabbitmq-cluster]# kubectl exec -it pod/rabbitmq-cluster-0 -n rabbitmq-cluster -- bash
root@rabbitmq-cluster-0:/# rabbitmqctl cluster_status

说明: 可以看到rabbitmq集群三节点运行正常。

图示: ​

在k8s中部署rabbitmq镜像集群_主机名_07

8 访问 rabbitmq 集群的 web 界面,查看集群的状态
访问 http://<nodeip>:30072,用户名和密码都是 guest。

图示: ​

在k8s中部署rabbitmq镜像集群_主机名_08

2.4 测试
1 说明
模拟RabbitMQ节点故障,重启其中的一个node节点,比如rabbitmq-cluster-0,然后观察集群状态。

2 删除rabbitmq-cluster-0节点
[root@k8s-master1 rabbitmq-cluster]# kubectl delete pod rabbitmq-cluster-0 -n rabbitmq-cluster
pod "rabbitmq-cluster-0" deleted

说明:
此时在web界面查看集群的状态,先后经历了三个状态,红色表示节点故障,黄色表示节点恢复中(暂不可用),绿色表示节点运行正常。

3 查看pod,发现rabbitmq-cluster-0节点30s左右重启成功
[root@k8s-master1 rabbitmq-cluster]# kubectl get pod -n rabbitmq-cluster
NAME READY STATUS RESTARTS AGE
rabbitmq-cluster-0 1/1 Running 0 30s
rabbitmq-cluster-1 1/1 Running 0 30m
rabbitmq-cluster-2 1/1 Running 0 30m

4 查看RabbitMQ集群状态
发现rabbitmq集群各节点状态正常。
# kubectl exec -it rabbitmq-cluster-1 -n rabbitmq-cluster -- rabbitmqctl cluster_status
Cluster status of node rabbit@rabbitmq-cluster-1 ...
[{nodes,[{disc,['rabbit@rabbitmq-cluster-0','rabbit@rabbitmq-cluster-1',
'rabbit@rabbitmq-cluster-2']}]},
{running_nodes,['rabbit@rabbitmq-cluster-0','rabbit@rabbitmq-cluster-2',
'rabbit@rabbitmq-cluster-1']},
{cluster_name,<<"rabbit@rabbitmq-cluster-0.rabbitmq-cluster.rabbitmq-cluster.svc.cluster.local">>},
{partitions,[]},
{alarms,[{'rabbit@rabbitmq-cluster-0',[]},
{'rabbit@rabbitmq-cluster-2',[]},
{'rabbit@rabbitmq-cluster-1',[]}]}]
[root@k8s-master1 rabbitmq-cluster]#

5 客户端访问RabbitMQ集群地址
(1) 访问域名如下,端口为5672
# kubectl run -i --tty --image busybox:1.28.4 dns-test --restart=Never --rm /bin/sh
/ # nslookup rabbitmq-cluster.rabbitmq-cluster.svc.cluster.local
Server: 172.28.0.2
Address 1: 172.28.0.2 kube-dns.kube-system.svc.cluster.local

Name: rabbitmq-cluster.rabbitmq-cluster.svc.cluster.local
Address 1: 172.27.36.88 rabbitmq-cluster-2.rabbitmq-cluster.rabbitmq-cluster.svc.cluster.local
Address 2: 172.27.169.155 rabbitmq-cluster-1.rabbitmq-cluster.rabbitmq-cluster.svc.cluster.local
Address 3: 172.27.36.87 rabbitmq-cluster-0.rabbitmq-cluster.rabbitmq-cluster.svc.cluster.local
/ #

(2) 连接方式
客户端可以连接RabbitMQ集群中的任意一个节点,如果一个节点故障,客户端自行重新连接到其他的可用节点,也就是说,RabbitMQ集群有"重连"机
制,但是这种集群连接方式对客户端不透明,不太建议这种连接方式。推荐方式,给客户端提供一个统一的透明的集群连接地址,在集群前面部署LVS或
Haproxy,通过四层负载均衡代理RabbitMQ的三个node节点的5672端口。

6 集群故障修复
[root@k8s-master1 rabbitmq-cluster]# kubectl delete -f rabbitmq-cluster.yml
[root@k8s_nfs ~]# rm -rf /ifs/kubernetes/*/*
[root@k8s-master1 rabbitmq-cluster]# kubectl apply -f rabbitmq-cluster.yml