Title: kubernetes Ceph RBD

Categories: kubernetes

Description: kubernetes Ceph RBD

Keywords: kubernetes

使用 Ceph RBD 做为 Kubernetes 后端存储

Ceph 安装部署

由于这里我们使用 RBD 所以我们使用到的组件为 Ceph.mon, Ceph.osd, 这两个组件就可以了。 Ceph.mds 为 cephfs 所需组件

部署环境

# Ceph.Mon = 2n+1 个 ,3个的情况下只能掉线一个,如果同时2个掉线
# 集群会出现无法仲裁,集群会一直等待 Ceph.Mon 恢复超过半数。

172.16.1.37  Ceph.admin + Ceph.Mon
172.16.1.38  Ceph.Mon + Ceph.osd
172.16.1.39  Ceph.Mon + Ceph.osd
172.16.1.40  Ceph.osd

初始化环境

# 1. ceph 对时间要求很严格, 一定要同步所有的服务器时间

# 2. 配置 hosts

cat << "EOF" >> /etc/hosts
# --- Ceph Hosts -----
172.16.1.37  ceph-node-1
172.16.1.38  ceph-node-2
172.16.1.39  ceph-node-3
172.16.1.40  ceph-node-4
# --- Ceph Hosts -----
EOF


# 3. 配置 hostname

hostnamectl --static set-hostname ceph-node-1
hostnamectl --static set-hostname ceph-node-2
hostnamectl --static set-hostname ceph-node-3
hostnamectl --static set-hostname ceph-node-4


# 4. Ceph.admin 节点 配置无密码ssh

ssh-keygen
ssh-copy-id ceph-node-1 -p33
ssh-copy-id ceph-node-2 -p33
ssh-copy-id ceph-node-3 -p33
ssh-copy-id ceph-node-4 -p33

Now try logging into the machine, with:   "ssh -p '33' 'ceph-node-2'"



# 5. 增加 ~/.ssh/config 文件, 否则 ceph-deploy 创建集群 报端口错误
[root@ceph-node-1 ~]# vi ~/.ssh/config

Host ceph-node-1
    Hostname ceph-node-1
    Port 33
Host ceph-node-2
    Hostname ceph-node-2
    Port 33
Host ceph-node-3
    Hostname ceph-node-3
    Port 33
Host ceph-node-4
    Hostname ceph-node-4
    Port 33

安装 Ceph-deploy

# 管理节点 安装 ceph-deploy 管理工具
# 配置 官方 的 Ceph 源

rpm --import https://download.ceph.com/keys/release.asc
rpm -Uvh --replacepkgs https://download.ceph.com/rpm-jewel/el7/noarch/ceph-release-1-0.el7.noarch.rpm

# 安装 epel 源
rpm -Uvh http://mirrors.ustc.edu.cn/centos/7/extras/x86_64/Packages/epel-release-7-9.noarch.rpm


[root@ceph-node-1 ~]# yum makecache

[root@ceph-node-1 ~]# yum -y install ceph-deploy ntpdate

创建 Ceph-Mon

# 创建集群目录,用于存放配置文件,证书等信息

mkdir -p /opt/ceph-cluster

cd /opt/ceph-cluster/

# 创建ceph-mon 节点
[root@ceph-node-1 ceph-cluster]# ceph-deploy new ceph-node-1 ceph-node-2 ceph-node-3


Monitor initial members are ['ceph-node-1', 'ceph-node-2', 'ceph-node-3']


# 查看配置文件

[root@ceph-node-1 ceph-cluster]# cat ceph.conf 
[global]
fsid = 211a5d26-0377-4d1c-8555-c4793cef83c1
mon_initial_members = ceph-node-1, ceph-node-2, ceph-node-3
mon_host = 172.16.1.37,172.16.1.38,172.16.1.39
auth_cluster_required = cephx
auth_service_required = cephx
auth_client_required = cephx


# 修改 osd 的副本数,既数据保存N份。

echo 'osd_pool_default_size = 2' >> ./ceph.conf


# 注: 如果文件系统为 ext4 请添加

echo 'osd max object name len = 256' >> ./ceph.conf
echo 'osd max object namespace len = 64' >> ./ceph.conf

安装 Ceph

# 可通过 ceph-deploy 安装,也可以登陆node 本地安装
# 命令: ceph-deploy install {ceph-node}[{ceph-node} ...]

[root@ceph-node-1 ceph-cluster]# ceph-deploy install ceph-node-1 ceph-node-2 ceph-node-3 ceph-node-4

# 使用 cpeh-deploy 安装,会一直使用官方源下载,超级慢
# 如果出现超时,请自行在每个服务器中使用 yum 安装

# 替换 ceph 源 为 163 源
sed -i 's/download\.ceph\.com/mirrors\.163\.com\/ceph/g' /etc/yum.repos.d/ceph.repo


yum -y install ceph ceph-radosgw


# 检测 安装

[root@ceph-node-1 ceph-cluster]# ceph --version
ceph version 10.2.7 (50e863e0f4bc8f4b9e31156de690d765af245185)

初始化 ceph-mon 节点

# 请务必在 ceph-cluster 目录下

[root@ceph-node-1 ceph-cluster]# ceph-deploy mon create-initial



[ceph_deploy.gatherkeys][INFO  ] Storing ceph.client.admin.keyring
[ceph_deploy.gatherkeys][INFO  ] Storing ceph.bootstrap-mds.keyring
[ceph_deploy.gatherkeys][INFO  ] keyring 'ceph.mon.keyring' already exists
[ceph_deploy.gatherkeys][INFO  ] Storing ceph.bootstrap-osd.keyring
[ceph_deploy.gatherkeys][INFO  ] Storing ceph.bootstrap-rgw.keyring
[ceph_deploy.gatherkeys][INFO  ] Destroy temp directory /tmp/tmpNfXVDA

初始化 ceph.osd 节点

# 首先创建 存储空间, 如果使用分区,可略过

[root@ceph-node-2 ~]# mkdir -p /opt/ceph-osd-1 && chown ceph:ceph /opt/ceph-osd-1
[root@ceph-node-3 ~]# mkdir -p /opt/ceph-osd-2 && chown ceph:ceph /opt/ceph-osd-2
[root@ceph-node-4 ~]# mkdir -p /opt/ceph-osd-3 && chown ceph:ceph /opt/ceph-osd-3




# 启动 osd

[root@ceph-node-1 ceph-cluster]# ceph-deploy osd prepare ceph-node-2:/opt/ceph-osd-1 ceph-node-3:/opt/ceph-osd-2 ceph-node-4:/opt/ceph-osd-3
# 激活 所有 osd 节点

[root@ceph-node-1 ceph-cluster]# ceph-deploy osd activate ceph-node-2:/opt/ceph-osd-1 ceph-node-3:/opt/ceph-osd-2 ceph-node-4:/opt/ceph-osd-3
# 把管理节点的配置文件与keyring同步至其它节点
[root@ceph-node-1 ceph-cluster]# ceph-deploy admin ceph-node-1 ceph-node-2 ceph-node-3 ceph-node-4
# 没有出现 红色的 ERROR 
# 查看状态

[root@ceph-node-1 ceph-cluster]# ceph -s
    cluster 7ab7e076-24e8-4236-bd4e-88675aab7365
     health HEALTH_OK
     monmap e1: 3 mons at {ceph-node-1=172.16.1.37:6789/0,ceph-node-2=172.16.1.38:6789/0,ceph-node-3=172.16.1.39:6789/0}
            election epoch 6, quorum 0,1,2 ceph-node-1,ceph-node-2,ceph-node-3
     osdmap e15: 3 osds: 3 up, 3 in
            flags sortbitwise,require_jewel_osds
      pgmap v24: 64 pgs, 1 pools, 0 bytes data, 0 objects
            15628 MB used, 8957 GB / 9452 GB avail
                  64 active+clean
# 查看 osd tree

[root@ceph-node-1 ceph-cluster]# ceph osd tree
ID WEIGHT  TYPE NAME            UP/DOWN REWEIGHT PRIMARY-AFFINITY 
-1 9.23126 root default                                           
-2 3.07709     host ceph-node-2                                   
 0 3.07709         osd.0             up  1.00000          1.00000 
-3 3.07709     host ceph-node-3                                   
 1 3.07709         osd.1             up  1.00000          1.00000 
-4 3.07709     host ceph-node-4                                   
 2 3.07709         osd.2             up  1.00000          1.00000 
# 设置所有开机启动

systemctl enable ceph-osd.target
systemctl enable ceph-mon.target
# 重启系统以后重启 osd

#查看处于down 的 osd
ceph osd tree

# 登陆所在node 启动ceph-osd进程 [id 为 tree 查看的 id]

systemctl start ceph-osd@id

Kubernetes Volume Ceph RBD

官方 RDB 的文件 https://github.com/kubernetes/kubernetes/tree/master/examples/volumes/rbd

k8s 安装 ceph-common

# 1. 在所有的 k8s node 里面安装 ceph-common
yum -y install ceph-common

# 2. 拷贝 ceph.conf 与 ceph.client.admin.keyring
拷贝到 /etc/ceph/ 目录下

# 3. 配置 kubelet 增加ceph参数
# 这里最好是在创建 k8s 集群的时候就添加好

vim /usr/local/bin/kubelet

# 增加 如下

  -v /etc/ceph:/etc/ceph:ro \
  -v /sbin/modprobe:/sbin/modprobe:ro \
  -v /usr/sbin/modprobe:/usr/sbin/modprobe:ro \
  -v /lib/modules:/lib/modules:ro \

# 重启 kubelet

systemctl restart kubelet.service

# 否则创建 pod 的时候 报错
with: rbd: failed to modprobe rbd error:exit status 1

修改 ceph 配置

# 修改配置
# rbd image有4个 features,layering, exclusive-lock, object-map, fast-diff, deep-flatten
因为目前内核仅支持layering,修改默认配置。

[root@ceph-node-1 ceph-cluster]# echo 'rbd_default_features = 1' >> ./ceph.conf

# 验证一下
[root@ceph-node-1 ceph-cluster]# ceph --show-config|grep rbd|grep features
rbd_default_features = 1

# 把管理节点的配置文件与keyring同步至其它节点
[root@ceph-node-1 ceph-cluster]# ceph-deploy --overwrite-conf admin ceph-node-1 ceph-node-2 ceph-node-3 ceph-node-4

创建 ceph-secret

# 获取 client.admin 的值
[root@ceph-node-1 ceph-cluster]# ceph auth get-key client.admin
AQBpUAxZGmDBBxAAVbgeRss9jv39dE0biTE7qQ==

# 转换成 base64 编码
[root@ceph-node-1 ceph-cluster]# echo "AQBpUAxZGmDBBxAAVbgeRss9jv39dE0biTE7qQ=="|base64
QVFCcFVBeFpHbURCQnhBQVZiZ2VSc3M5anYzOWRFMGJpVEU3cVE9PQo=

# 创建ceph-secret.yaml文件

apiVersion: v1
kind: Secret
metadata:
  name: ceph-secret
data:
  key: QVFCcFVBeFpHbURCQnhBQVZiZ2VSc3M5anYzOWRFMGJpVEU3cVE9PQo=


# 导入 yaml 文件
[root@k8s-node-28 cephrbd]# kubectl apply -f ceph-secret.yaml
secret "ceph-secret" created

# 查看 状态
[root@k8s-node-28 cephrbd]# kubectl get secret |grep ceph
ceph-secret           Opaque                                1         53s

创建 ceph image

# 创建一个 1G 的 image
[root@ceph-node-1 ceph-cluster]# rbd create test-image -s 1G

# 查看 image
[root@ceph-node-1 ceph-cluster]# rbd list
test-image

[root@ceph-node-1 ceph-cluster]# rbd info test-image
rbd image 'test-image':
        size 1024 MB in 256 objects
        order 22 (4096 kB objects)
        block_name_prefix: rbd_data.373b2ae8944a
        format: 2
        features: layering
        flags:

# 这里 format 为 2 , 如果旧系统 不支持 format 2 ,可将 format 设置为 1 。

创建一个 pv

# 创建 test-pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: test-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  rbd:
    monitors:
      - 172.16.1.37:6789
      - 172.16.1.38:6789
      - 172.16.1.38:6789
    pool: rbd
    image: test-image
    user: admin
    secretRef:
      name: ceph-secret
    fsType: ext4
    readOnly: false
  persistentVolumeReclaimPolicy: Recycle



# 导入 yaml 文件

[root@k8s-node-28 cephrbd]# kubectl apply -f test-pv.yaml 
persistentvolume "test-pv" created

# 查看 pv
[root@k8s-node-28 cephrbd]# kubectl get pv |grep test-pv
test-pv   1Gi        RWO           Recycle         Available                                      33s

创建一个 pvc

# vi test-pvc.yaml

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi


# 导入 yaml 文件

[root@k8s-node-28 cephrbd]# kubectl apply -f test-pvc.yaml 
persistentvolumeclaim "test-claim" created


# 查看 pvc

[root@k8s-node-28 cephrbd]# kubectl get pvc |grep test
test-claim   Bound     test-pv   1Gi        RWO                          31s

创建一个 deployment

vi nginx-deplyment.yaml


apiVersion: extensions/v1beta1 
kind: Deployment 
metadata: 
  name: nginx-dm
spec: 
  replicas: 1
  template: 
    metadata: 
      labels: 
        name: nginx 
    spec: 
      containers: 
        - name: nginx 
          image: nginx:alpine 
          imagePullPolicy: IfNotPresent
          ports: 
            - containerPort: 80
          volumeMounts:
            - name: ceph-rbd-volume
              mountPath: "/usr/share/nginx/html"
      volumes:
      - name: ceph-rbd-volume
        persistentVolumeClaim:
          claimName: test-claim


# 导入 yaml 文件

[root@k8s-node-28 cephrbd]# kubectl apply -f nginx-deplyment.yaml 
deployment "nginx-dm" configured


# 查看 pods

[root@k8s-node-28 cephrbd]# kubectl get pods
NAME                        READY     STATUS    RESTARTS   AGE
nginx-dm-1697116629-j4m1g   1/1       Running   0          8m

测试

# 查看 分区文件

[root@k8s-node-28 cephrbd]# kubectl exec -it nginx-dm-1697116629-j4m1g -- df -h
Filesystem                Size      Used Available Use% Mounted on
overlay                 115.2G      4.9G    104.4G   4% /
tmpfs                    62.8G         0     62.8G   0% /dev
tmpfs                    62.8G         0     62.8G   0% /sys/fs/cgroup
/dev/mapper/centos-root
                        115.2G      4.9G    104.4G   4% /dev/termination-log
/dev/mapper/centos-root
                        115.2G      4.9G    104.4G   4% /etc/resolv.conf
/dev/mapper/centos-root
                        115.2G      4.9G    104.4G   4% /etc/hostname
/dev/mapper/centos-root
                        115.2G      4.9G    104.4G   4% /etc/hosts
shm                      64.0M         0     64.0M   0% /dev/shm
/dev/rbd0               975.9M      1.3M    907.4M   0% /usr/share/nginx/html
tmpfs                    62.8G     12.0K     62.8G   0% /var/run/secrets/kubernetes.io/serviceaccount
tmpfs                    62.8G         0     62.8G   0% /proc/kcore
tmpfs                    62.8G         0     62.8G   0% /proc/timer_list
tmpfs                    62.8G         0     62.8G   0% /proc/timer_stats
tmpfs                    62.8G         0     62.8G   0% /proc/sched_debug
tmpfs                    62.8G         0     62.8G   0% /sys/firmware


## 写入测试
[root@k8s-node-28 cephrbd]# kubectl exec -it nginx-dm-1697116629-j4m1g -- touch /usr/share/nginx/html/jicki.html

# 删除 pod
[root@k8s-node-28 cephrbd]# kubectl delete pod/nginx-dm-1697116629-j4m1g
pod "nginx-dm-1697116629-j4m1g" deleted

# 新的 pod
[root@k8s-node-28 cephrbd]# kubectl get pods
NAME                        READY     STATUS    RESTARTS   AGE
nginx-dm-1697116629-v2n52   1/1       Running   0          11s

# 查看文件
[root@k8s-node-28 cephrbd]# kubectl exec -it nginx-dm-1697116629-v2n52 -- ls -lt /usr/share/nginx/html
total 16
-rw-r--r--    1 root     root             0 May  9 07:53 jicki.html

FAQ and Error

FAQ 1

# ceph 挂载关于 namespace != default 的情况下


1. 需要配置 secret = namespace

kubectl get secret  可以看到只存在 default 的 认证


2. 需要配置 pv = namespace ,虽然pv 是全局的,但是最好还是配置一下

kubectl get pv --namespace=


3. 需要配置 pvc = namespace 。

kubectl get pvc --namespace=


# 确认以上3点,否则在挂载namespace 的时候会报错

ceph timeout expired waiting for volumes to attach/mount for pod

Error 1

# 删除 osd 如果创建出错,请删除 osd

# 使用 ceph osd tree 查看出错的 osd.id

ceph osd out id   提出集群

# 登陆所在 服务器 停止服务

systemctl stop ceph-osd@id

# 然后再执行  crush remove 删除 tree

ceph osd crush remove osd.id

# 最后 执行 auth del 和 rm 删除

ceph auth del osd.id 

ceph osd rm id

# 在运行 tree 已经不存在了
# 如果使用分区挂载 还需要 登陆 osd 节点中 umount 分区
# 使用 lsblk 查看挂载
# 如: /dev/sdb 被挂载

umount /dev/sdb
ceph-disk zap /dev/sdb

Error 2

# 如果暴力删除了 osd 然后重建了 osd

ceph -s

报错 stale+active+undersized+degraded+remapped

# 执行 ceph health detail 查看所有报错的信息

# 执行 ceph pg <pgid> query  查看具体信息
# 如果执行 query 报错
# 使用 ceph pg force_create_pg <pgid>  覆盖错误

# 如果 datail 有很多 pgid 出错 使用 for 循环去跑

for pg in `ceph health detail | grep "stale+active+undersized+degraded" | awk '{print $2}' | sort | uniq`; 
do 
  ceph pg force_create_pg $pg
done

# 如果仍然不能解决问题,那么请使用暴力方法
# 重建ceph 集群 删除集群所有文件,重新部署

systemctl stop ceph-osd.target
systemctl stop ceph-mon.target


rm -rf /etc/ceph/*
rm -rf /var/log/ceph/*
rm -rf /var/lib/ceph/*

# osd 清除挂载 目录的里的所有内容

# 卸载 ceph
yum -y remove ceph ceph-radosgw

# 重新安装 
yum -y install ceph ceph-radosgw

# 在 osd 节点 创建目录
mkdir -p /var/lib/ceph/osd/