====== Gerenciar Volumes no Kubernetes ======
==== Trabalhando com Volumes Baseado em Host ====
=== Volume emptyDir ===
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
kube-ctrl-pl-01.juntotelecom.com.br Ready control-plane,master 4d20h v1.23.5
kube-worker-01.juntotelecom.com.br Ready 2d v1.23.5
kube-worker-02.juntotelecom.com.br Ready 2d v1.23.5
apiVersion: v1
kind: Pod
metadata:
name: pod1
spec:
containers:
- name: busybox
image: busybox:1.28
imagePullPolicy: IfNotPresent
command:
- sleep
- "3600"
volumeMounts:
- mountPath: /backup
name: backup-volume
volumes:
- name: backup-volume
emptyDir: {}
nodeSelector:
kubernetes.io/hostname: kube-worker-01.juntotelecom.com.br
* **volumeMounts**: Define quais serão os pontos de montagem de volumes dentro do Pod.
* **mountPath**: Define a localização da montagem do volume dentro do Pod.
* **volumes**: Define quais serão os volumes utilizados pelo Pod.
* **name**: Define o nome do volume que será utilizado pelo Pod.
* **emptyDir**: Cria um volume quando um Pod é atribuído a um Nó, e existe desde que esse Pod esteja em execução nesse nó. Como o nome diz, inicialmente está vazio.
* **nodeSelector**: Define em qual nó o Pod será alocado. Isso é possível devido ao label kubernetes.io/hostname: kube-worker-01.juntotelecom.com.br.
$ kubectl apply -f pod1.yaml
pod/pod1 created
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod1 1/1 Running 0 119s 172.16.101.73 kube-worker-01.juntotelecom.com.br
$ kubectl exec -it pod1 -- df -Th backup
Filesystem Type Size Used Available Use% Mounted on
/dev/sda1 ext4 30.4G 2.2G 26.6G 8% /backup
$ kubectl get po pod1 -o yaml | grep uid
uid: 1a3c822d-d9d1-40f9-8b3b-273e953a2701
$ kubectl exec -it pod1 -- cp /etc/hosts /backup
$ ssh kube-worker-01.juntotelecom.com.br
$ sudo ls /var/lib/kubelet/pods/1a3c822d-d9d1-40f9-8b3b-273e953a2701/volumes/kubernetes.io~empty-dir/backup-volume
hosts
$ sudo cat /var/lib/kubelet/pods/1a3c822d-d9d1-40f9-8b3b-273e953a2701/volumes/kubernetes.io~empty-dir/backup-volume/hosts
# Kubernetes-managed hosts file.
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
172.16.101.73 pod1
$ kubectl delete -f pod1.yaml
pod "pod1" deleted
=== Volume hostPath ===
---
apiVersion: v1
kind: Pod
metadata:
name: pod2
spec:
containers:
- image: busybox:1.28
imagePullPolicy: IfNotPresent
name: busybox
command:
- sleep
- "3600"
volumeMounts:
- mountPath: /backup
name: backup-volume
volumes:
- name: backup-volume
hostPath:
path: /home/gean/data
type: Directory
nodeSelector:
kubernetes.io/hostname: kube-worker-02.juntotelecom.com.br
* **hostPath**: Um volume hostPath, monta um arquivo ou diretório do sistema de arquivos do nó do host no seu Pod;
* **path**: Define o caminho que o volume vai armazenar os arquivos fisicamente no Nó;
* **type**: Define o tipo de objeto utilizado no volume. No exemplo apresentado estamos usando **Directory**.
* **nodeSelector**: Define em qual nó o Pod será alocado. Isso é possível devido ao label kubernetes.io/hostname: kube-worker-02.juntotelecom.com.br.
$ ssh kube-worker-02.juntotelecom.com.br
$ mkdir /home/gean/data
$ kubectl apply -f pod2.yaml
pod/pod2 created
$ kubectl get po pod2 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod2 1/1 Running 0 29s 172.16.213.137 kube-worker-02.juntotelecom.com.br
$ kubectl exec -it pod2 -- df -Th backup
Filesystem Type Size Used Available Use% Mounted on
/dev/sdb1 ext4 30.4G 2.2G 26.6G 8% /backup
$ scp /etc/hostname kube-worker-02.juntotelecom.com.br:/home/gean/data
$ kubectl exec -it pod2 -- ls /backup
hostname
$ kubectl exec -it pod2 -- cat /backup/hostname
kube-ctrl-pl-01.juntotelecom.com.br
$ kubectl delete -f pod2.yaml
pod "pod2" deleted
====== Gerenciar Storage Class, Persistent Volume e Persistent Volume Claim ======
=== Storage Class ===
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: local-storage
namespace: default
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
* **provisioner**: Determina qual plug-in de volume é usado para provisionar Pvs;
* **volumeBindingMode**: Permite controlar quando a vinculação de volume e o provisionamento dinâmico devem ocorrer. O valor WaitForFirstConsumer atrasará a vinculação e o provisionamento de um PersistentVolume, até que um Pod usando PersistentVolumeClaim seja criado.
[[https://kubernetes.io/docs/concepts/storage/storage-classes/]]
$ kubectl apply -f storage-class.yaml
storageclass.storage.k8s.io/local-storage created
$ kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
local-storage kubernetes.io/no-provisioner Delete WaitForFirstConsumer false 54s
=== Persistent Volume ===
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-deploy
namespace: default
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-storage
local:
path: /home/gean/data
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- kube-worker-02.juntotelecom.com.br
* **capacity**: Define a capacidade de armazenamento do volume;
* **accessModes**: Define o modo de acesso ao volume. O valor **ReadWriteOnce** permite que o volume possa ser montado como leitura-gravação por um único nó. No valor **ReadOnlyMany** o volume pode ser montado somente para leitura por muitos nós e no valor **ReadWriteMany** o volume pode ser montado como leitura-escrita por muitos nós;
* **persistentVolumeReclaimPolicy**: Define o que acontece com um volume persistente, quando liberado de sua reivindicação. As opções válidas são **Retain** (padrão para PersistentVolumes, criados manualmente), **Delete** (padrão para PersistentVolumes, provisionados dinamicamente) e **Recycle** (reprovado). A reciclagem deve ser suportada pelo plug-in de volume subjacente a este PersistentVolume;
* **storageClassName**: Define o nome do Storage Class.
* **nodeAffinity, required, nodeSelectorTerms**: Define em qual nó o Pod será alocado. Isso é possível devido ao label kubernetes.io/hostname: kube-worker-02.juntotelecom.com.br.
$ kubectl apply -f volume-local.yaml
persistentvolume/pv-deploy created
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-deploy 1Gi RWO Retain Available local-storage 5m36s
=== Persistent Volume Claim ===
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: volume-claim-local
namespace: default
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-storage
resources:
requests:
storage: 1Gi
* **resources**: Define a solicitação de armazenamento. O mesmo modelo de recurso se aplica a volumes e volume claim;
* **requests**: PVCs são solicitações para esses recursos e também atuam como verificações de declaração para o recurso.
$ kubectl apply -f claim-local.yaml
persistentvolumeclaim/volume-claim-local created
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
volume-claim-local Pending local-storage 23s
$ kubectl get sc,pv,pvc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
storageclass.storage.k8s.io/local-storage kubernetes.io/no-provisioner Delete WaitForFirstConsumer false 13m
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pv-deploy 1Gi RWO Retain Available local-storage 9m26s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/volume-claim-local Pending local-storage 63s
=== Executar Deploy com Volumes Persistentes ===
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: storage
volumes:
- name: storage
persistentVolumeClaim:
claimName: volume-claim-local
* **persistentVolumeClaim**: Define o uso de Volume Persistent Claim no Deploy.
* **claimName**: Define o nome do Volume Persistent Claim.
$ kubectl apply -f nginx-deploy.yaml
deployment.apps/nginx-deploy created
$ kubectl get po -l app=nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deploy-56f5cc7dff-jxbc8 1/1 Running 0 119s 172.16.213.138 kube-worker-02.juntotelecom.com.br
$ kubectl get sc,pv,pvc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
storageclass.storage.k8s.io/local-storage kubernetes.io/no-provisioner Delete WaitForFirstConsumer false 18m
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pv-deploy 1Gi RWO Retain Bound default/volume-claim-local local-storage 13m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/volume-claim-local Bound pv-deploy 1Gi RWO local-storage 5m21s
POD=$(kubectl get pods | grep nginx-deploy | awk -F" " '{print $1}')
$ kubectl exec -it $POD -- mount | grep nginx
/dev/sdb1 on /usr/share/nginx/html type ext4 (rw,relatime,errors=remount-ro)
HOST=$(kubectl get pods -o wide | grep nginx-deploy | awk -F" " '{print $6}')
$ curl $HOST
403 Forbidden
403 Forbidden
nginx/1.21.6
$ echo 'Servidor Nginx - Node 2' > index.html
$ scp index.html kube-worker-02.juntotelecom.com.br:/home/gean/data
$ curl $HOST
Servidor Nginx - Node 2
$ kubectl delete -f nginx-deploy.yaml
deployment.apps "nginx-deploy" deleted