Ceph Ansible with kubernetes

什么是 Ceph

Ceph是一个统一的分布式存储系统,设计初衷是提供较好的性能、可靠性和可扩展性。Ceph项目最早起源于Sage就读博士期间的工作(最早的成果于2004年发表),并随后贡献给开源社区。在经过了数年的发展之后,目前已得到众多云计算厂商的支持并被广泛应用。RedHat及OpenStack都可与Ceph整合以支持虚拟机镜像的后端存储。

核心组件及概念介绍

  • Monitor
    一个Ceph集群需要多个Monitor组成的小集群,它们通过Paxos同步数据,用来保存OSD的元数据。
  • OSD
    OSD全称Object Storage Device,也就是负责响应客户端请求返回具体数据的进程。一个Ceph集群一般都有很多个OSD。
  • MDS
    MDS全称Ceph Metadata Server,是CephFS服务依赖的元数据服务。
  • Object
    Ceph最底层的存储单元是Object对象,每个Object包含元数据和原始数据。
  • PG
    PG全称Placement Grouops,是一个逻辑的概念,一个PG包含多个OSD。引入PG这一层其实是为了更好的分配数据和定位数据。
  • RADOS
    RADOS全称Reliable Autonomic Distributed Object Store,是Ceph集群的精华,用户实现数据分配、Failover等集群操作。
  • Libradio
    Librados是Rados提供库,因为RADOS是协议很难直接访问,因此上层的RBD、RGW和CephFS都是通过librados访问的,目前提供PHP、Ruby、Java、Python、C和C++支持。
  • CRUSH
    CRUSH是Ceph使用的数据分布算法,类似一致性哈希,让数据分配到预期的地方。
  • RBD
    RBD全称RADOS block device,是Ceph对外提供的块设备服务。
  • RGW
    RGW全称RADOS gateway,是Ceph对外提供的对象存储服务,接口与S3和Swift兼容。
  • CephFS
    CephFS全称Ceph File System,是Ceph对外提供的文件系统服务。

ceph-ansible

  • ceph 官方提供了 ansible 的安装脚本 ceph-ansible。将项目克隆到本地,可以看到最新的稳定版本是 stable-4.0,克隆代码后注意切换到改分支或者4.x的tag。根据集群要求准备了3台服务器。部署 OSDs 的节点需要一块额外的磁盘用作存储。ansible 的 hosts 文件如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    [all]
    192.168.56.121 ansible_user=vagrant ansible_ssh_pass=vagrant ansible_become=true
    192.168.56.122 ansible_user=vagrant ansible_ssh_pass=vagrant ansible_become=true
    192.168.56.123 ansible_user=vagrant ansible_ssh_pass=vagrant ansible_become=true

    [mons]
    192.168.56.121
    192.168.56.122
    192.168.56.123

    [osds]
    192.168.56.121
    192.168.56.122
    192.168.56.123

    [mgrs]
    192.168.56.121
    192.168.56.122
    192.168.56.123

    [mdss]
    192.168.56.121
    192.168.56.122
    192.168.56.123

    [grafana-server]
    192.168.56.121
  • 这里将 192.168.56.121 作为用于执行 ansible-playbook 的节点。在这个节点上需要配置到另外2台服务器的 ssh 免密码登录并安装一些依赖:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    for host in \
    192.168.56.121 \
    192.168.56.122 \
    192.168.56.123; \
    do \
    ssh-copy-id -i ~/.ssh/id_rsa.pub vagrant@$host; \
    done
    yum install -y ansible epel-release python2-pip
    pip install -r requirements.txt
  • 配置 site.yml 配置文件,将没用到的 hosts 注释:

    1
    2
    3
    4
    5
    6
    - hosts:
    - mons
    - osds
    - mgrs
    - mdss
    - grafana-server
  • 配置全局变量 group_vars/all.yml:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    cluster: ceph

    centos_package_dependencies:
    - epel-release
    - libselinux-python
    ceph_origin: repository
    ceph_repository: community
    ceph_mirror: http://mirrors.aliyun.com/ceph
    ceph_stable_key: http://mirrors.aliyun.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.56.1/24
    cluster_network: "{{ public_network }}"
  • 配置 OSDs 变量,主要配置用哪个盘存储数据:

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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:

    1
    2
    3
    4
    5
    6
    7
    [ceph]
    name=Ceph noarch packages
    baseurl=http://mirrors.aliyun.com/ceph/rpm-nautilus/el7/x86_64/
    enabled=1
    gpgcheck=1
    type=rpm-md
    gpgkey=http://mirrors.aliyun.com/ceph/keys/release.asc
  • 安装,注意版本要和服务端的一致。

    1
    2
    yum clean all && yum makecache
    yum install -y ceph-common
  • 创建 RBD pool:

    1
    ceph osd pool create kube 128
  • 授权 kube 用户:

    1
    2
    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:

    1
    2
    3
    ceph auth get-key client.admin | base64
    ceph auth get-key client.kube | base64
    kubectl apply -f ceph-kube-secret.yaml
    ceph-kube-secret.yaml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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:

    1
    kubectl apply -f ceph-storageclass.yaml
    ceph-storageclass.yaml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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 测试

    1
    kubectl apply -f ceph-pvc.yaml -n ceph
    ceph-pvc.yaml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    kind: PersistentVolumeClaim
    metadata:
    name: ceph-pvc
    namespace: ceph
    spec:
    storageClassName: ceph-rbd
    accessModes:
    - ReadOnlyMany
    resources:
    requests:
    storage: 1Gi

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

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

    结合日志查阅资料发现是在 kube-controller-manager 的 pod 容器中没有 rbd 命令。具体可以查看 github issue 可以通过安装 external-storage 插件来解决。克隆下来后路径如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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.yaml 和 rolebingding.yaml 的 namespace 修改为 ceph,然后部署:

    1
    kubectl apply -f rbac -n ceph

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

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

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

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

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

    pod.yaml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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 事件,发现如下报错:

    1
    2
    3
    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,发现如下报错:

    1
    2
    3
    4
    5
    6
    [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 配置来解决:

    1
    ceph osd crush tunables hammer

ceph 配置 dashboard

  • 启用模块:

    1
    ceph mgr enable dashboard
  • 创建证书:

    1
    ceph dashboard create-self-signed-cert
  • 重启:

    1
    2
    ceph mgr module disable dashboard
    ceph mgr module enable dashboard
  • 配置 ip,端口:

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

    注意 ip 是 active monitor 节点的 ip

  • 创建用户:

    1
    ceph dashboard ac-user-create <username> <password> administrator
setzero wechat