其他分享
首页 > 其他分享> > k8s对接Ceph实现持久化存储(16)

k8s对接Ceph实现持久化存储(16)

作者:互联网

一、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-provisioner
rbd-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
来源: https://www.cnblogs.com/yangmeichong/p/16617501.html