Kubernetes/Ceph 技术堆栈

要使用 Ceph 块设备,您必须在 Kubernetes 环境中安装和配置Ceph-CSI。 下图描绘了Kubernetes/Ceph 技术堆栈。

image.png

创建 pool

默认情况下,Ceph块设备使用RBD池。 为Kubernetes卷存储创建一个池。 确保您的Ceph集群正在运行,然后创建池。

ceph osd pool create kubernetes

有关指定池的放置组数以及放置组的详细信息,请参阅创建池,了解您应该为池所设置的放置组数量的详细信息。

必须在使用前初始化新创建的池。 使用RBD工具初始化池:

rbd pool init kubernetes

配置 CEPH-CLI

创建用户

为Kubernetes和Ceph-CSI创建一个新用户。 执行以下内容并记录生成的密钥:

$ ceph auth get-or-create client.kubernetes mon 'profile rbd' osd 'profile rbd pool=kubernetes' mgr 'profile rbd pool=kubernetes'
[client.kubernetes]
    key = AQD9o0Fd6hQRChAAt7fMaSZXduT3NWEqylNpmg==

创建集群ID和集群地址

Ceph-CSI要求存储在Kubernetes中的ConfigMap对象来定义Ceph集群的Ceph监视器地址。 收集Ceph集群唯一的FSID和监视器地址:

$ ceph mon dump
<...>
fsid b9127830-b0cc-4e34-aa47-9d1a2e9949a8
<...>
0: [v2:192.168.1.1:3300/0,v1:192.168.1.1:6789/0] mon.a
1: [v2:192.168.1.2:3300/0,v1:192.168.1.2:6789/0] mon.b
2: [v2:192.168.1.3:3300/0,v1:192.168.1.3:6789/0] mon.c

生成类似于下面示例的CSI-Config-Map.yaml文件,替换FSID,以及集群地址

$ cat <<EOF > csi-config-map.yaml
---
apiVersion: v1
kind: ConfigMap
data:
  config.json: |-
    [
      {
        "clusterID": "b9127830-b0cc-4e34-aa47-9d1a2e9949a8",
        "monitors": [
          "192.168.1.1:6789",
          "192.168.1.2:6789",
          "192.168.1.3:6789"
        ]
      }
    ]
metadata:
  name: ceph-csi-config
EOF

执行

kubectl apply -f csi-config-map.yaml

最新版本的Ceph-CSI还需要一个额外的ConfigMap对象来定义密钥管理服务(KMS)提供程序详细信息。 如果未设置KMS,请在CSI-kms-config-map.yaml文件中放置一个空配置,也会在https://github.com/ceph/ceph-csi/tree/master/examples/kms中引用示例

$ cat <<EOF > csi-kms-config-map.yaml
---
apiVersion: v1
kind: ConfigMap
data:
  config.json: |-
    {}
metadata:
  name: ceph-csi-encryption-kms-config
EOF

运行

$ kubectl apply -f csi-kms-config-map.yaml

创建凭证

Ceph-CSI要求Cephx凭证与Ceph集群进行通信。 生成类似于下面的示例的CSI-RBD-Secret.yaml文件,使用新创建的Kubernetes用户ID和Cephx密钥:

$ cat <<EOF > csi-rbd-secret.yaml
---
apiVersion: v1
kind: Secret
metadata:
  name: csi-rbd-secret
  namespace: default
stringData:
  userID: kubernetes
  userKey: AQD9o0Fd6hQRChAAt7fMaSZXduT3NWEqylNpmg==
EOF

执行

$ kubectl apply -f csi-rbd-secret.yaml

配置 CEPH-CSI 插件

创建所需的 ServiceAccount、RBAC ClusterRole、ClusterRoleBinding Kubernetes对象。

$ kubectl apply -f https://raw.githubusercontent.com/ceph/ceph-csi/master/deploy/rbd/kubernetes/csi-provisioner-rbac.yaml
$ kubectl apply -f https://raw.githubusercontent.com/ceph/ceph-csi/master/deploy/rbd/kubernetes/csi-nodeplugin-rbac.yaml

最后,创建Ceph-CSI Provisioner和Node插件。

$ wget https://raw.githubusercontent.com/ceph/ceph-csi/master/deploy/rbd/kubernetes/csi-rbdplugin-provisioner.yaml
$ kubectl apply -f csi-rbdplugin-provisioner.yaml
$ wget https://raw.githubusercontent.com/ceph/ceph-csi/master/deploy/rbd/kubernetes/csi-rbdplugin.yaml
$ kubectl apply -f csi-rbdplugin.yaml

使用块设备

创建 STORAGECLASS

Kubernetes StorageClass 定义了一类存储。 可以创建多个StorageClass对象来映射到不同的服务质量级别(即NVME基于HDD的池)和功能。

例如,要创建一个Ceph-CSI StorageClass,可映射到上面创建的Kubernetes池,可以在确保“ClusterId”属性与您的Ceph群集的FSID匹配之后使用以下yaml文件:

$ cat <<EOF > csi-rbd-sc.yaml
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
   name: csi-rbd-sc
provisioner: rbd.csi.ceph.com
parameters:
   clusterID: b9127830-b0cc-4e34-aa47-9d1a2e9949a8
   pool: kubernetes
   imageFeatures: layering
   csi.storage.k8s.io/provisioner-secret-name: csi-rbd-secret
   csi.storage.k8s.io/provisioner-secret-namespace: default
   csi.storage.k8s.io/controller-expand-secret-name: csi-rbd-secret
   csi.storage.k8s.io/controller-expand-secret-namespace: default
   csi.storage.k8s.io/node-stage-secret-name: csi-rbd-secret
   csi.storage.k8s.io/node-stage-secret-namespace: default
reclaimPolicy: Delete
allowVolumeExpansion: true
mountOptions:
   - discard
EOF

$ kubectl apply -f csi-rbd-sc.yaml

创建

Filesystem for volumeMode

  • ReadWriteOnce
  • ReadOnlyMany

Block for volumeMode

  • ReadWriteOnce
  • ReadWriteMany
  • ReadOnlyMany

基于 block

创建 PVC

$ cat <<EOF > raw-block-pvc.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: raw-block-pvc
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Block
  resources:
    requests:
      storage: 1Gi
  storageClassName: csi-rbd-sc
EOF

$ kubectl apply -f raw-block-pvc.yaml

创建测试 pod

$ cat <<EOF > raw-block-pod.yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-with-raw-block-volume
spec:
  containers:
    - name: fc-container
      image: fedora:26
      command: ["/bin/sh", "-c"]
      args: ["tail -f /dev/null"]
      volumeDevices:
        - name: data
          devicePath: /dev/xvda
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: raw-block-pvc
EOF

$ kubectl apply -f raw-block-pod.yaml

基于 filesystem

创建 PVC

$ cat <<EOF > pvc.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: rbd-pvc
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 1Gi
  storageClassName: csi-rbd-sc
EOF

$ kubectl apply -f pvc.yaml

创建测试pod

$ cat <<EOF > pod.yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: csi-rbd-demo-pod
spec:
  containers:
    - name: web-server
      image: nginx
      volumeMounts:
        - name: mypvc
          mountPath: /var/lib/www/html
  volumes:
    - name: mypvc
      persistentVolumeClaim:
        claimName: rbd-pvc
        readOnly: false
EOF

$ kubectl apply -f pod.yaml

kubernetes 挂载 Ceph NFS

部署所需环境

部署 CephFS

要使用 NFS,需要先部署 CephFS

# 创建一个 pool 用于存储 cephfs 数据
ceph osd pool create cephfs_data

# 创建一个 pool 用于存储 cephfs 元数据
ceph osd pool create cephfs_metadata

# 创建 cephfs, 指定 cephfs_metadata 存储元数据, 指定 cephfs_data 存储实际数据
ceph fs new cephfs cephfs_metadata cephfs_data

# 查看 cephfs
ceph fs ls

部署 MDS

# 在 ceph01, ceph02, ceph03 部署 mds
ceph orch apply mds cephfs --placement="3 ceph01 ceph02 ceph03"

创建 NFS

ceph osd pool create ganesha_data
ceph osd pool application enable ganesha_data nfs
ceph orch apply nfs nfs ganesha_data --placement=3
# eph orch apply nfs nfs ganesha_data --placement="1 ceph1"

在 CephFS 中创建 nfs 文件夹作为 nfs 存储的根目录

# 挂载CephFS(需要安装ceph-commons):
mkdir -p /mnt/cephfs
mount -t ceph ceph1:/ /mnt/cephfs -o name=admin,secret=AQBYSjZfQF+UJBAAC6QJjNACndkw2LcCR2XLFA==

Ceph的NFS是基于CephFS提供的,我们首先在CephFS中创建一个/nfs目录,用于作为NFS服务的根目录。

# 前一步骤中已经挂载了CephFS到/mnt/cephfs
mkdir /mnt/cephfs/nfs

# 其中mount的时候的secret是/etc/ceph/ceph.client.admin.keyring的值,也可以替换成secretfile=/etc/ceph/ceph.client.admin.keyring。

在 dashboard 中创建 nfs 存储

最后,在dashboard中创建一个NFS即可

image.png

挂载 nfs

挂载NFS:

mount -t nfs 192.168.7.14:/nfs /mnt/nfs

storageclass

制作镜像

https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner/releases

下载 Source code

更改 Dockerfile

FROM alpine # 修改镜像,避免无法下载
LABEL maintainers="Kubernetes Authors"
LABEL description="NFS subdir external provisioner"
ARG binary=./bin/nfs-subdir-external-provisioner

COPY ${binary} /nfs-subdir-external-provisioner
ENTRYPOINT ["/nfs-subdir-external-provisioner"]

制作镜像,成成 nfs-subdir-external-provisioner:latest 镜像

make build
make container

更改镜像标签

docker tag nfs-subdir-external-provisioner:latest k8s.gcr.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2

部署

$ helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
$ helm install nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
    --set nfs.server=x.x.x.x \
    --set nfs.path=/exported/path

测试

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
spec:
  storageClassName: nfs-client
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Mi
---
kind: Pod
apiVersion: v1
metadata:
  name: test-pod
spec:
  containers:
  - name: test-pod
    image: busybox:stable
    command:
      - "/bin/sh"
    args:
      - "-c"
      - "touch /mnt/SUCCESS && exit 0 || exit 1"
    volumeMounts:
      - name: nfs-pvc
        mountPath: "/mnt"
  restartPolicy: "Never"
  volumes:
    - name: nfs-pvc
      persistentVolumeClaim:
        claimName: test-claim

kubectl appply -f