Executar uma Aplicação Com Estado e de Instância Única
Esta página mostra como executar um aplicativo com estado e de instância única no Kubernetes utilizando um PersistentVolume e um Deployment. O aplicativo utilizado é o MySQL.
Objetivos
- Crie um PersistentVolume referenciando um disco no seu ambiente.
- Crie um Deployment do MySQL.
- Exponha o MySQL para outros pods no cluster em um nome DNS conhecido.
Antes de você começar
Você precisa ter um cluster do Kubernetes e a ferramenta de linha de comando kubectl deve estar configurada para se comunicar com seu cluster. É recomendado executar esse tutorial em um cluster com pelo menos dois nós que não estejam atuando como hosts de camada de gerenciamento. Se você ainda não possui um cluster, pode criar um usando o minikube ou pode usar um dos seguintes ambientes:
Para verificar a versão, digite
kubectl version
.Você precisa ter um provisionador dinâmico de PersistentVolume com uma StorageClass padrão, ou provisionar PersistentVolumes estaticamente por conta própria para atender aos PersistentVolumeClaims utilizados aqui.
Fazer o deploy do MySQL
Você pode executar um aplicativo com estado criando um Deployment do Kubernetes e conectando-o a um PersistentVolume existente usando um PersistentVolumeClaim. Por exemplo, este arquivo YAML descreve um Deployment que executa o MySQL e faz referência ao PersistentVolumeClaim. O arquivo define um volume mount para /var/lib/mysql e, em seguida, cria um PersistentVolumeClaim que procura por um volume de 20G. Essa requisição é atendida por qualquer volume existente que atenda aos requisitos ou por um provisionador dinâmico.
Note: A senha é definida no arquivo de configuração yaml, e isso não é seguro. Veja Secrets do Kubernetes para uma solução segura.
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
selector:
app: mysql
clusterIP: None
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
spec:
selector:
matchLabels:
app: mysql
strategy:
type: Recreate
template:
metadata:
labels:
app: mysql
spec:
containers:
- image: mysql:9
name: mysql
env:
# Em cenários reais, utilize um Secret
- name: MYSQL_ROOT_PASSWORD
value: password
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim:
claimName: mysql-pv-claim
apiVersion: v1
kind: PersistentVolume
metadata:
name: mysql-pv-volume
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 20Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/data"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pv-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
Faça o deploy do PV e do PVC do arquivo YAML:
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-pv.yaml
Faça o deploy do conteúdo do arquivo YAML:
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-deployment.yaml
Exiba informações sobre o Deployment:
kubectl describe deployment mysql
A saída é semelhante a esta:
Name: mysql Namespace: default CreationTimestamp: Tue, 01 Nov 2016 11:18:45 -0700 Labels: app=mysql Annotations: deployment.kubernetes.io/revision=1 Selector: app=mysql Replicas: 1 desired | 1 updated | 1 total | 0 available | 1 unavailable StrategyType: Recreate MinReadySeconds: 0 Pod Template: Labels: app=mysql Containers: mysql: Image: mysql:9 Port: 3306/TCP Environment: MYSQL_ROOT_PASSWORD: password Mounts: /var/lib/mysql from mysql-persistent-storage (rw) Volumes: mysql-persistent-storage: Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace) ClaimName: mysql-pv-claim ReadOnly: false Conditions: Type Status Reason ---- ------ ------ Available False MinimumReplicasUnavailable Progressing True ReplicaSetUpdated OldReplicaSets: <none> NewReplicaSet: mysql-63082529 (1/1 replicas created) Events: FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 33s 33s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set mysql-63082529 to 1
Liste os pods criados pelo Deployment:
kubectl get pods -l app=mysql
A saída é semelhante a esta:
NAME READY STATUS RESTARTS AGE mysql-63082529-2z3ki 1/1 Running 0 3m
Inspecione o PersistentVolumeClaim:
kubectl describe pvc mysql-pv-claim
A saída é semelhante a esta:
Name: mysql-pv-claim Namespace: default StorageClass: Status: Bound Volume: mysql-pv-volume Labels: <none> Annotations: pv.kubernetes.io/bind-completed=yes pv.kubernetes.io/bound-by-controller=yes Capacity: 20Gi Access Modes: RWO Events: <none>
Acessando a instância do MySQL
O arquivo YAML anterior cria um Service que permite que outros Pods no cluster acessem o banco de dados. A opção clusterIP: None
faz com que o nome DNS do Service resolva diretamente para o endereço IP do Pod. Isso é ideal quando você tem apenas um Pod por trás do Service e não pretende aumentar o número de Pods.
Execute um cliente MySQL para se conectar ao servidor:
kubectl run -it --rm --image=mysql:9 --restart=Never mysql-client -- mysql -h mysql -ppassword
Este comando cria um novo Pod no cluster executando um cliente MySQL e o conecta ao servidor por meio do Service. Se a conexão for bem-sucedida, você saberá que seu banco de dados MySQL com estado está em funcionamento.
Waiting for pod default/mysql-client-274442439-zyp6i to be running, status is Pending, pod ready: false
If you don't see a command prompt, try pressing enter.
mysql>
Atualizando
A imagem ou qualquer outra parte do Deployment pode ser atualizada normalmente
com o comando kubectl apply
. Aqui estão algumas precauções específicas para aplicativos com estado:
- Não faça o escalonamento do aplicativo. Esta configuração é apenas para aplicativos de instância única. O PersistentVolume subjacente só pode ser montado em um Pod. Para aplicativos com estado em cluster, consulte a documentação do StatefulSet.
- Use
strategy:
type: Recreate
no arquivo YAML de configuração do Deployment. Isso instrui o Kubernetes a não usar atualizações graduais. Atualizações graduais não funcionarão, pois não é possível ter mais de um Pod em execução ao mesmo tempo. A estratégiaRecreate
irá parar o primeiro Pod antes de criar um novo com a configuração atualizada.
Excluindo um deployment
Exclua os objetos implantados pelo nome:
kubectl delete deployment,svc mysql
kubectl delete pvc mysql-pv-claim
kubectl delete pv mysql-pv-volume
Se você provisionou manualmente um PersistentVolume, também precisará excluí-lo manualmente, assim como liberar o recurso subjacente. Se você usou um provisionador dinâmico, ele exclui automaticamente o PersistentVolume ao detectar que você excluiu o PersistentVolumeClaim. Alguns provisionadores dinâmicos (como os de EBS e PD) também liberam o recurso subjacente ao excluir o PersistentVolume.
Próximos passos
Saiba mais sobre objetos Deployment.
Saiba mais sobre implantação de aplicativos