进学阁

业精于勤荒于嬉,行成于思毁于随

0%

构建分布式存储系统(五)

NFS搭建

安装nfs-server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 在每个机器。
yum install -y nfs-utils


# 在master 执行以下命令
echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports


# 执行以下命令,启动 nfs 服务;创建共享目录
mkdir -p /nfs/data


# 在master执行
systemctl enable rpcbind
systemctl enable nfs-server
systemctl start rpcbind
systemctl start nfs-server

# 使配置生效
exportfs -r


#检查配置是否生效
exportfs

配置nfs-client(选做)

1
2
3
4
5
showmount -e 172.31.0.4

mkdir -p /nfs/data

mount -t nfs 172.31.0.4:/nfs/data /nfs/data

配置默认存储

配置动态供应的默认存储类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
## 创建了一个存储类
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-storage
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
archiveOnDelete: "true" ## 删除pv的时候,pv的内容是否要备份

---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
image: registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/nfs-subdir-external-provisioner:v4.0.2
# resources:
# limits:
# cpu: 10m
# requests:
# cpu: 10m
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-subdir-external-provisioner
- name: NFS_SERVER
value: 172.31.0.4 ## 指定自己nfs服务器地址
- name: NFS_PATH
value: /nfs/data ## nfs服务器共享的目录
volumes:
- name: nfs-client-root
nfs:
server: 172.31.0.4
path: /nfs/data
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io

确认是否生效

1
kubectl get sc

Ceph存储集群

Rook介绍

Rook https://rook.io 是一个自管理的分布式存储编排系统,可以为Kubernetes提供便利的存储解决方案。Rook本身并不提供存储,而是在kubernetes和存储系统之间提供适配层,简化存储系统的部署与维护工作。

目前,Rook支持的存储系统包括:Ceph、CockroachDB、Cassandra、EdgeFS、Minio、NFS。当然,Rook支持的最好的还是Cph 和 NFS。

为什么要使用Rook?

使用Rook的其中一个主要好处在于它是通过原生的Kubernetes机制和数据存储交互。这就意味着你不再需要通过命令行手动配置Ceph。

  • 你想要在一个集群里部署CephFS吗?只需要创建一个YAML文件就行了!
  • 什么?你还想要部署一个支持S3 API的对象存储?行,另外再建一个YAML文件就行!

Cpeh介绍

Ceph Ceph Documentation 是一种为优秀的性能、可靠性和可扩展性而设计的统一的、分布式文件系统。ceph 的统一体现在可以提供文件系统、块存储和对象存储,分布式体现在可以动态扩展。

Ceph支持三种存储:

  • 块存储(RDB):可以直接作为磁盘挂载
  • 文件系统(CephFS):提供POSIX兼容的网络文件系统CephFS,专注于高性能、大容量存储
  • 对象存储(RADOSGW):提供RESTful接口,也提供多种编程语言绑定。兼容S3(是AWS里的对象存储)、Swift(是openstack里的对象存储)

核心组件

Ceph 主要有三个基本进程:

  • OSD 用于集群中所有数据与对象的存储,处理集群数据的复制、恢复、回填、再均衡,并向其他osd守护进程发送心跳,然后向 Monitor 提供一些监控信息。
  • Monitor 监控整个集群的状态,维护集群的 cluster MAP 二进制表,保证集群数据的一致性。
  • MDS (可选) 为 Ceph 文件系统提供元数据计算、缓存与同步。MDS 进程并不是必须的进程,只有需要使用 CephFS 时,才需要配置 MDS 节点。

安装Ceph集群

通过rook安装ceph集群需要满足以下两个前提条件:

  • 已部署好的Kubernetes集群 (
  • osd节点需要有未格式化⽂件系统的磁盘(

前置准备

1. 在master1节点下载rook到本地,使用最新版本1.8.8

1
git clone --single-branch --branch v1.8.8 https://github.com/rook/rook.git

2. 给所有需要安装ceph的worker节点安装lvm2

1
2
3
4
5
6
yum install lvm2 -y

#检查是否安装成功
[root@sit-k8s-worker1 ~]# yum list installed | grep lvm2
lvm2.x86_64 7:2.02.187-6.el7_9.5 @iflytekdc-updates
lvm2-libs.x86_64 7:2.02.187-6.el7_9.5 @iflytekdc-updates

3. 给worker节点打上标签,保证ceph只安装在这3台worker节点上

1
2
3
kubectl label node k8s-worker1 role=ceph-storage
kubectl label node k8s-worker2 role=ceph-storage
kubectl label node k8s-worker3 role=ceph-storage

修改完成后使用命令查看label属性

1
2
3
4
5
6
[root@k8s-master1 ~]# kubectl get nodes --show-labels

NAME STATUS ROLES AGE VERSION LABELS
k8s-worker1 Ready worker 3d17h v1.21.5 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-worker1,kubernetes.io/os=linux,node-role.kubernetes.io/worker=,role=ceph-storage
k8s-worker2 Ready worker 3d17h v1.21.5 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-worker2,kubernetes.io/os=linux,node-role.kubernetes.io/worker=,role=ceph-storage
k8s-worker3 Ready worker 3d17h v1.21.5 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-worker3,kubernetes.io/os=linux,node-role.kubernetes.io/worker=,role=ceph-storage
  1. 手动下载安装ceph所需镜像

rook 中ceph依赖很多都是使用国外的镜像,下载很慢,而且经常出现400,所以建议直接手动下载。
注意,以下脚本在所有节点都需要运行(master 和 worker)

创建可执行文件 ceph.sh,内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
image_list=(
csi-node-driver-registrar:v2.5.0
csi-attacher:v3.4.0
csi-snapshotter:v5.0.1
csi-resizer:v1.4.0
csi-provisioner:v3.1.0
)
aliyuncs="registry.aliyuncs.com/it00021hot"
google_gcr="k8s.gcr.io/sig-storage"
for image in ${image_list[*]}
do
docker image pull ${aliyuncs}/${image}
docker image tag ${aliyuncs}/${image} ${google_gcr}/${image}
docker image rm ${aliyuncs}/${image}
echo "${aliyuncs}/${image} ${google_gcr}/${image} downloaded."
done

同时给其授予可执行权限

1
chmod +x ceph.sh

检查镜像是否下载完成

1
docker images | grep csi

5. 修改ceph调度算法,通过节点亲和性让其运行在指定节点上,同时手动指定节点及磁盘

还记得我们之前挂载磁盘的时候给ceph预留了一个空盘吧?现在需要用到了~

先通过lsblk查看盘符,可以看到vdb2是预留给ceph的

然后修改ceph集群配置

1
vim /root/rook/deploy/examples/cluster.yaml

注意,name 不能够配置为IP,而应该是标签 kubernetes.io/hostname 的内容

6. 修改operator.yaml,让CSI守护进程可以调度到主节点

默认情况下master节点是不允许调度的,但是ceph有些守护进程是需要调度到master去。

这一步是为了解决后面出现的问题,如果此时不修改也可以在后面出现问题的时候再改。

这些都是经验教训,网上的安装手册不会告诉你有这一步。

先查看一下master节点的污点设置

1
2
3
[root@k8s-master1 ~]# kubectl describe no/sit-k8s-master1 | grep Taints

Taints: node-role.kubernetes.io/master:NoSchedule

然后修改rook operator的配置

1
vim /root/rook/deploy/examples/operator.yaml

安装ceph集群

ceph 相关镜像较大,创建集群过程中可能会存在镜像拉取失败问题,可以在worker节点提前下载。

所需镜像:

rook/ceph:v1.8.8

quay.io/ceph/ceph: v16.2.7

quay.io/cephcsi/cephcsi:v3.5.1

1. 创建ceph所需要的资源

1
2
cd /root/rook/deploy/examples
kubectl apply -f crds.yaml -f common.yaml -f operator.yaml

执行完成后等待容器启动,只有完全启动后才能执行进行下一步操作。

2. 安装ceph集群

需要先修改一下集群osd的资源限制,否则osd的内存使用率会无限增长(同样是经验教训)

1
2
cd /root/rook/deploy/examples
vim cluster.yaml

在186行处加入资源限制,建议内存设置4G以上,同时需要注意yaml文件的格式。

修改保存后执行以下命令安装ceph集群

1
kubectl apply -f cluster.yaml

创建完成后,可以查看pod的状态:

以上是所有组件的 pod 完成后的状态,以rook-ceph-osd-prepare 开头的 pod 用于自动感知集群新挂载硬盘,只不过我们前面手动指定了节点,所以这个不起作用。osd-0、osd-1、osd-2容器必须是存在且正常的,如果上述pod均正常运行成功,则视为集群安装成功。

安装ceph dashboard

Ceph Dashboard 是一个内置的基于 Web 的管理和监视应用程序,它是开源 Ceph 发行版的一部分。通过 Dashboard 可以获取 Ceph 集群的各种基本状态信息。

默认的 ceph 已经安装的 ceph-dashboard,其 SVC 地址是 service clusterIP,并不能被外部访问,需要创建 service 服务

1
kubectl apply -f dashboard-external-https.yaml

创建NodePort类型就可以被外部访问了

1
2
3
4
[root@k8s-master1 ~]# kubectl get svc -n rook-ceph|grep dashboard

rook-ceph-mgr-dashboard ClusterIP 109.233.40.229 <none> 8443/TCP 8m28s
rook-ceph-mgr-dashboard-external-https NodePort 109.233.34.181 <none> 8443:32234/TCP 29s

浏览器访问(master1-ip换成自己的集群ip): https://master1-ip:32234/

用户名默认是admin,至于密码可以通过以下代码获取:

1
kubectl -n rook-ceph get secret rook-ceph-dashboard-password -o jsonpath="{['data']['password']}"|base64 --decode && echo

安装rook工具箱

Rook 工具箱是一个包含用于 Rook 调试和测试的常用工具的容器,安装很简单

1
2
cd /root/rook/deploy/examples
kubectl apply -f toolbox.yaml -n rook-ceph

待容器Running后,即可执行相关命令:

1
2
3
4
5
6
7
# 查看容器状态
[root@k8s-master1 ~]# kubectl get po -n rook-ceph | grep tools

rook-ceph-tools-775f4f4468-dcg4x 1/1 Running 0 2m12s

# 进入ceph容器
[root@k8s-master1 ~]# kubectl -n rook-ceph exec -it $(kubectl -n rook-ceph get pod -l "app=rook-ceph-tools" -o jsonpath='{.items[0].metadata.name}') -- bash

工具箱相关查询命令

1
2
3
4
ceph status
ceph osd status
ceph df
rados df

部署 RBD StorageClass

Ceph 可以同时提供对象存储 RADOSGW、块存储 RBD、文件系统存储 Ceph FS。RBD 即 RADOS Block Device 的简称,RBD 块存储是最稳定且最常用的存储类型。RBD 块设备类似磁盘可以被挂载。RBD 块设备具有快照、多副本、克隆和一致性等特性,数据以条带化的方式存储在 Ceph 集群的多个 OSD 中。注意:RBD只支持ReadWriteOnce存储类型

1. 创建 StorageClass

1
2
cd /root/rook/deploy/examples/csi/rbd
kubectl apply -f storageclass.yaml

2. 校验pool安装情况

1
2
3
4
5
[root@k8s-master1 ~]# kubectl -n rook-ceph exec -it $(kubectl -n rook-ceph get pod -l "app=rook-ceph-tools" -o jsonpath='{.items[0].metadata.name}') -- bash

[root@rook-ceph-tools-775f4f4468-dcg4x /]# ceph osd lspools
1 device_health_metrics
2 replicapool

3. 查看StorageClass

1
2
3
4
[root@k8s-master1 rbd]# kubectl get sc

NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
rook-ceph-block rook-ceph.rbd.csi.ceph.com Delete Immediate true 43s

4. 将Ceph设置为默认存储卷

1
[root@k8s-master1 ~]# kubectl patch storageclass rook-ceph-block -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

修改完成后再查看StorageClass状态(有个default标识

1
2
3
4
[root@k8s-master1 ~]# kubectl get sc

NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
rook-ceph-block (default) rook-ceph.rbd.csi.ceph.com Delete Immediate true 108s

通过上面的步骤我们已经给Kubernetes集群安装了Ceph存储,至此我们的高可用集群就已经搭建完毕,甚至可以直接在生产环境使用了。同时也可以看到使用Rook安装Ceph还是很简单的,只需要执行对应的yaml文件即可。

不过要注意的是我们目前给集群安装的StorageClass是基于RBD的块存储,只支持ReadWriteOnce存储类型,如果你要使用ReadWriteMany存储类型,还需要安装CephFs存储。