参考连接

本文内容参考:Ceph 官网

官网推荐的安装方式是使用cephadm

如果要将 Ceph 与 Kubernetes 集成,官网推荐使用Rook

一、普通安装方式(非 K8s 集群)

1. 前置要求

系统推荐: 官方目前推荐使用 Ubuntu 20.04

系统内软件需求:

  • Python3

  • Systemd

  • Podman or Docker (用于运行容器)

    安装 docker 请参考官网教程,若遇到网络问题,请参考官网的手动安装教程。

  • 时间同步(如 chrony)

  • lvm2(提供存储)

  • openssh

# 查看是否安装相应的软件
# python version
python3 --version
# systemd version
systemctl --version
# docker version, 安装教程请参考docker官网
docker version
# chrony version, 安装使用"sudo apt install chrony"命令
chronyc -v
sudo systemctl status chronyd.service # 查看chrony的service
# lvm2
dpkg -l | grep lvm2 # 查看是否安装lvm2
# 若没有安装则安装
sudo apt update && sudo apt install -y lvm2

# cephadm 基于发行版的安装方法
sudo apt install -y cephadm
# 检查是否安装成功
sudo which cephadm

2. ceph 初始化

Ceph 集群由monitor节点管理,monitor节点可以有多个,官方推荐大多数情况下 5 个节点是比较合适的,超过 7 个的monitor节点没有额外好处。

参考链接:Running the bootstrap command

cephadm bootstrap --mon-ip *<mon-ip>* # mon-ip 就是monitor的ip

上述命令做了下列事情:

  1. 在本地主机上为新集群创建monitorManager daemon
  2. 为集群生成新的 ssh key 并将其添加到 root 用户的/root/.ssh/authorized_keys中。(ceph 的运行和管理要求使用无须密码的 root 权限,所以直接用 root 最方便,可以使用–ssh-user 指定为非 root 用户)
  3. 将集群的 ssh key 的公钥写入/etc/ceph/ceph.pub
  4. client.admin管理员密钥的副本写入/etc/ceph/ceph.client.admin.keyring
  5. _admin标签添加到运行命令的主机。默认情况下,具有此标签的主机都将获得/etc/ceph/ceph.conf以及/etc/ceph/ceph.client.admin.keyring的副本。

此步完成以后,根据命令行的提示可以在网页访问<mon_ip>:8443,输入命令行显示的用户名和密码即可登录查看。

尝试使用 ceph cli:

# 进入ceph daemon 容器
sudo cephadm shell
# 查看服务以及状态
ceph orch ls
ceph orch status

补充,若想直接使用 ceph 命令而不进入容器,则执行下列命令:

cephadm add-repo --release reef
cephadm install ceph-common
# 验证是否安装好
stat /sbin/mount.ceph

3. 添加节点

添加的节点不一定需要安装cephadm,但需要满足前置要求

在满足要求后,在已经部署好的monitor节点上执行命令:

# 此命令实际上是将ceph.pub复制到了指定ip的用户目录的authorized_keys里
# 同Bootstrap中一样,user必须具有免密的root权限,而且必须具有ssh访问<usernam@ip>的权限
ssh-copy-id -f -i /etc/ceph/ceph.pub uername@ip

在设置好后,在monitor的 daemon 容器里执行:

# 添加指定主机,可以追加"--labels=_admin"等添加标签
ceph orch host add <hostname> <hostip>
# 给指定主机追加label
ceph orch host label add <host> <label>

有一些特殊的标签:

  • _no_schedule:不在该节点上调度或部署守护进程
  • _no_conf_keyring:不要在此节点上部署配置文件或密钥环
  • _no_autotune_memory:不要自动调整该节点上守护进程占用的内存
  • _admin:将 client.admin 和 ceph.conf 分发到该节点(如果需要在某节点上访问 ceph cli,则需要把这个标签加上)

4. 删除节点

可以通过下列操作删除加入的节点:

# 移除指定主机上的OSD
ceph orch host drain <host>
# 从集群中删除主机,如果host上有正在使用的osd,则删除会失败
ceph orch host rm <host> --rm-crush-entry

5. 添加存储

集群节点上需要有未使用的块设备,如在 pve 下新添加的设备,设备的最小容量是 5G。

# 让ceph自动使用任何可用和未使用的设备
ceph orch apply osd --all-available-devices
# 将指定设备作为OSD
ceph orch daemon add osd <host>:<device-path>

有了 OSD 后,需要在 OSD 上提供 cephfs:

ceph fs volume create <fs_name> --placement="<placement spec>"
# 一个例子,将名字为foo的fs放置在具有mds标签的host上
ceph fs volume create foo --placement="label:mds"

也可以通过ceph orch apply -i <mds>.yaml部署:

service_type: mds
service_id: fs_name
placement:
  count: 3
  label: mds

6. 在客户机使用 ceph

此部分参考:Mount Cephfs: Prerequisites

首先,在要使用 ceph 的客户机上运行以下命令:

mkdir -p -m /etc/ceph
# 下面这个命令实际是在monitor上生成了集群的最小配置信息,
# 并将其复制进了指定路径,可以手动操作这步
ssh <user>@<mon-host> "sudo ceph config generate-minimal-conf" | sudo tee /etc/ceph/ceph.conf
# 调整权限
chmod 644 /etc/ceph/ceph.conf
# 创建一个用户用于访问指定的cephfs,并且将keyring复制到客户机,可以手动执行
ssh <user>@<mon-host> "sudo ceph fs authorize <cephfs_name> client.<ceph_user> / rw" | sudo tee /etc/ceph/ceph.client.<ceph_user>.keyring
# 更改权限
chmod 600 /etc/ceph/ceph.client.foo.keyring

客户机使用 ceph 需要安装 cephadm。在安装好 cephadm 后,使用下列命令安装需要的工具:

cephadm add-repo --release reef
cephadm install ceph-common
# 验证是否安装好
stat /sbin/mount.ceph

安装好后使用下列命令,mount 指定的 cephfs,即可使用:

# mount -t ceph 192.168.20.81:6789:/ /mnt/cephs -o name=test,fs=foo
# 由于已经配置好/etc/ceph/ceph.conf以及keyring了,因此secret和mon_addr等选项可以不用设置
mount -t ceph :/ /mnt/cephs -o name=test,fs=foo

7. 其他命令

  1. 将主机置于维护模式或退出维护模式(停止主机上的所有 Ceph 守护进程)
# --force会忽略warnning,但无法忽略alerts
# --yes-i-really-mean-it会跳过所有安全检查,并且强制使主机进入维护模式(可能导致数据丢失)
ceph orch host maintenance enter <hostname> [--force] [--yes-i-really-mean-it]
ceph orch host maintenance exit <hostname>
  1. 某些极其可能不会向内核注册设备的移除或插入事件,此时可以在这些设备上运行rescan
ceph orch host rescan <hostname> [--with-summary]
  1. 可以使用 ceph orch apply -i <file.yaml> 通过yaml文件一次性添加多个 host:

详细配置参考:Ceph Service Specification

# yaml 文件示例
service_type: host
hostname: node-00
addr: 192.168.0.10
labels:
  - example1
  - example2
---
service_type: host
hostname: node-01
addr: 192.168.0.11
labels:
  - grafana
---
service_type: host
hostname: node-02
addr: 192.168.0.12

二、集成到 K8s 集群中(使用 Rook)

参考资料:Rook 官网

1. 前置要求

请参考官网的前置要求

  • 现有的 k8s 集群, k8s 版本要求为 v1.26-v1.31 (截止 2024-08-29)

  • 使用 helm 安装,因此需要在 master 上安装 helm

  • 节点 CPU 架构只支持:amd64/x86_64 和 arm64

  • ceph 需要节点上具有以下类型的本地存储设备来提供存储:

    • Raw devices (原始设备)
    • Raw partitions (原始分区)
    • LVM Logical Volumes (no formatted filesystem) (无格式化的 LVM 逻辑卷)
    • Persistent Volumes available from a storage class in block mode (block 模式下 storage class 里可用的持久卷)
  • 某些情况下 ceph 会使用到lvm工具,可以使用sudo apt install lvm2安装(具体参考官网的说明,安装命令因发行版而异)

2. 在 k8s 集群部署 Rook

Rook 官网提供了使用 helm 的安装方式:

# 可以克隆下它的仓库,要使用到部分示例yaml文件
git clone --single-branch --branch v1.15.0 https://github.com/rook/rook.git
# value.yaml 在 deploy/charts 路径下
helm repo add rook-release https://charts.rook.io/release
helm install --create-namespace --namespace rook-ceph rook-ceph rook-release/rook-ceph -f values.yaml

# 删除方式
# 查看
helm ls --namespace rook-ceph
# 删除
helm delete --namespace rook-ceph rook-ceph

3. 创建 ceph 集群

使用 helm 部署好 rook-operator 后,需要手动创建一个 ceph 集群。其实是通过kubectl create -f传入一个 yaml,rook-operator会自动将 k8s 集群节点加入到 ceph 集群。

# 默认的cluster.yaml在rook git仓库的 deploy/examples 路径下
kubectl create -f cluster.yaml
# 使用下列命令查看集群内的pod情况
 kubectl -n rook-ceph get pod

4. 使用 rook-toolbox 调试集群

rook-toolbox 是一个工具箱 pod,在里面可以使用 ceph 命令查看集群信息,进行调试:

# 示例yaml在 deploy/examples/toolbox.yaml 可直接使用
kubectl create -f deploy/examples/toolbox.yaml
# 可以使用下列命令进入pod,进行测试
kubectl -n rook-ceph exec -it <podname> -- bash
# 常用命令:
# ceph status
# ceph osd status
# ceph df
# ceph fs volume info <fsname>
# ceph fs volume ls

5. 创建 cephfs

可以使用下列 yaml 创建一个 cephfs,用于提供存储:

# filesystem.yaml
apiVersion: ceph.rook.io/v1
kind: CephFilesystem
metadata:
  name: myfs # 此处的name是自定义的
  namespace: rook-ceph
spec:
  metadataPool:
    replicated:
      size: 3
  dataPools:
    - name: replicated
      replicated:
        size: 3
  preserveFilesystemOnDelete: true
  metadataServer:
    activeCount: 1

使用上面的 filesystem.yaml 创建一个文件系统

kubectl create -f filesystem.yaml
# 查看创建的文件系统
kubectl -n rook-ceph get CephFilesystem
# 在rook-toolbox内查看
ceph fs ls
ceph fs volume ls
ceph fs volume info myfs # myfs 是上面yaml中设置的名称

6. 制备静态 pv

此部分参考官网 首先需要创建一个StorageClass,这是 k8s 与 CSI 驱动互操作所需的:

# deploy/examples/csi/cephfs/storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: rook-cephfs
# Change "rook-ceph" provisioner prefix to match the operator namespace if needed
provisioner: rook-ceph.cephfs.csi.ceph.com
parameters:
  # clusterID is the namespace where the rook cluster is running
  # If you change this namespace, also change the namespace below where the secret namespaces are defined
  clusterID: rook-ceph

  # CephFS filesystem name into which the volume shall be created
  fsName: myfs # myfs是上面创建的filesystem的名字

  # Ceph pool into which the volume shall be created
  # Required for provisionVolume: "true"
  pool: myfs-replicated

  # The secrets contain Ceph admin credentials. These are generated automatically by the operator
  # in the same namespace as the cluster.
  csi.storage.k8s.io/provisioner-secret-name: rook-csi-cephfs-provisioner
  csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
  csi.storage.k8s.io/controller-expand-secret-name: rook-csi-cephfs-provisioner
  csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
  csi.storage.k8s.io/node-stage-secret-name: rook-csi-cephfs-node
  csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph

reclaimPolicy: Delete

动态制备的官网例子

由于项目中主要使用静态制备 pv 的方式来共享数据,且制备方式较为复杂,因此重点介绍:

  1. 复制rook-csi-cephfs-nod

    • 使用kubectl -n rook-ceph get secret可以看到有一个名为rook-csi-cephfs-nod的 secret。
    • 使用kubectl -n rook-ceph get secret -o yaml > <filename>命令将其输出为 yaml 文件。
    • 将其中的adminIDadminKey分别改为userIDuserKey,secret 的名称改为rook-csi-cephfs-nod-user
    • 添加此 secretkubectl apply -f <filename>
  2. 先使用下面的 yaml 文件创建一个 PVC:

# pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: my-pvc # 名字自行更改
  namespace: first-namespace # 如果都是默认的话,此处应该为rook-ceph
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 100Gi # 容量按需调整
  storageClassName: rook-cephfs
  volumeMode: Filesystem

使用kubectl get pvc -n rook-ceph命令可以查看到新创建的 pvc。系统会动态制备一个 pv 给这个 pvc 使用,可以使用kubectl get pv查看到。

使用kubectl get pv <pvname> -o yaml > <filename>获取到 pv 的配置信息(例子来源于官网):

# pv.yaml
kind: PersistentVolume
apiVersion: v1
metadata:
  name: pvc-a02dd277-cb26-4c1e-9434-478ebc321e22
  annotations:
    pv.kubernetes.io/provisioned-by: rook.cephfs.csi.ceph.com
  finalizers:
    - kubernetes.io/pv-protection
spec:
  capacity:
    storage: 100Gi
  csi:
    driver: rook.cephfs.csi.ceph.com
    volumeHandle: >-
      0001-0011-rook-0000000000000001-8a528de0-e274-11ec-b069-0a580a800213      
    volumeAttributes:
      clusterID: rook
      fsName: rook-cephfilesystem
      storage.kubernetes.io/csiProvisionerIdentity: 1654174264855-8081-rook.cephfs.csi.ceph.com
      subvolumeName: csi-vol-8a528de0-e274-11ec-b069-0a580a800213
      subvolumePath: >-
        /volumes/csi/csi-vol-8a528de0-e274-11ec-b069-0a580a800213/da98fb83-fff3-485a-a0a9-57c227cb67ec        
    nodeStageSecretRef:
      name: rook-csi-cephfs-node
      namespace: rook
    controllerExpandSecretRef:
      name: rook-csi-cephfs-provisioner
      namespace: rook
  accessModes:
    - ReadWriteMany
  claimRef:
    kind: PersistentVolumeClaim
    namespace: first-namespace
    name: base-pvc
    apiVersion: v1
    resourceVersion: "49728"
  persistentVolumeReclaimPolicy: Retain
  storageClassName: rook-cephfs
  volumeMode: Filesystem
  1. 将其按下面的例子修改,注意删除原来导出的 yaml 中不必要的配置:
kind: PersistentVolume
apiVersion: v1
metadata:
  # name 为原pv name+<你要用的新namespace>,其实没有规定,此处为官网建议,示例的新namespace为“newnamespace”
  name: pvc-a02dd277-cb26-4c1e-9434-478ebc321e22-newnamespace
spec:
  capacity:
    # 容量和原pv保持一致
    storage: 100Gi
  csi:
    driver: rook.cephfs.csi.ceph.com
    # 原volumeHanle后+<你要用的新namespace>
    volumeHandle: 0001-0011-rook-0000000000000001-8a528de0-e274-11ec-b069-0a580a800213-newnamespace
    volumeAttributes:
      clusterID: rook
      fsName: rook-cephfilesystem
      storage.kubernetes.io/csiProvisionerIdentity: 1654174264855-8081-rook.cephfs.csi.ceph.com
      subvolumeName: csi-vol-8a528de0-e274-11ec-b069-0a580a800213
      subvolumePath: /volumes/csi/csi-vol-8a528de0-e274-11ec-b069-0a580a800213/da98fb83-fff3-485a-a0a9-57c227cb67ec
      # 添加 rootPath,值和subvolumePath一样
      rootPath: /volumes/csi/csi-vol-8a528de0-e274-11ec-b069-0a580a800213/da98fb83-fff3-485a-a0a9-57c227cb67ec
      # 添加staticVolume
      staticVolume: "true"
    nodeStageSecretRef:
      name: rook-csi-cephfs-node
      namespace: rook
  accessModes:
    - ReadWriteMany
  # persistentVolumeReclaimPolicy改为Retain
  persistentVolumeReclaimPolicy: Retain
  storageClassName: rook-cephfs
  volumeMode: Filesystem
  1. 有了新的 pv,就可以在其他命名空间中创建一个新的 pvc,让这个 pvc 使用我们制备的 pv:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: second-pvc # 新pvc的名字
  namespace: newnamespace # 新pvc所在的命名空间
  finalizers:
    - kubernetes.io/pvc-protection
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 100Gi # 注意容量应小于等于制备的pv
  volumeName: pvc-a02dd277-cb26-4c1e-9434-478ebc321e22-newnamespace # 我们制备的新pv的名字
  storageClassName: rook-cephfs
  volumeMode: Filesystem
  1. 使用新的 pv,尝试使用[busybox-pod]测试新的 pvc:
# busybox.yaml
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  namespace: default # 新pvc所在的命名空间
spec:
  containers:
    - image: busybox
      command:
        - sleep
        - "3600"
      imagePullPolicy: IfNotPresent
      name: busybox
      volumeMounts:
        - name: test-volume
          mountPath: /test # 把volume挂载的路径
  volumes:
    - name: test-volume # volume的名字
      persistentVolumeClaim:
        claimName: second-pvc # 我们制备的pvc的名字
        readOnly: false
  restartPolicy: Always

随后使用kubectl apply -f <filename>启动这个 pod,使用kubectl -n <newnamespace> exec -it <podname> -- sh 进入这个 pod。

可以使用dd if=/dev/zero of=./testfile bs=1M count=1024快速生成一个 1G 大小的文件。然后在 rook-toolbox 里使用ceph fs volume info myfsceph status查看存储使用的情况。