Volumes locaux
À partir du modèle suivant, créer un pod constitué de deux conteneurs. Basés sur busybox, ceux-ci vont nous permettre d'illustrer le fonctionnement des volumes partagés.
Nous allons commencer par un volume de type EmptyDir monté dans le /data/shared-storage sur chaque conteneur.
apiVersion: v1
kind: Pod
metadata:
name: volume-test
labels:
app: volume-test
spec:
volumes:
... # volumes à partager
containers:
- name: busybox1
image: busybox
command: [ "/bin/sh", "-c", "--" ]
args: ["trap : TERM INT; (while true; do sleep 1000; done) & wait"]
volumeMounts:
... # montage du volume partagé dans le premier conteneur
- name: busybox2
image: busybox
command: [ "/bin/sh", "-c", "--" ]
args: ["trap : TERM INT; (while true; do sleep 2000; done) & wait"]
volumeMounts:
... # montage du volume partagé dans le second conteneur
- Appliquer le manifeste et vérifier la création.
- La description du pod doit indiquer la présence du volume partagé
kubectl describe pod volume-test
Volumes:
shared-storage:
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
- Nous pouvons exécuter un terminal à l'intérieur des deux conteneurs
kubectl exec -it volume-test -c busybox1 /bin/sh
kubectl exec -it volume-test -c busybox2 /bin/sh
- Depuis le premier conteneur, créé un fichier à la racine
echo test1 > /test1.txt
- Depuis le second conteneur, afficher les fichiers à la racine, rien de particulier ne doit apparaitre
- Depuis le premier conteneur, créé un fichier dans /data/shared-storage/
echo test-shared1 > /data/shared-storage/shared1
- Depuis le second conteneur, liste les fichiers dans le répertoire partagé
ls /data/shared-storage/
/data/shared-storage # ls
shared1
- Nous allons tuer le second conteneur, ce qui va provoquer la création d'un nouveau conteneur pour prendre sa place
# Depuis l'intérieur de second conteneur
/ > kill 1
/ > command terminated with exit code 137
- Après la recréation du conteneur, se connecter à l'intérieur.
Le fichier créé précédemment est-il toujours présent ?
Stockage distant
Nous allons manipuler les trois types de ressources qui permettent de monter des volumes distants dans un Pod :
- les StorageClasses ;
- les PersistentVolumes ;
- les PersistentVolumeClaims ;
Les volumes distants se déclarent au niveau des Pods de la même manière que les volumes locaux. La différence étant qu'un volume distant est forcément attaché à une StorageClass.
Généralement, la StorageClass est fournie par l'administrateur de la plateforme et n'a pas besoin d'être créé par l'utilisateur. Nous allons cependant en créer une pour bien comprendre l'intéraction de tous les éléments.
Création et montage d'un PVC
Commençons par regarder notre StorageClass, celle-ci nous permettra de créer des PersistentVolumeClaim sans devoir spécifier les mêmes paramètres à chaque fois.
- Vous disposez d'une StorageClass définie comme suit dans le cluster :
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: capacitive-fs
parameters:
clusterID: 691e2997-9932-426f-be8e-ea633a02bb12
csi.storage.k8s.io/controller-expand-secret-name: dtl-train-fs-secret
csi.storage.k8s.io/controller-expand-secret-namespace: cephfs
csi.storage.k8s.io/node-stage-secret-name: dtl-train-fs-secret
csi.storage.k8s.io/node-stage-secret-namespace: cephfs
csi.storage.k8s.io/provisioner-secret-name: dtl-train-fs-secret
csi.storage.k8s.io/provisioner-secret-namespace: cephfs
fsName: fast-distributed-fs
mounter: kernel
pool: dtl-train-cd-data
provisioner: cephfs.csi.ceph.com
reclaimPolicy: Retain
allowVolumeExpansion: true
volumeBindingMode: Immediate
Grace à cette StorageClass, nous pouvons créer un PersistentVolumeClaim.
- Créer le PVC selon le modèle suivant.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ceph-claim
namespace: <votre namespace>
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Mi
storageClassName: capacitive-fs
- Après quelques secondes, la description du PVC doit indiqué que celui-ci est attaché à un volume persistant.
kubectl describe pvc ceph-claim
Name: ceph-claim
...
Status: Bound
Volume: pvc-63318b64-bf5d-11e8-9a69-00505687a6c6
Annotations: pv.kubernetes.io/bind-completed=yes
pv.kubernetes.io/bound-by-controller=yes
volume.beta.kubernetes.io/storage-provisioner=kubernetes.io/rbd
Finalizers: [kubernetes.io/pvc-protection]
Capacity: 100Mi
Access Modes: RWO
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ProvisioningSucceeded 15m persistentvolume-controller Successfully provisioned volume pvc-63318b64-bf5d-11e8-9a69-00505687a6c6 using kubernetes.io/rbd
- Pour confirmer cela, nous pouvons afficher le volume persistant en question.
kubectl describe persistentvolume pvc-63318b64-bf5d-11e8-9a69-00505687a6c6
Name: pvc-63318b64-bf5d-11e8-9a69-00505687a6c6
...
Status: Bound
Claim: apl/ceph-claim
Reclaim Policy: Delete
Access Modes: RWO
Capacity: 100Mi
Source:
Type: RBD (a Rados Block Device mount on the host that shares a pod's lifetime)
RBDImage: kubernetes-dynamic-pvc-6333de5b-bf5d-11e8-8429-00505687593b
Keyring: /etc/ceph/keyring
SecretRef: &{ceph-admin-secret }
ReadOnly: false
Enfin, il ne nous reste plus qu'à créer un pod pour consommer ce volume persistant. Dans le cas d'un PV créé via un PersistentVolumeClaim comme c'est le cas ici, il suffit de monter le PVC comme un volume. Kubernetes gère alors pour nous le cycle de vie du provisionnement, les pods ne seront pas disponibles tant que le PVC ne disposera pas d'un PV attaché.
- Créer un pod sur le modèle suivant.
apiVersion: v1
kind: Pod
metadata:
name: volume-test
labels:
app: volume-test
spec:
volumes:
- name: claim-volume
persistentVolumeClaim:
claimName: <nom du pvc>
containers:
- name: busybox1
image: busybox
command: [ "/bin/sh", "-c", "--" ]
args: ["trap : TERM INT; (while true; do sleep 1000; done) & wait"]
volumeMounts:
... # monter le PVC déclaré comme volume plus haut
- Après création, le volume partagé est utilisable depuis le Pod (nous pourrions vérifier de la même
manière que pour les volumes
emptyDirvus plus haut).
Suppression
La suppression des ressources persistantes est une opération délicate qui expose au risque de perte définitive de données. Nous allons observer les mécanismes offerts par Kubernetes pour protéger les volumes persistants de suppressions accidentelles.
PVC protection
La fonctionnalité "Storage Object in Use Protection" permet d'empêcher la suppression des volumes montés par des Pods.
- Afficher la description du Pod créé précedemment
kubectl describe pod volume-test
Le résultat doit contenir le point de montage du conteneur ainsi qu'un évennement de montage du volume.
Containers:
busybox1:
...
Mounts:
/data/shared-volume from claim-volume (rw)
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulAttachVolume 3s attachdetach-controller AttachVolume.Attach succeeded for volume "pvc-63318b64-bf5d-11e8-9a69-00505687a6c6"
- Afficher la description du PVC.
kubectl describe pvc <nom du pvc>
Le résultat doit contenir une ligne telle que ci-dessous.
Finalizers: [kubernetes.io/pvc-protection]
Cette ligne indique que la protection des volumes déjà montés est activée.
- Maintenant que nous avons vérifié la bonne activation de la protection, nous allons supprimer le PVC.
kubectl delete pvc <nom du pvc>
kubectl get pvc
Le PVC doit maintenant se trouver dans l'état Terminating
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
ceph-claim Terminating pvc-63318b64-bf5d-11e8-9a69-00505687a6c6 100Mi RWO ceph 1h
Le PVC restera dans cet état tant qu'il sera monté dans un Pod. - Supprimons donc notre Pod
kubectl delete pod <nom du pod>
Immédiatement après la suppression du Pod, le PVC et le PV sont supprimés.
> kubectl get pvc
No resources found.
> kubectl get pv
No resources found.
Reclaim policy
L'attribut reclaim policy d'un PersistentVolume définit l'action à mener lors de la suppresion du
PersistentVolumeClaim qui l'a provisionné dynamiquement.
La reclaim policy par défaut est Delete, ce qui signifie qu'à la suppression du PVC, le PV sera également supprimé.
Il est possible de modifier cette valeur pour Retain, afin de conserver le PV intact.
- Recréer le PVC que nous venons de supprimer.
- Attendre le provisionnement du PV correspondant.
- Afficher la description du PV correspondant.
kubectl get pv <identifiant du pv créé>
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-96dd4fc0-bf6d-11e8-9a69-00505687a6c6 100Mi RWO Delete Bound ceph-claim ceph 25s
Comme prévu, la valeur de reclaim policy est Delete
- Modifier la valeur de reclaim policy
kubectl edit pv <identifiant du pv>
Nous pouvons maintenant supprimer le PVC et constater que le PV n'est pas supprimé automatiquement.
kubectl delete pvc <nom du pvc>
kubectl get pv
Le statut du PV passe à Released
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-96dd4fc0-bf6d-11e8-9a69-00505687a6c6 100Mi RWO Retain Released ceph-claim ceph 4m