Kubernetes statefulset com volume NFS persistente

Oct 16 2020

Eu tenho um kubernetescluster e tenho uma implantação simples mongodbcom NFSconjunto de volume persistente. Funciona bem, mas como recursos como bancos de dados stateful, pensei em usar Statefulsetpara o mongodb, mas agora o problema é que, quando analiso a documentação, o statefulset tem em volumeClaimTemplatesvez de volumes(em implantações).

Mas agora vem o problema.

em um deploymentfaça assim:

PersistentVolume-> PersistentVolumeClaim->Deployment

Mas como podemos fazer isso Statefulset?

É como:

volumeClaimTemplates -> StatefulSet

Como posso definir um PersistentVolumepara o volumeClaimTemplates. Se não usarmos PersistentVolumepara StatefulSet, como ele cria o volume e ONDE ele cria os volumes? Está em hostmáquinas (ou seja, nós de trabalho do Kubernetes)?

Como tenho um NFSprovisionador separado que estou usando para a mongodbimplantação (com replicasset = 1), como posso usar a mesma configuração StatefulSet?

Aqui está o my mongo-deployment.yaml-> que irei transformar em um statefulset, conforme mostrado no segundo trecho de código ( mongo-stateful.yaml)

  1. mongo-deployment.yaml
<omitted>
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: task-pv-volume
  labels:
    name: mynfs # name can be anything
spec:
  storageClassName: manual # same storage class as pvc
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  nfs:
    server: <nfs-server-ip>
    path: "/srv/nfs/mydata" 
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: task-pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteMany #  must be the same as PersistentVolume
  resources:
    requests:
      storage: 1Gi          
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongodb-deployment    
  labels:
    name: mongodb
spec:
  selector:
    matchLabels:
      app: mongodb
  replicas: 1
  template:
    metadata:
      labels: 
        app: mongodb
    spec:
      containers:
      - name: mongodb
        image: mongo
        ports:
        -  containerPort: 27017
        ... # omitted some parts for easy reading
        volumeMounts:
        - name: data  
          mountPath: /data/db
      volumes: 
        - name: data
          persistentVolumeClaim: 
            claimName: task-pv-claim    
  1. mongo-stateful.yaml
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: task-pv-volume
  labels:
    name: mynfs # name can be anything
spec:
  storageClassName: manual # same storage class as pvc
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    server: <nfs-server-ip>
    path: "/srv/nfs/mydata" 
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongodb-statefulset
spec:
  selector:
    matchLabels:
      name: mongodb-statefulset
  serviceName: mongodb-statefulset
  replicas: 2
  template:
    metadata:
      labels:
        name: mongodb-statefulset
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: mongodb
        image: mongo:3.6.4
        ports:
        - containerPort: 27017
        volumeMounts:
        - name: db-data
          mountPath: /data/db
  volumeClaimTemplates:
  - metadata:
      name: db-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "manual"
      resources:
        requests:
          storage: 2Gi

Mas isso não está funcionando ( mongo-stateful.yaml) os pods estão no pendingestado quando eu os descrevo:

default-scheduler 0/3 nodes estão disponíveis: 1 node (s) tinha taint {node-role.kubernetes.io/master:}, que o pod não tolerou, 2 pod tem PersistentVolumeClaims imediatos não ligados

PS: A implantação funciona bem sem erros, o problema é com Statefulset

Alguém pode me ajudar, como escrever um statefulset com volumes?

Respostas

1 fjammes Oct 16 2020 at 14:50

Se sua classe de armazenamento não suportar provisionamento de volume dinâmico, você terá que criar PVs e PVCs associados manualmente , usando arquivos yaml, então o volumeClaimTemplates permitirá vincular PVCs existentes com seus pods de statefulset.

Aqui está um exemplo prático: https://github.com/k8s-school/k8s-school/blob/master/examples/MONGODB-install.sh

Você deve:

  • execute-o localmente em https://kind.sigs.k8s.io/, que suportam provisionamento de volume dinâmico, então aqui os PVCs e PVs serão criados automaticamente
  • exportar arquivos yaml de PVs e PVCs
  • use esses arquivos yaml como modelo para criar seus PVs e PVCs para seu back-end NFS.

Aqui está o que você obterá no Kind:

$ ./MONGODB-install.sh + kubectl apply -f 13-12-mongo-configmap.yaml configmap/mongo-init created + kubectl apply -f 13-11-mongo-service.yaml service/mongo created + kubectl apply -f 13-14-mongo-pvc.yaml statefulset.apps/mongo created $ kubectl get pods
NAME      READY   STATUS    RESTARTS   AGE
mongo-0   2/2     Running   0          8m38s
mongo-1   2/2     Running   0          5m58s
mongo-2   2/2     Running   0          5m45s
$ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE database-mongo-0 Bound pvc-05247511-096e-4af5-8944-17e0d8222512 1Gi RWO standard 8m42s database-mongo-1 Bound pvc-f53c35a4-6fc0-4b18-b5fc-d7646815c0dd 1Gi RWO standard 6m2s database-mongo-2 Bound pvc-2a711892-eeee-4481-94b7-6b46bf5b76a7 1Gi RWO standard 5m49s $ kubectl get pv 
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                      STORAGECLASS   REASON   AGE
pvc-05247511-096e-4af5-8944-17e0d8222512   1Gi        RWO            Delete           Bound    default/database-mongo-0   standard                8m40s
pvc-2a711892-eeee-4481-94b7-6b46bf5b76a7   1Gi        RWO            Delete           Bound    default/database-mongo-2   standard                5m47s
pvc-f53c35a4-6fc0-4b18-b5fc-d7646815c0dd   1Gi        RWO            Delete           Bound    default/database-mongo-1   standard                6m1s

E um dump de um PVC (gerado aqui por volumeClaimTemplateporque odf kind dynamic volume provisionning):

$ kubectl get pvc database-mongo-0 -o yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  annotations:
    pv.kubernetes.io/bind-completed: "yes"
    pv.kubernetes.io/bound-by-controller: "yes"
    volume.beta.kubernetes.io/storage-provisioner: rancher.io/local-path
    volume.kubernetes.io/selected-node: kind-worker2
  creationTimestamp: "2020-10-16T15:05:20Z"
  finalizers:
  - kubernetes.io/pvc-protection
  labels:
    app: mongo
  managedFields:
    ...
  name: database-mongo-0
  namespace: default
  resourceVersion: "2259"
  selfLink: /api/v1/namespaces/default/persistentvolumeclaims/database-mongo-0
  uid: 05247511-096e-4af5-8944-17e0d8222512
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: standard
  volumeMode: Filesystem
  volumeName: pvc-05247511-096e-4af5-8944-17e0d8222512
status:
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: 1Gi
  phase: Bound

E o PV relacionado:

kubectl get pv pvc-05247511-096e-4af5-8944-17e0d8222512 -o yaml     
apiVersion: v1
kind: PersistentVolume
metadata:
  annotations:
    pv.kubernetes.io/provisioned-by: rancher.io/local-path
  creationTimestamp: "2020-10-16T15:05:23Z"
  finalizers:
  - kubernetes.io/pv-protection
  managedFields:
    ...
  name: pvc-05247511-096e-4af5-8944-17e0d8222512
  resourceVersion: "2256"
  selfLink: /api/v1/persistentvolumes/pvc-05247511-096e-4af5-8944-17e0d8222512
  uid: 3d1e894e-0924-411a-8378-338e48ba4a28
spec:
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: 1Gi
  claimRef:
    apiVersion: v1
    kind: PersistentVolumeClaim
    name: database-mongo-0
    namespace: default
    resourceVersion: "2238"
    uid: 05247511-096e-4af5-8944-17e0d8222512
  hostPath:
    path: /var/local-path-provisioner/pvc-05247511-096e-4af5-8944-17e0d8222512_default_database-mongo-0
    type: DirectoryOrCreate
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - kind-worker2
  persistentVolumeReclaimPolicy: Delete
  storageClassName: standard
  volumeMode: Filesystem
status:
  phase: Bound