Armazenamento em Bloco RBD para Ambientes Cloud-Native com Ceph e Rook

Fundamentos do Armazenamento em Bloco RBD

O armazenamento em bloco é fundamentado em sequências de bytes de tamanho fixo, geralmente organizados em setores de 512 bytes. Interfaces baseadas em blocos são amplamente utilizadas em mídias tradicionais e modernas, como HDDs, SSDs e soluções de nuvem como EBS e CBS. No ecossistema Ceph, o RBD (RADOS Block Device) oferece uma solução robusta com características avançadas:

  • Provisionamento Dinâmico (Thin-provisioning): O espaço é alocado conforme a demanda real.
  • Escalabilidade Massiva: Suporte a imagens de até 16 exabytes.
  • Snapshots e Clones: Capacidade de criar pontos de restauração e clonagem via Copy-on-write.
  • Alta Disponibilidade: Replicação assíncrona multissite e recuperação de desastres.
  • Integração Nativa: Suporte direto via driver de kernel e compatibilidade total com KVM/libvirt.

Estratégias de Integração com Kubernetes

A conexão entre o Ceph e o Kubernetes pode ser realizada através de três abstrações principais:

  1. Volumes: Definição direta no manifesto do Pod, referenciando o driver específico.
  2. PV/PVC (Persistent Volume / Claim): Abstração que separa a requisição de armazenamento da sua implementação física.
  3. StorageClass: Automatiza o provisionamento. O administrador define as classes e o usuário solicita via PVC, permitindo o provisionamento dinâmico.

Provisionamento Dinâmico com Rook

O Rook atua como um operador cloud-native que simplifica a implantação e o gerenciamento do Ceph dentro do Kubernetes. Ele gerencia automaticamente drivers CSI (Contanier Storage Interface) para RBD e CephFS. Abaixo, definimos uma classe de armazenamento utilizando o driver CSI do Rook:

apiVersion: ceph.rook.io/v1
kind: CephBlockPool
metadata:
  name: pool-replicado-dados
  namespace: rook-ceph
spec:
  failureDomain: host
  replicated:
    size: 3
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
   name: ceph-rbd-sc
provisioner: rook-ceph.rbd.csi.ceph.com
parameters:
    clusterID: rook-ceph
    pool: pool-replicado-dados
    imageFormat: "2"
    imageFeatures: layering
    csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner
    csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
    csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node
    csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
    csi.storage.k8s.io/fstype: xfs
allowVolumeExpansion: true
reclaimPolicy: Delete

Após a aplicação deste manifesto, é possível verificar a criação do pool e da classe de armazenamento:

# Verificação do Pool no Ceph
ceph osd lspools
# Resultado esperado: 1 device_health_metrics, 2 pool-replicado-dados

# Verificação da StorageClass no Kubernetes
kubectl get sc ceph-rbd-sc

Implementação Prática: Aplicação WordPress e MySQL

Para demonstrar o uso do armazenamento RBD, utilizaremos uma arquitetura clássica de WordPress com banco de dados MySQL, onde ambos utilizam PVCs vinculados à nossa StorageClass.

Configuração do Banco de Dados (MySQL)

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-mysql-dados
spec:
  storageClassName: ceph-rbd-sc
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 15Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: db-mysql
spec:
  selector:
    matchLabels:
      app: blog-storage
      tier: db
  template:
    metadata:
      labels:
        app: blog-storage
        tier: db
    spec:
      containers:
      - image: mysql:5.7
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: senha_forte_123
        volumeMounts:
        - name: mysql-vol
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-vol
        persistentVolumeClaim:
          claimName: pvc-mysql-dados

Configuração da Camada de Aplicação (WordPress)

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-wp-html
spec:
  storageClassName: ceph-rbd-sc
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-wordpress
spec:
  selector:
    matchLabels:
      app: blog-storage
      tier: frontend
  template:
    metadata:
      labels:
        app: blog-storage
        tier: frontend
    spec:
      containers:
      - image: wordpress:latest
        name: wordpress
        env:
        - name: WORDPRESS_DB_HOST
          value: db-mysql-service
        - name: WORDPRESS_DB_PASSWORD
          value: senha_forte_123
        volumeMounts:
        - name: wp-vol
          mountPath: /var/www/html
      volumes:
      - name: wp-vol
        persistentVolumeClaim:
          claimName: pvc-wp-html

Fluxo de Provisionamento e Persistência

O ciclo de vida do provisionamento segue uma lógica automatizada pelo driver CSI:

  1. O usuário submete um PersistentVolumeClaim (PVC).
  2. A StorageClass identifica o provisioner (Rook-Ceph).
  3. O provisioner solicita ao Ceph a criação de uma imagem RBD no pool correspondente.
  4. Um PersistentVolume (PV) é criado dinamicamante e vinculado (Bound) ao PVC.
  5. O driver mapeia o dispositivo de bloco no nó onde o Pod está agendado e monta o sistema de arquivos solicitado.

Para validar o mapeamanto no nível do sistema operacional, pode-se executar o comando rbd showmapped nos nós do cluster, revelando os dispositivos /dev/rbd* ativos.

Escalabilidade com StatefulSets

Para aplicações que exigem armazenamento persistente individual por réplica, como clusters de bancos de dados ou sistemas distribuídos, utilizamos o volumeClaimTemplates em um StatefulSet:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: srv-web-escalavel
spec:
  serviceName: "nginx"
  replicas: 2
  selector:
    matchLabels:
      app: web-node
  template:
    metadata:
      labels:
        app: web-node
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        volumeMounts:
        - name: data-storage
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: data-storage
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "ceph-rbd-sc"
      resources:
        requests:
          storage: 5Gi

Neste modelo, cada Pod gerado (ex: srv-web-escalavel-0, srv-web-escalavel-1) receberá seu próprio volume RBD exclusivo e persistente.

Tags: Ceph Rook kubernetes RBD StorageClass

Publicado em 9-14 16:06