一、Ceph简介
官网:https://ceph.com/en/
https://docs.ceph.com/en/latest/start/intro/
ceph 是一种开源的分布式的存储系统 包含以下几种存储类型: 块存储(rbd),对象存储(RADOS Fateway),文件系统(cephfs)
块存储(rbd):
块是一个字节序列(例如,512 字节的数据块)。 基于块的存储接口是使用旋转介质(如硬 盘,CD,软盘甚至传统的 9 轨磁带)存储数据的最常用方法;
Ceph 块设备是精简配置,可调 整大小并存储在 Ceph 集群中多个 OSD 条带化的数据。 Ceph 块设备利用 RADOS 功能,如快 照,复制和一致性。 Ceph 的 RADOS 块设备(RBD)使用内核模块或 librbd 库与 OSD 进行交互;Ceph 的块设备为内核模块或 QVM 等 KVM 以及依赖 libvirt 和 QEMU 与 Ceph 块设备集成的 OpenStack 和 CloudStack 等基于云的计算系统提供高性能和无限可扩展性。 可以使用同一 个集群同时运行 Ceph RADOS Gateway,CephFS 文件系统和 Ceph 块设备。
linux 系统中,ls /dev/下有很多块设备文件,这些文件就是我们添加硬盘时识别出来的; rbd 就是由 Ceph 集群提供出来的块设备。可以这样理解,sda 是通过数据线连接到了真实的 硬盘,而 rbd 是通过网络连接到了 Ceph 集群中的一块存储区域,往 rbd 设备文件写入数据, 最终会被存储到 Ceph 集群的这块区域中;
总结:块设备可理解成一块硬盘,用户可以直接使用不含文件系统的块设备,也可以将其格 式化成特定的文件系统,由文件系统来组织管理存储空间,从而为用户提供丰富而友好的数 据操作支持。
文件系统:
Ceph 文件系统(CephFS)是一个符合 POSIX 标准的文件系统,它使用 Ceph 存储集群来存储 其数据。 Ceph 文件系统使用与 Ceph 块设备相同的 Ceph 存储集群系统。
用户可以在块设备上创建 xfs 文件系统,也可以创建 ext4 等其他文件系统,Ceph 集群实现了自己的文件系统来组织管理集群的存储空间,用户可以直接将 Ceph 集群的文件系统挂载到用户机上使用,Ceph 有了块设备接口,在块设备上完全可以构建一个文件系统,那么 Ceph 为什么还需要文件系统接口呢?
主要是因为应用场景的不同,Ceph 的块设备具有优异的读写性能,但不能多处挂载同时读写,目前主要用在 OpenStack 上作为虚拟磁盘,而 Ceph 的文件系统接口读写性能较块设备接口差,但具有优异的共享性。
对象存储:
Ceph 对象存储使用 Ceph 对象网关守护进程(radosgw),它是一个用于与 Ceph 存储集群交 互的 HTTP 服务器。由于它提供与 OpenStack Swift 和 Amazon S3 兼容的接口,因此 Ceph 对 象网关具有自己的用户管理。 Ceph 对象网关可以将数据存储在用于存储来自 Ceph 文件系统客户端或 Ceph 块设备客户端的数据的相同 Ceph 存储集群中:使用方式就是通过 http 协议上传下载删除对象(文件即对象)。
有了块设备接口存储和文件系统接口存储,为什么还整个对象存储呢?
Ceph 的块设备存储具有优异的存储性能但不具有共享性,而 Ceph 的文件系统具有共享性然而性能较块设备存储差,为什么不权衡一下存储性能和共享性,整个具有共享性而存储性能好于文件系统存储的存储呢,对象存储就这样出现了。
分布式存储的优点:
高可靠:既满足存储读取不丢失,还要保证数据长期存储。 在保证部分硬件损坏后依然可 以保证数据安全
高性能:读写速度快
可扩展:分布式存储的优势就是“分布式”,所谓的“分布式”就是能够将多个物理节点整合在一起形成共享的存储池,节点可以线性扩充,这样可以源源不断的通过扩充节点提升性 能和扩大容量,这是传统存储阵列无法做到的
二、Ceph核心组件介绍
在 ceph 集群中,不管你是想要提供对象存储,块设备存储,还是文件系统存储,所有 Ceph 存储集群部署都是从设置每个 Ceph 节点,网络和 Ceph 存储开始 的。 Ceph 存储集群至少需要一个 Ceph Monitor,Ceph Manager 和 Ceph OSD(对象存储守护进程)。 运行 Ceph Filesystem 客户端时也需要 Ceph 元数据服务器。
Monitors:Ceph 监视器(ceph-mon)维护集群状态的映射,包括监视器映射,管理器映射, OSD 映射和 CRUSH 映射。这些映射是 Ceph 守护进程相互协调所需的关键集群状态。监视器 还负责管理守护进程和客户端之间的身份验证。冗余和高可用性通常至少需要三个监视器。
Managers:Ceph Manager 守护程序(ceph-mgr)负责跟踪运行时指标和 Ceph 集群的当前状态,包括存储利用率,当前性能指标和系统负载。Ceph Manager 守护进程还托管基于 python 的模块来管理和公开 Ceph 集群信息,包括基于 Web 的 Ceph Dashboard 和 REST API。高可用性通常至少需要两名 Managers
Ceph OSD:Ceph OSD(对象存储守护进程,ceph-osd)存储数据,处理数据复制,恢复,重新平衡,并通过检查其他 Ceph OSD 守护进程来获取心跳,为 Ceph 监视器和管理器提供一些 监视信息。冗余和高可用性通常至少需要 3 个 Ceph OSD。
MDS:Ceph 元数据服务器(MDS,ceph-mds)代表 Ceph 文件系统存储元数据(即Ceph 块设备和 Ceph 对象存储不使用 MDS)。 Ceph 元数据服务器允许 POSIX 文件系统用户执行基本命令(如 ls,find 等),而不会给 Ceph 存储集群带来巨大负担。
三、安装Ceph集群
3.1 初始化实验环境
ceph准备3台服务器,每台服务器3块硬盘,k8s可以在一起可以独立,最好独立,但是网络相通
主机名 | IP | 配置 | 用途 |
master | 192.168.10.10 | centos 7.9 4核4G 3块20G硬盘 | ceph控制节点、osd、k8s控制节点 |
node1 | 192.168.10.11 | centos7.9 2核2G 3块20G硬盘 | ceph-mon监控节点、osd、k8s工作节点 |
node2 | 192.168.10.12 | centos7.9 2核2G 3块20G硬盘 | ceph-osd对象存储节点、k8s工作节点 |
# 环境初始化 1.配置主机名并写入到hosts文件中 2.配置ssh信任 3.关闭防火墙、关闭selinux 4.配置Ceph安装源,并将ceph.repo放到每台机器 yum install -y yum-utils && yum-config-manager --add-repo https://dl.fedoraproject.org/pub/epel/7/x86_64/ && sudo yum install --nogpgcheck -y epel-release && sudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 && rm /etc/yum.repos.d/dl.fedoraproject.org* [root@master yum.repos.d]# cat /etc/yum.repos.d/ceph.repo [Ceph] name=Ceph packages for $basearch baseurl=http://mirrors.aliyun.com/ceph/rpm-jewel/el7/x86_64/ enabled=1 gpgcheck=0 type=rpm-md gpgkey=https://mirrors.aliyun.com/ceph/keys/release.asc priority=1 [Ceph-noarch] name=Ceph noarch packages baseurl=http://mirrors.aliyun.com/ceph/rpm-jewel/el7/noarch/ enabled=1 gpgcheck=0 type=rpm-md gpgkey=https://mirrors.aliyun.com/ceph/keys/release.asc priority=1 [ceph-source] name=Ceph source packages baseurl=http://mirrors.aliyun.com/ceph/rpm-jewel/el7/SRPMS/ enabled=1 gpgcheck=0 type=rpm-md gpgkey=https://mirrors.aliyun.com/ceph/keys/release.asc priority=1 清空缓存 yum clean all 生成新的缓存 yum makecache fast 升级 yum 源 yum -y update 5.安装iptables yum install iptables-services -y service iptables stop && systemctl disable iptables 6.时间同步 ntpdate time1.aliyun.com 7. 安装基础软件包 yum install -y yum-utils device-mapper-persistent-data lvm2 wget net-tools nfs-utils lrzsz gcc gcc-c++ make cmake libxml2-devel openssl-devel curl curl-devel unzip sudo ntp libaio-devel wget vim ncurses-devel autoconf automake zlib-devel python-devel epel-release openssh-server socat ipvsadm conntrack ntpdate telnet deltarpm
3.2 安装Ceph集群
# 1.在master节点安装ceph-deploy yum install python-setuptools ceph-deploy -y # 在master、node1、node2节点安装ceph yum install ceph ceph-radosgw -y # 查看ceph版本 [root@master ~]# ceph --version ceph version 10.2.11 (e4b061b47f07f583c92a050d9e84b1813a35671e) # master节点 cd /etc/ceph [root@master ceph]# ceph-deploy new master node1 node2 [root@master ceph]# ls ceph.conf ceph-deploy-ceph.log ceph.mon.keyring rbdmap Ceph 配置文件、一个 monitor 密钥环和一个日志文件
# 2.安装ceph-monitor # 修改ceph配置文件:默认副本数从 3 改成 1;把 osd_pool_default_size = 2加入[global]段,这样只有 2 个 osd 也能达到 active+clean 状态: [root@master ceph]# cat ceph.conf [global] fsid = 11e3daf7-ff48-4770-ae92-9bc6d9612144 mon_initial_members = master, node1, node2 mon_host = 192.168.10.10,192.168.10.11,192.168.10.12 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx osd_pool_default_size = 2 mon clock drift allowed = 0.500 mon clock drift warn backoff = 10 mon clock drift allowed #监视器间允许的时钟漂移量默认值 0.05 mon clock drift warn backoff #时钟偏移警告的退避指数。默认值 5 ceph 对每个mon之间的时间同步延时默认要求在 0.05s 之间,这个时间有的时候太短了。所以如果 ceph 集群如果出现 clock 问题就检查 ntp 时间同步或者适当放宽这个误差时间。 cephx 是认证机制是整个 Ceph 系统的用户名/密码
# 3.配置初始 monitor、收集所有的密钥 [root@master ceph]# ceph-deploy mon create-initial [root@master ceph]# ls *.keyring ceph.bootstrap-mds.keyring ceph.bootstrap-mgr.keyring ceph.bootstrap-osd.keyring ceph.bootstrap-rgw.keyring ceph.client.admin.keyring ceph.mon.keyring # 4.部署osd [root@master ceph]# ceph-deploy osd prepare master:/dev/sdb [root@master ceph]# ceph-deploy osd prepare node1:/dev/sdb [root@master ceph]# ceph-deploy osd prepare node2:/dev/sdb # 查看磁盘 [root@master ceph]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 40G 0 disk ├─sda1 8:1 0 1G 0 part /boot └─sda2 8:2 0 39G 0 part ├─centos-root 253:0 0 35G 0 lvm / └─centos-swap 253:1 0 4G 0 lvm sdb 8:16 0 20G 0 disk ├─sdb1 8:17 0 15G 0 part /var/lib/ceph/osd/ceph-0 └─sdb2 8:18 0 5G 0 part sdc 8:32 0 20G 0 disk sr0 11:0 1 973M 0 rom # 激活osd [root@master ceph]# ceph-deploy osd activate master:/dev/sdb1 [root@master ceph]# ceph-deploy osd activate node1:/dev/sdb1 [root@master ceph]# ceph-deploy osd activate node2:/dev/sdb1 # 查看osd [root@master ceph]# ceph osd tree ID WEIGHT TYPE NAME UP/DOWN REWEIGHT PRIMARY-AFFINITY -1 0.04376 root default -2 0.01459 host master 0 0.01459 osd.0 up 1.00000 1.00000 -3 0.01459 host node1 1 0.01459 osd.1 up 1.00000 1.00000 -4 0.01459 host node2 2 0.01459 osd.2 up 1.00000 1.00000 # 查看状态 [root@master ceph]# ceph-deploy osd list master node1 node2
3.3 创建ceph文件系统
# 5.创建mds [root@master ceph]# ceph-deploy mds create master node1 node2 #查看是否有文件系统 [root@master ceph]# ceph fs ls No filesystems enabled # 6.创建存储池 [root@master ceph]# ceph osd pool create cephfs_data 26 pool 'cephfs_data' created [root@master ceph]# ceph osd pool create cephfs_metadata 26 pool 'cephfs_metadata' created # 创建文件系统 [root@master ceph]# ceph fs new simon cephfs_metadata cephfs_data new fs with metadata pool 2 and data pool 1
其中:new 后的fsname可自定义
[root@master ceph]# ceph fs ls name: simon, metadata pool: cephfs_metadata, data pools: [cephfs_data ]. # 查看mds [root@master ceph]# ceph mds stat e7: 1/1/1 up {0=node2=up:active}, 2 up:standby
active 是活跃的,另 1 个是处于热备份的状态
一个 cephfs 至少要求两个 librados 存储池,一个为 data,一个为 metadata。当配置这两个存储池时,注意:
1. 为 metadata pool 设置较高级别的副本级别,因为 metadata 的损坏可能导致整个文件系统不用
2. 建议,metadata pool 使用低延时存储,比如 SSD,因为 metadata 会直接影响客户端的响应速度。
关于创建存储池:
确定 pg_num 取值是强制性的,因为不能自动计算。下面是几个常用的值: *少于 5 个 OSD 时可把 pg_num 设置为 128 *OSD 数量在 5 到 10 个时,可把 pg_num 设置为 512 *OSD 数量在 10 到 50 个时,可把 pg_num 设置为 4096 *OSD 数量大于 50 时,你得理解权衡方法、以及如何自己计算 pg_num 取值 *自己计算 pg_num 取值时可借助 pgcalc 工具 随着 OSD 数量的增加,正确的 pg_num 取值变得更加重要,因为它显著地影响着集群的行为、以及出错时的数据持久性(即灾难性事件导致数据丢失的概率)。
# health HEALTH_OK表示集群正常 [root@master ceph]# ceph -s cluster 11e3daf7-ff48-4770-ae92-9bc6d9612144 health HEALTH_OK monmap e1: 3 mons at {master=192.168.10.10:6789/0,node1=192.168.10.11:6789/0,node2=192.168.10.12:6789/0} election epoch 6, quorum 0,1,2 master,node1,node2 fsmap e7: 1/1/1 up {0=node2=up:active}, 2 up:standby osdmap e20: 3 osds: 3 up, 3 in flags sortbitwise,require_jewel_osds pgmap v46: 116 pgs, 3 pools, 2068 bytes data, 20 objects 323 MB used, 45723 MB / 46046 MB avail 116 active+clean
3.4 测试k8s挂载ceph rbd
# ceph网段和k8s网段一定要能ping通 [root@master ceph]# kubectl get nodes NAME STATUS ROLES AGE VERSION master Ready control-plane,master 11d v1.20.7 node1 Ready worker 11d v1.20.7 node2 Ready worker 11d v1.20.7 # 1.在 k8s 的各个节点 yum install ceph-common -y # 2.将ceph配置文件拷贝到k8s控制节点和工作节点 scp /etc/ceph/* node1:/etc/ceph/ # 3.创建ceph rbd # 先创建pool池k8srbd1,占用pgs为56 [root@master ceph]# ceph osd pool create k8srbd1 56 pool 'k8srbd1' created # 在pool池k8srbd1 创建rbd,名称rbda,rbda大小为1024M [root@master ceph]# rbd create rbda -s 1024 -p k8srbd1 # 禁用,挂载rbd不会出现问题 [root@master ceph]# rbd feature disable k8srbd1/rbda object-map fast-diff deep-flatten
# 在k8s控制机创建ceph配置文件目录 mkdir /root/ceph cd /root/ceph [root@master ceph]# cat pod.yaml apiVersion: v1 kind: Pod metadata: name: testrbd spec: containers: - image: nginx name: nginx imagePullPolicy: IfNotPresent volumeMounts: - name: testrbd mountPath: /mnt volumes: - name: testrbd rbd: monitors: - '192.168.10.10:6789' - '192.168.10.11:6789' - '192.168.10.12:6789' pool: k8srbd1 image: rbda fsType: xfs readOnly: false user: admin keyring: /etc/ceph/ceph.client.admin.keyring [root@master ceph]# kubectl apply -f pod.yaml pod/testrbd created [root@master ceph]# kubectl get pods NAME READY STATUS RESTARTS AGE testrbd 1/1 Running 0 49s [root@master ceph]# kubectl describe pods testrbd Volumes: testrbd: Type: RBD (a Rados Block Device mount on the host that shares a pod's lifetime) CephMonitors: [192.168.10.10:6789 192.168.10.11:6789 192.168.10.12:6789] RBDImage: rbda FSType: xfs RBDPool: k8srbd1 RadosUser: admin Keyring: /etc/ceph/ceph.client.admin.keyring SecretRef: nil ReadOnly: false default-token-cj9pm: Type: Secret (a volume populated by a Secret) SecretName: default-token-cj9pm Optional: false
[root@master ceph]# kubectl exec -it testrbd -- /bin/sh # df -h Filesystem Size Used Avail Use% Mounted on overlay 17G 9.6G 7.5G 57% / tmpfs 64M 0 64M 0% /dev tmpfs 910M 0 910M 0% /sys/fs/cgroup /dev/rbd0 1014M 33M 982M 4% /mnt /dev/mapper/centos-root 17G 9.6G 7.5G 57% /etc/hosts shm 64M 0 64M 0% /dev/shm tmpfs 910M 12K 910M 1% /run/secrets/kubernetes.io/serviceaccount tmpfs 910M 0 910M 0% /proc/acpi tmpfs 910M 0 910M 0% /proc/scsi tmpfs 910M 0 910M 0% /sys/firmware # 之前创建的pool池里rbda已经被使用,如果再次挂载,pod会变成pending状态,不创建就卡着 [root@master ceph]# kubectl get pods NAME READY STATUS RESTARTS AGE testrbd 1/1 Running 0 8m37s testrbd1 0/1 Pending 0 118s # 可以发现rbda已经被使用了 [root@master ceph]# kubectl describe pods testrbd1 Normal SuccessfulAttachVolume 59s attachdetach-controller AttachVolume.Attach succeeded for volume "testrbd" Warning FailedMount 1s kubelet MountVolume.WaitForAttach failed for volume "testrbd" : rbd image k8srbd1/rbda is still being used # 再次在k8srbd1里创建一个rbda1 [root@master ceph]# rbd create rbda1 -s 1024 -p k8srbd1 [root@master ceph]# rbd feature disable k8srbd1/rbda1 object-map fast-diff deep-flatten [root@master ceph]# kubectl apply -f pod-1.yaml pod/testrbd1 created # pod-1.yaml只需要修改name和image: rbda1 [root@master ceph]# kubectl get pods NAME READY STATUS RESTARTS AGE testrbd 1/1 Running 0 17m testrbd1 1/1 Running 0 58s
3.5 基于ceph rbd生成pv
(1)创建 ceph-secret 这个 k8s secret 对象,这个 secret 对象用于 k8s volume 插件访问 ceph 集群,获取 client.admin 的 keyring 值,并用 base64 编码,在 master(ceph 管理节点)操作
[root@master ceph]# ceph auth get-key client.admin|base64 # ceph控制节点
QVFCYWh3UmpDWjlkSHhBQW9CN2hGbk1LSFhubE1URmNqRzllbEE9PQ==
(2)创建 ceph 的 secret,在 k8s 的控制节点操作,创建yaml文件:
[root@master ceph]# cat ceph-secret.yaml # k8s控制节点 apiVersion: v1 kind: Secret metadata: name: ceph-secret data: key: QVFCYWh3UmpDWjlkSHhBQW9CN2hGbk1LSFhubE1URmNqRzllbEE9PQ== [root@master ceph]# kubectl apply -f ceph-secret.yaml secret/ceph-secret created # 3.回到ceph管理节点创建pool池 [root@master ceph]# ceph osd pool create k8stest 56 pool 'k8stest' created [root@master ceph]# rbd create rbda -s 1024 -p k8stest [root@master ceph]# rbd feature disable k8stest/rbda object-map fast-diff deep-flatten
# 4. 创建pv [root@master ceph]# cat pv.yaml apiVersion: v1 kind: PersistentVolume metadata: name: ceph-pv spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce rbd: monitors: - '192.168.10.10:6789' - '192.168.10.11:6789' - '192.168.10.12:6789' pool: k8stest image: rbda user: admin secretRef: name: ceph-secret fsType: xfs readOnly: false persistentVolumeReclaimPolicy: Recycle [root@master ceph]# kubectl apply -f pv.yaml persistentvolume/ceph-pv created [root@master ceph]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE ceph-pv 1Gi RWO Recycle Available 4s # 5.创建pvc [root@master ceph]# cat pvc.yaml kind: PersistentVolumeClaim apiVersion: v1 metadata: name: ceph-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi persistentvolumeclaim/ceph-pvc created [root@master ceph]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE ceph-pvc Bound ceph-pv 1Gi RWO 3s # 6.测试挂载pvc:把pvc做成卷 [root@master ceph]# cat pod-2.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: selector: matchLabels: app: nginx replicas: 2 # tells deployment to run 2 pods matching the template template: # create pods using pod definition in this template metadata: labels: app: nginx spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent ports: - containerPort: 80 volumeMounts: - mountPath: "/ceph-data" name: ceph-data volumes: - name: ceph-data persistentVolumeClaim: claimName: ceph-pvc [root@master ceph]# kubectl apply -f pod-2.yaml deployment.apps/nginx-deployment created [root@master ceph]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-deployment-fdff5b9c8-9r4mj 1/1 Running 0 5m38s nginx-deployment-fdff5b9c8-htf6s 0/1 ContainerCreating 0 5m38s # 出现下面这个情况的原因是:2个nginx分别部署在不同的node工作节点上 [root@master ceph]# kubectl describe pods nginx-deployment-fdff5b9c8-htf6s Warning FailedAttachVolume 83s attachdetach-controller Multi-Attach error for volume "ceph-pv" Volume is already used by pod(s) nginx-deployment-fdff5b9c8-9r4mj
# 删除重建可以成功 kubectl delete pods nginx-deployment-fdff5b9c8-htf6s
[root@master ceph]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-fdff5b9c8-9r4mj 1/1 Running 0 16m
nginx-deployment-fdff5b9c8-twtms 1/1 Running 0 17s
通过上面实验可以发现 pod 是可以以 ReadWriteOnce 共享挂载相同的 pvc 的
注意:ceph rbd 块存储的特点
ceph rbd 块存储能在同一个 node 上跨 pod 以 ReadWriteOnce 共享挂载
ceph rbd 块存储能在同一个 node 上同一个 pod 多个容器中以 ReadWriteOnce 共享挂载
ceph rbd 块存储不能跨 node 以 ReadWriteOnce 共享挂载
如果一个使用ceph rdb 的pod所在的node挂掉,这个pod虽然会被调度到其它node, 但是由于 rbd 不能跨 node 多次挂载和挂掉的 pod 不能自动解绑 pv 的问题,这个新 pod 不会正常运行
Deployment 更新特性:
deployment 触发更新的时候,它确保至少所需 Pods 75% 处于运行状态(最大不可用 比例为 25%)。故像一个 pod 的情况,肯定是新创建一个新的 pod,新 pod 运行正常之 后,再关闭老的 pod。
默认情况下,它可确保启动的 Pod 个数比期望个数最多多出 25%
问题:
结合 ceph rbd 共享挂载的特性和 deployment 更新的特性,我们发现原因如下:
由于 deployment 触发更新,为了保证服务的可用性,deployment 要先创建一个 pod 并运行正常之后,再去删除老 pod。而如果新创建的 pod 和老 pod 不在一个 node,就 会导致此故障。
解决办法:
1,使用能支持跨 node 和 pod 之间挂载的共享存储,例如 cephfs,GlusterFS 等
2,给 node 添加 label,只允许 deployment 所管理的 pod 调度到一个固定的 node 上。 (不建议,这个 node 挂掉的话,服务就故障了)
3.6 基于Storageclass 动态生成pv
kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: rbd-provisioner rules: - 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"] - apiGroups: [""] resources: ["services"] resourceNames: ["kube-dns","coredns"] verbs: ["list", "get"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: rbd-provisioner subjects: - kind: ServiceAccount name: rbd-provisioner namespace: default roleRef: kind: ClusterRole name: rbd-provisioner apiGroup: rbac.authorization.k8s.io --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: rbd-provisioner rules: - apiGroups: [""] resources: ["secrets"] verbs: ["get"] - apiGroups: [""] resources: ["endpoints"] verbs: ["get", "list", "watch", "create", "update", "patch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: rbd-provisioner roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: rbd-provisioner subjects: - kind: ServiceAccount name: rbd-provisioner namespace: default --- apiVersion: apps/v1 kind: Deployment metadata: name: rbd-provisioner spec: selector: matchLabels: app: rbd-provisioner replicas: 1 strategy: type: Recreate template: metadata: labels: app: rbd-provisioner spec: containers: - name: rbd-provisioner image: quay.io/xianchao/external_storage/rbd-provisioner:v1 imagePullPolicy: IfNotPresent env: - name: PROVISIONER_NAME value: ceph.com/rbd serviceAccount: rbd-provisioner --- apiVersion: v1 kind: ServiceAccount metadata: name: rbd-provisionerrbd-provisioner.yaml
# 1.创建rbd的供应商,#把 rbd-provisioner.tar.gz 上传到node上,导入镜像 docker load -i rbd-provisioner.tar.gz Loaded image: quay.io/xianchao/external_storage/rbd-provisioner:v1 [root@master ceph]# kubectl apply -f rbd-provisioner.yaml clusterrole.rbac.authorization.k8s.io/rbd-provisioner created clusterrolebinding.rbac.authorization.k8s.io/rbd-provisioner created role.rbac.authorization.k8s.io/rbd-provisioner created rolebinding.rbac.authorization.k8s.io/rbd-provisioner created deployment.apps/rbd-provisioner created serviceaccount/rbd-provisioner created [root@master ceph]# kubectl get pods NAME READY STATUS RESTARTS AGE rbd-provisioner-685746688f-nnsrh 1/1 Running 0 112s # 2.创建ceph-secret-1.yaml和之前一样获取设置key值 cd /etc/ceph ceph auth get-key client.admin| base64 [root@master ceph]# cat ceph-secret-1.yaml apiVersion: v1 kind: Secret metadata: name: ceph-secret-1 type: "ceph.com/rbd" # 和rbd-provisioner一致 data: key: QVFCYWh3UmpDWjlkSHhBQW9CN2hGbk1LSFhubE1URmNqRzllbEE9PQ== [root@master ceph]# kubectl apply -f ceph-secret-1.yaml secret/ceph-secret-1 created [root@master ceph]# kubectl get Secret NAME TYPE DATA AGE ceph-secret Opaque 1 61m ceph-secret-1 ceph.com/rbd 1 7s # 创建pool池 [root@master ceph]# ceph osd pool create k8stest1 56 pool 'k8stest1' created
# 3.创建storageclass [root@master ceph]# cat storageclass.yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: k8s-rbd provisioner: ceph.com/rbd parameters: monitors: 192.168.10.10:6789,192.168.10.11:6789,192.168.10.12:6789 adminId: admin adminSecretName: ceph-secret-1 pool: k8stest1 userId: admin userSecretName: ceph-secret-1 fsType: xfs imageFormat: "2" imageFeatures: "layering" [root@master ceph]# kubectl apply -f storageclass.yaml storageclass.storage.k8s.io/k8s-rbd created [root@master ceph]# kubectl get StorageClass NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE k8s-rbd ceph.com/rbd Delete Immediate false 20s # 查看rbd-provisioner-685746688f-nnsrh日志发现有一个报错,报错原因是 1.20 版本仅用了 selfLink [root@master ceph]# kubectl logs rbd-provisioner-685746688f-nnsrh E0823 10:00:41.362761 1 event.go:259] Could not construct reference to: '&v1.Endpoints{TypeMeta:v1.TypeMeta{Kind:"", APIVersion:""},
ObjectMeta:v1.ObjectMeta{Name:"ceph.com-rbd", GenerateName:"", Namespace:"default", SelfLink:"", UID:"58a63d0d-6870-4be5-a8ba-83fc0ee0343b", ResourceVersion:"87013",
Generation:0, CreationTimestamp:v1.Time{Time:time.Time{wall:0x0, ext:63796845641, loc:(*time.Location)(0x1bc94e0)}}, DeletionTimestamp:(*v1.Time)(nil),
DeletionGracePeriodSeconds:(*int64)(nil), Labels:map[string]string(nil), Annotations:map[string]string{"control-plane.alpha.kubernetes.io/leader":
"{\"holderIdentity\":\"rbd-provisioner-685746688f-nnsrh_723aeee5-22ca-11ed-8eb6-ce86e577e758\",\"leaseDurationSeconds\":15,\"acquireTime\":\"2022-08-23T10:00:41Z\",
\"renewTime\":\"2022-08-23T10:00:41Z\",\"leaderTransitions\":0}"}, OwnerReferences:[]v1.OwnerReference(nil), Initializers:(*v1.Initializers)(nil), Finalizers:[]string(nil),
ClusterName:""}, Subsets:[]v1.EndpointSubset(nil)}' due to: 'selfLink was empty, can't make reference'. Will not report event: 'Normal' 'LeaderElection'
'rbd-provisioner-685746688f-nnsrh_723aeee5-22ca-11ed-8eb6-ce86e577e758 became leader' # 生产环境一定要是高可用,否则可能会影响业务 # 解决方法: # api配置文件中新增一条 vim /etc/kubernetes/manifests/kube-apiserver.yaml - --feature-gates=RemoveSelfLink=false [root@master ceph]# kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml pod/kube-apiserver created # 然后删除临时生成的kube-apiserver状态为CrashLoopBackOff的pod节点 # 如果是高可用的集群,改完生效后删除临时pod,再去改第二个控制节点 [root@master ceph]# kubectl delete pods kube-apiserver -n kube-system pod "kube-apiserver" deleted # 4.创建pvc [root@master ceph]# cat rbd-pvc.yaml kind: PersistentVolumeClaim apiVersion: v1 metadata: name: rbd-pvc spec: accessModes: - ReadWriteOnce volumeMode: Filesystem resources: requests: storage: 1Gi storageClassName: k8s-rbd [root@master ceph]# kubectl apply -f rbd-pvc.yaml persistentvolumeclaim/rbd-pvc created # 已经绑定到自动创建的STORAGECLASS里了 [root@master ceph]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE rbd-pvc Bound pvc-c854c881-d01f-4da3-804e-41e80aa80515 1Gi RWO k8s-rbd 4s # 查看rbd-pvc日志 [root@master ceph]# kubectl describe pvc rbd-pvc
# 5.创建pod,挂载pvc [root@master ceph]# cat pod-sto.yaml apiVersion: v1 kind: Pod metadata: labels: test: rbd-pod name: ceph-rbd-pod spec: containers: - name: ceph-rbd-nginx image: nginx imagePullPolicy: IfNotPresent volumeMounts: - name: ceph-rbd mountPath: /mnt readOnly: false volumes: - name: ceph-rbd persistentVolumeClaim: claimName: rbd-pvc [root@master ceph]# kubectl apply -f pod-sto.yaml pod/ceph-rbd-pod created [root@master ceph]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES ceph-rbd-pod 1/1 Running 0 30s 10.244.104.3 node2 <none> <none>
3.7 k8s挂载cephfs
[root@master ceph]# ceph fs ls name: simon, metadata pool: cephfs_metadata, data pools: [cephfs_data ] # 1.创建ceph子目录 为了别的地方能挂载 cephfs,先创建一个 secretfile [root@master ceph]# cat /etc/ceph/ceph.client.admin.keyring |grep key|awk -F" " '{print $3}' > /etc/ceph/admin.secret 挂载 cephfs 的根目录到集群的 mon 节点下的一个目录,比如data,因为挂载后,我们就可以直接在data 下面用 Linux 命令创建子目录了。 [root@master ~]# mkdir /root/data [root@master ~]# mount -t ceph 192.168.10.12:6789:/ /root/data -o name=admin,secretfile=/etc/ceph/admin.secret [root@master ~]# df -h 文件系统 容量 已用 可用 已用% 挂载点 192.168.10.12:6789:/ 45G 408M 45G 1% /root/data 在 cephfs 的根目录里面创建了一个子目录 lucky,k8s 以后就可以挂载这个目录 [root@master data]# mkdir /root/data/lucky [root@master data]# chmod 0777 lucky #2.测试k8s的pod挂载cephfs # 创建k8s链接ceph使用secret 将/etc/ceph/ceph.client.admin.keyring 里面的 key 的值转换为 base64 [root@master ceph]# cat cephfs-secret.yaml apiVersion: v1 kind: Secret metadata: name: cephfs-secret data: key: QVFCYWh3UmpDWjlkSHhBQW9CN2hGbk1LSFhubE1URmNqRzllbEE9PQ== [root@master ceph]# kubectl apply -f cephfs-secret.yaml secret/cephfs-secret created [root@master ceph]# kubectl get Secret NAME TYPE DATA AGE cephfs-secret Opaque 1 10s # 3.创建pv [root@master ceph]# cat cephfs-pv.yaml apiVersion: v1 kind: PersistentVolume metadata: name: cephfs-pv spec: capacity: storage: 1Gi accessModes: - ReadWriteMany cephfs: monitors: - 192.168.10.12:6789 path: /lucky user: admin readOnly: false secretRef: name: cephfs-secret persistentVolumeReclaimPolicy: Recycle # 4.创建pvc [root@master ceph]# cat cephfs-pvc.yaml kind: PersistentVolumeClaim apiVersion: v1 metadata: name: cephfs-pvc spec: accessModes: - ReadWriteMany volumeName: cephfs-pv resources: requests: storage: 1Gi [root@master ceph]# kubectl apply -f cephfs-pv.yaml persistentvolume/cephfs-pv created [root@master ceph]# kubectl apply -f cephfs-pvc.yaml persistentvolumeclaim/cephfs-pvc created [root@master ceph]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE cephfs-pv 1Gi RWX Recycle Bound default/cephfs-pvc 10s [root@master ceph]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE cephfs-pvc Bound cephfs-pv 1Gi RWX 6s # 创建pod,挂载cephfs-pvc [root@master ceph]# cat cephfs-pod-1.yaml apiVersion: v1 kind: Pod metadata: name: cephfs-pod-1 spec: containers: - image: nginx name: nginx imagePullPolicy: IfNotPresent volumeMounts: - name: test-v1 mountPath: /mnt volumes: - name: test-v1 persistentVolumeClaim: claimName: cephfs-pvc [root@master ceph]# cat cephfs-pod-2.yaml apiVersion: v1 kind: Pod metadata: name: cephfs-pod-2 spec: containers: - image: nginx name: nginx imagePullPolicy: IfNotPresent volumeMounts: - name: test-v1 mountPath: /mnt volumes: - name: test-v1 persistentVolumeClaim: claimName: cephfs-pvc [root@master ceph]# kubectl apply -f cephfs-pod-1.yaml pod/cephfs-pod-1 created [root@master ceph]# kubectl apply -f cephfs-pod-2.yaml pod/cephfs-pod-2 created [root@master ceph]# kubectl get pods NAME READY STATUS RESTARTS AGE cephfs-pod-1 1/1 Running 0 76s cephfs-pod-2 1/1 Running 0 32s # 测试 [root@master ceph]# kubectl exec -it cephfs-pod-1 -- /bin/sh # cd /mnt # ls # touch hello # echo aa > 1.txt # touch welcome # exit [root@master lucky]# kubectl exec -it cephfs-pod-2 -- /bin/sh # cd /mnt #echo 222> 2.txt # exit # 查看cephfs文件目录下内容 [root@master lucky]# pwd /root/data/lucky [root@master lucky]# ls 1.txt 2.txt hello welcome [root@master lucky]# cat 1.txt aa [root@master lucky]# cat 2.txt 222 [root@master lucky]# echo aaaaaa > a.txt [root@master lucky]# kubectl exec -it cephfs-pod-2 -- /bin/sh # cd /mnt # cat a.txt aaaaaa
标签:ceph,rbd,16,Ceph,master,pod,k8s,root From: https://www.cnblogs.com/yangmeichong/p/16617501.html