Ceph Ansible

Ceph 介绍

无论是想要为云平台提供 Ceph Object Storage Ceph Block Device 服务,部署一个 Ceph Filesystem 总是从设置每一个 Ceph 节点 ,网络和 Ceph 存储集群开始。一个 Ceph 存储集群至少需要一个 Ceph Monitor,Ceph Manger,和 Ceph OSD(Object Storage Daemon)。当运行 Ceph 文件系统客户端时也需要 Ceph Metadata Server。

  • Monitors: 一个 Ceph 监视器(ceph-mon) 维护集群状态的映射,包括监视器,管理,OSD 和 CURSH 映射。这些映射是 Ceph 守护进程之间相互协调的关键。监视器还负责管理守护进程和客户端之间的身份验证。为了保证冗余和高可用,至少需要3个监视器。

  • Mangers: 一个 Ceph 管理(ceph-mgr) 守护进程负责保持追踪 Ceph 集群运行时指标和当前集群状态,包括存储利用率,当前的性能指标和系统负载。Ceph 管理进程还托管基于 python 的模块来管理和公开 Ceph 集群信息,包括一个基于网页的 Ceph Dashboard REST API 。为了保证高可用,至少需要2个管理节点。

  • Ceph OSDs: 一个 Ceph OSD(object storage daemon, ceph-osd) 存储数据,处理数据复制、恢复、重新平衡,并通过检查其他 Ceph OSD 进程的心跳来提供一些监控信息给 Ceph 监视器和管理。为了保证冗余和高可用,至少需要3个 Ceph OSDs。

  • MDSs: 一个 Ceph 元数据服务(MDS, ceph-mds) 存储代表 Ceph 文件系统 (例如 Ceph 快设备和 Ceph 对象存储就不使用 MDS)的元数据。Ceph 元数据服务允许 POSIX 文件系统用户执行基本的命令(像 ls, find 等)而不会给 Ceph 存储集群代理极大的负载。

Ceph 将数据存储为逻辑存储池中的对象。利用 CRUSH 算法,Ceph 计算哪个放置组应该存储该对象,并进一步计算哪个 Ceph 进程节点应该存储改放置组。CRUSH 算法能使 Ceph 存储集群能够动态扩展,重新平衡和恢复。

ceph-ansible

ceph 官方提供了 ansible 的安装脚本 ceph-ansible 。将项目克隆到本地,可以看到最新的稳定版本是stable-4.0。根据集群要求准备了6台服务器。部署 OSDs 的节点需要一块额外的磁盘用作存储。ansible 的 hosts 文件如下所示:

[all]
192.168.0.10    ansible_host=192.168.0.10    ansible_user=test    ansible_become=true
192.168.0.11    ansible_host=192.168.0.11    ansible_user=test    ansible_become=true
192.168.0.12    ansible_host=192.168.0.12    ansible_user=test    ansible_become=true
192.168.0.13    ansible_host=192.168.0.13    ansible_user=test    ansible_become=true
192.168.0.14    ansible_host=192.168.0.14    ansible_user=test    ansible_become=true
192.168.0.15    ansible_host=192.168.0.15    ansible_user=test    ansible_become=true

[mons]
192.168.0.10
192.168.0.11
192.168.0.12

[osds]
192.168.0.13
192.168.0.14
192.168.0.15

[mgrs]
192.168.0.10
192.168.0.11

这里将 192.168.0.10 作为用于执行 ansible-playbook 的节点。在这个节点上需要配置到另外5台服务器的 ssh 免密码登录(也可以在 hosts 文件中配置密码)。并安装一些依赖:

yum install -y ansible epel-release python2-pip
pip install -r requirements.txt

配置 site.yml 配置文件,将没用到的 hosts 注释:

- hosts:
  - mons
  - osds
  - mgrs

配置全局变量 group_vars/all.yml:

cluster: ceph

centos_package_dependencies:
  - epel-release
  - libselinux-python
ceph_origin: repository
ceph_repository: community
ceph_mirror: http://mirrors.163.com/ceph
ceph_stable_key: http://mirrors.163.com/ceph/keys/release.asc
ceph_stable_repo: "{{ ceph_mirror }}/rpm-{{ ceph_stable_release }}"
ceph_stable_release: nautilus
ceph_stable: true
fetch_directory: ~/ceph-ansible-keys
monitor_interface: eth0
public_network: 192.168.0.0/24
cluster_network: "{{ public_network }}"

配置 OSDs 变量,主要配置用哪个盘存储数据:

devices:
  - /dev/vdb

配置好可以运行 ansible-playbook -i hosts site.yml;。等待 ceph 安装完毕。安装完成后执行 ceph -s 可以看到如下输出:

  cluster:
    id:     b358e8f9-3ffa-438b-8b38-38f9f5468d12
    health: HEALTH_OK
 
  services:
    mon: 3 daemons, quorum VM_48_51_centos,VM_48_62_centos,VM_48_83_centos (age 2d)
    mgr: VM_48_51_centos(active, since 2d), standbys: VM_48_83_centos
    osd: 3 osds: 3 up (since 87m), 3 in (since 87m)
 
  data:
    pools:   0 pools, 0 pgs
    objects: 0 objects, 0 B
    usage:   3.0 GiB used, 294 GiB / 297 GiB avail
    pgs:     

kubernetes 配置 ceph

客户端节点配置

k8s 节点安装 ceph 客户端,注意版本要和服务端的一致。添加 ceph 的源,将以下内容写入到 /etc/yum.repo.d/ceph.repo:

[ceph]
name=Ceph noarch packages
baseurl=http://mirrors.163.com/ceph/rpm-nautilus/el7/x86_64/
enabled=1
gpgcheck=1
type=rpm-md
gpgkey=http://mirrors.163.com/ceph/keys/release.asc

再执行下列命令来安装:

yum clean all && yum makecache
yum install -y ceph-common

创建 RBD pool:

ceph osd pool create kube 128

授权 kube 用户:

ceph auth get-or-create client.kube mon 'allow r' osd 'allow class-read, allow rwx pool=kube' -o ceph.client.kube.keyring
ceph auth get client.kube

将生成的 keyring 文件放到 k8s 节点的 /etc/ceph/ 目录下

创建 storageclass

创建 ceph secret:

ceph auth get-key client.admin | base64
ceph auth get-key client.kube | base64
kubectl apply -f ceph-kube-secret.yml
ceph-kube-secret.yml
apiVersion: v1
kind: Namespace
metadata:
  name: ceph
---
apiVersion: v1
kind: Secret
metadata:
  name: ceph-admin-secret
  namespace: ceph
type: kubernetes.io/rbd
data:
  key: QVFEVGdBOWQ4bDA1TUJBQWhnamFJNHd6QzROVXJyR1J3RnlPWnc9PQ==
---
apiVersion: v1
kind: Secret
metadata:
  name: ceph-kube-secret
  namespace: ceph
type: kubernetes.io/rbd
data:
  key: QVFBVWJ4VmRYbHNwS3hBQUxJSDdQWmxlalk5WW10Rm5DRnQwU2c9PQ==

创建动态 RBD StorageClass:

kubectl apply -f ceph-kube-secret.yaml
ceph-storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ceph-rbd
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: kubernetes.io/rbd
parameters:
  monitors: 192.168.0.10:6789,192.168.0.11:6789,192.168.0.12:6789
  adminId: admin
  adminSecretName: ceph-admin-secret
  adminSecretNamespace: ceph
  pool: kube
  userId: kube
  userSecretName: ceph-kube-secret
  fsType: xfs
  imageFormat: "2"
  imageFeatures: "layering"

创建 pvc:

kubectl apply -f ceph-pvc.yaml -n ceph
ceph-pvc.yaml
kind: PersistentVolumeClaim
metadata:
  name: ceph-pvc
  namespace: ceph
spec:
  storageClassName: ceph-rbd
  accessModes:
     - ReadOnlyMany
  resources:
    requests:
      storage: 1Gi

查看 pvc 的状态发现一直是 pending,describe 查看 pvc 事件,发现报错:

rbd: create volume failed, err: executable file not found in $PATH

结合日志查阅资料发现是在 kube-controller-manager 的 pod 容器中没有 rbd 命令。具体可以查看 github issue

可以通过安装 external-storage 插件来解决。克隆下来后路径如下:

ceph
└── rbd
    └── deploy
        ├── non-rbac
        │   └── deployment.yaml
        ├── rbac
        │   ├── clusterrolebinding.yaml
        │   ├── clusterrole.yaml
        │   ├── deployment.yaml
        │   ├── rolebinding.yaml
        │   ├── role.yaml
        │   └── serviceaccount.yaml
        └── README.md

由于部署 k8s 集群的时候启用了 rbac,所以我们用 rbac 目录下的部署文件。将 clusterrolebinding.yamlrolebingding.yaml 的 namespace 修改为 ceph,然后部署:

kubectl apply -f rbac -n ceph

等到部署完成后,修改 storageClass 的配置,把 provisioner: kubernetes.io/rbd 更改为 provisioner: ceph.com/rbd,重新部署。等待创建完成,重新部署 pvc,发现已经可以绑定了。查看 pvc 发现也已经创建了。

到 ceph 的 monitor 节点上,执行如下命令:

rbd ls -p kube
rbd info kubernetes-dynamic-pvc-10321857-9952-11e9-aac5-0a580ae9419b -p kube

可以获取到 image 的详细信息,说明 ceph 确实被使用了。

创建一个 pod 进行测试,发现 pod 一直处于 container creating 的状态。

pod.yml
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: rbd-dyn-pvc-pod
  name: ceph-rbd-dyn-pv-pod2
spec:
  containers:
  - name: ceph-rbd-dyn-pv-busybox2
    image: busybox
    command: ["sleep", "60000"]
    volumeMounts:
    - name: ceph-dyn-rbd-vol1
      mountPath: /mnt/ceph-dyn-rbd-pvc/busybox
      readOnly: false
  volumes:
  - name: ceph-dyn-rbd-vol1
    persistentVolumeClaim:
      claimName: ceph-pvc

查看 pod 事件,发现如下报错:

MountVolume.WaitForAttach failed for volume "pvc-ec2aa2a2-b290-11e9-998e-5254003f0e66" : rbd: map failed exit status 110, rbd output: rbd: sysfs write failed
In some cases useful info is found in syslog - try "dmesg | tail".
rbd: map failed: (110) Connection timed out

在 pod 所在节点执行命令 dmesg | tail,发现如下报错:

[260542.633436] libceph: mon1 10.107.36.4:6789 feature set mismatch, my 106b84a842a42 < server's 40106b84a842a42, missing 400000000000000
[260542.638039] libceph: mon1 10.107.36.4:6789 missing required protocol features
[260552.602373] libceph: mon2 10.107.36.12:6789 feature set mismatch, my 106b84a842a42 < server's 40106b84a842a42, missing 400000000000000
[260552.606904] libceph: mon2 10.107.36.12:6789 missing required protocol features
[260562.618453] libceph: mon0 10.107.36.21:6789 feature set mismatch, my 106b84a842a42 < server's 40106b84a842a42, missing 400000000000000
[260562.623014] libceph: mon0 10.107.36.21:6789 missing required protocol features

查阅资料发现这个错误和内核的特性有关,可以升级内核至4.5以上。也可以通过设置 ceph 来解决,具体可以查看 https://k2r2bai.com/2018/02/11/ceph/luminous-crush-issue/

这里通过调整 ceph 配置来解决:

ceph osd crush tunables hammer

ceph 配置 dashboard

启用模块:

ceph mgr enable dashboard

创建证书:

ceph dashboard create-self-signed-cert

重启:

ceph mgr module disable dashboard
ceph mgr module enable dashboard

配置 ip,端口:

ceph config set mgr mgr/dashboard/server_addr $IP
ceph config set mgr mgr/dashboard/server_port $PORT

注意 ip 是 active monitor 节点的 ip

创建用户:

ceph dashboard ac-user-create <username> <password> administrator

Sun Jun 23, 2019 cheon