Volumes
Sabemos que a função do container é processar dados e morrer e o que segura ele vivo é o processo com ID 1. Se esse processo morrer o container para. Somente é destruído os dados quando o container é destruído.

No mundo dos containers para persistir os dados usamos os volumes.

Os containers dentro de um pod rodam em suas respectivas camadas read-write como falamos anteriormente. O pod controla os containers dentro dele e quando um pod é finalizado ele destrói seus respectivos containers levando junto os dados.

Para persistir os dados é necessário também o uso de volumes.

Se criamos um pod normalmente os dados são perdidos quando o pod morrer

Para criar um volume usando um driver Local precisamos declarar um volume. Seria o mesmo processo quando um container cria o volume automaticamente. No cenário abaixo criamos um volume dentro do host, mas o volume ainda não está sendo usado.

É necessário mapear que o /opt do container corresponda ao volume no /data.

Se esse pod for destruído e criado novamente e subir em um node diferente, o dado estará lá? Não.
Dois pontos que devemos levar em consideração aqui.
-
Esse volume esta passando um path no node logo esse diretório precisa existir previamente com permissão adequada.
-
Isso funcionaria para um cluster com um único nó.
-
Em um cluster com múltiplos o pod pode subir em qualquer node que passe pela filtragem do scheduler. O dados não estariam disponíveis se ele subisse em um node diferente do que subiu antes.
Ter réplicas para o mesmo pod necessita que todos os pods vejam o mesmo diretório para que os dados façam sentido.
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: "ramdon-number-generator"
spec:
containers:
- name: alpine
image: "alpine"
command: ["/bin/sh", "-c"]
args: ["shuf -i 0-100 -n 1 >> /opt/number.out;"]
volumeMounts:
- name: data-volume
mountPath: /opt
volumes:
- name: data-volume
hostPath:
path: /data
type: Directory
EOF
# Observe que o pod não esta ready.
kubectl get pods
NAME READY STATUS RESTARTS AGE
ramdon-number-generator 0/1 ContainerCreating 0 22s
kubectl describe pod ramdon-number-generator
## Removido para facilitar a leitura
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 28s default-scheduler Successfully assigned default/ramdon-number-generator to kind-cluster-worker2
# Não conseguiu montar como esperado
Warning FailedMount 13s (x6 over 29s) kubelet MountVolume.SetUp failed for volume "data-volume" : hostPath type check failed: /data is not a directory
Se você trocasse por /tmp funcionaria.
Mas esta é uma solução específica para alguns e não para a grande maioria. O ideal não é guardar os dados das aplicações dentro dos nodes, mas ter uma solução externa para esse propósito.
Kubernetes suporta diferentes tipos de soluções de armazenamento.
- NFS
- GlusterFS
- Flocker
- Ceph
- Scaleio
- vSphere
- Outras
E também muitas soluções de cloud como:
- AWS
- Azure
- GCP
- outros
Por exemplo na AWS poderíamos usar o EBS.
volumes:
- name: data-volume
awsElasticBlockStore:
volumeID: <volume-id>
fsType: ext4
Vamos criar um container do nginx e um volume compartilhado entre ele e outro. O segundo container deverá colocar a hora no index.html do nginx.
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: pod-com-dois-containers
spec:
containers:
- name: nginx-container
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: html-volume
mountPath: /usr/share/nginx/html
- name: hora-container
image: alpine
command: ["/bin/sh", "-c"]
args:
- while true; do echo "$(date '+%Y-%m-%d %H:%M:%S')" > /mnt/html/index.html; sleep 1; done
volumeMounts:
- name: html-volume
mountPath: /mnt/html
volumes:
- name: html-volume
emptyDir: {}
EOF
