Alura > Cursos de DevOps > Cursos de Containers > Conteúdos de Containers > Primeiras aulas do curso Kubernetes: Deployments, Volumes e Escalabilidade

Kubernetes: Deployments, Volumes e Escalabilidade

Conhecendo ReplicaSets e Deployments - Introdução

Eu sou o Daniel Artine e dou as boas vindas à segunda parte do nosso curso de Kubernetes, da Alura. E nós vamos continuar falando mais sobre essa ferramenta tão poderosa, o Kubernetes, como, por exemplo, os detalhes que ficaram pendentes da parte 1.

Nós vamos abordar agora sobre o que é, por exemplo, um ReplicaSet um Deployment, um Volume e outros recursos, para que eles servem. Como nós podemos manter nossa aplicação sempre em execução utilizando uma ReplicaSet, um Deployment.

Como podemos persistir dados com Volumes e Volumes Persistentes ou, até mesmo, criá-los de maneira dinâmica com Storage Classes e escalar nossa aplicação de maneira automática com Horizontal Pod Autoscaler, conforme demanda consumo de recursos.

E nós vamos ver isso ainda no nosso cenário do Windows, do Linux, e também, fazendo algumas explicações no Google Cloud Platform para vocês absorverem o máximo de conteúdo nas três plataformas.

Então, nós vamos começar a colocar a mão na massa e também entender a teoria de início por trás dos ReplicaSets, do Deployment e eu vejo vocês no próximo vídeo e até mais.

Conhecendo ReplicaSets e Deployments - Conhecendo ReplicaSets

Uma das primeiras coisas que falamos no início do nosso curso, na parte 1, foi que quando criamos um Pod, o Kubernetes tem total capacidade de definir onde ele vai ser executado, através daquele componente chamado Escavaler.

Mas, também, vimos que caso este Pod falhe, o Kubernetes tem total capacidade de criar um novo Pod e substituir o antigo, que parou de funcionar. Com as mesmas características, mas, sendo um novo Pod e não o mesmo.

Isso porque os Pods são efêmeros, então, eles devem estar prontos para serem substituídos por questão de falha ou de atualização, sem causar grande impacto na nossa aplicação, como um todo.

Mas, como o Kubernetes vai conseguir fazer isso? Para isso, temos recursos, como nós já vimos. E esses dois recursos vão nos ajudar a resolver este tipo de problema: os ReplicaSets e os Deployments.

Nós vamos começar falando sobre os ReplicaSets e depois vamos falar sobre os Deployments.

Para entendermos o que é um ReplicaSet é bem fácil. Vamos visualizar este Pod. Nós acabamos de ver que, caso ele falhe, pare de ser executado, seja interrompido, ele morreu para sempre. Ele nunca mais vai voltar, não existe nenhuma maneira de fazer ele voltar.

E a pergunta que queremos responder é como conseguimos criar outro para assumir o lugar dele, de maneira automática.

Como assim? Vamos visualizar. Temos os nossos três Pods do banco de dado de notícias, do portal de notícias e do sistema de notícias. Caso, nós pararmos o nosso Pod do portal de notícias, sem nenhum mistério, simulando uma interrupção, o que vai acontecer?

A nossa aplicação do portal não está mais disponível porque acabamos de interromper ela, mas, vamos visualizar só para ter a garantia.

Ou seja, quando nosso Pod foi interrompido, por algum motivo, o que aconteceu? Aconteceu que ele não voltou por nenhuma razão. E nós queremos contornar esse tipo de situação, que em caso de falha ele volte.

Então, voltando à nossa apresentação, nós temos uma estrutura que resolve isso para nós, que são os ReplicaSets.

Então, vimos que um Pod é uma estrutura que encapsula um ou mais containers e um ReplicaSet nada mais é que uma estrutura que encapsula, pode encapsular, na verdade, um ou mais Pods.

Repara nas duas coisas que acabei de falar. Ela tem a capacidade de encapsular um ou mais Pods, ou seja, nós não temos a obrigatoriedade de criar um Pod com um ReplicaSet. Não é a toa que nós viemos fazendo isso, até agora, no curso. E que ele também pode gerenciar um ou mais Pods, ao mesmo tempo.

Logo, se, um desses Pods falhar, e ele nunca mais vai voltar, mas o ReplicaSet vai conseguir criar um novo para nós. E isso também vai funcionar para diversos Pods gerenciados por um mesmo ReplicaSet.

Então, o que vai acontecer? Caso algum desses Pods falhe, o que vai acontecer? Nós vamos ter um número de Pods desejados diferentes do número de Pods prontos. Logo, o próprio ReplicaSet vai criar um Pod novo para substituir esse que parou de funcionar.

E por que nós podemos ter diversas réplicas? Por diversos motivos que ainda vamos abordar no decorrer do curso.

Mas, um deles é que enquanto este Pod está voltando a ser executado, para que consigamos acessar nossa aplicação, nós temos outras três formas de acessar esta mesma aplicação, porque nós possuímos cópias dela em execução, então, enquanto essa aqui não volta, nós temos outras três para receber as requisições do nosso usuário.

E, também, caso nós estejamos recebendo muita requisição, nós conseguimos dividir através de um Set que vai fazer o balanceamento de carga, as requisições para esses Pods de maneira bem igual.

Então, vamos colocar a mão na massa. Vamos criar o nosso primeiro ReplicaSet. É bem fácil.

O que nós vamos fazer? Nós vamos criar um novo arquivo, clicando no botão "New File" no canto superior esquerdo da tela, chamado portal-noticias-replicaset.yaml. E, dentro desse arquivo, a primeira grande diferença que nós vamos ver é que a versão da api não vai ser só v1, vai ser um grupo específico da v1 que é a apps/v1, que podemos até conferir na própria documentação do Kubernetes.

Então, sobre ReplicaSets, nós conseguimos ver que apiVersion: apps/v1. O tipo que nós queremos criar é um ReplicaSet e ele também possui um metadata, então, qual vai ser o nome desse ReplicaSet? Vai ser portal-noticias-replicaset.

E uma especificação para ele, o que vai conter neste ReplicaSet. É nesse momento, em que talvez você esteja pensando, basta copiar o trecho das especificações do nosso portal-noticias e colar ele aqui no ReplicaSet e está tudo feito.

Não é bem assim. Nós vamos ter algumas peculiaridades, então, eu já vou comentar isso para termos como base o que nós vamos utilizar e vamos fazer o seguinte: nós precisamos de início, definir um template.

Qual vai ser o conteúdo, qual vai ser o modelo deste ReplicaSet, qual vai ser o padrão dele? Então, nós vamos definir o que no portal-noticias-replicaset? As informações do nosso Pod.

Então, o nosso Pod possui o que? Ele possui um metadata e esse metadata tem um name, como já está especificado mais abaixo do trecho copiado. Vou, até, descomentar este trecho e copiar.

Nós temos o metada que contém um name, um label que é app: portal-noticias, então, já definimos o metadata dos Pods, ou do Pod, no singular, que vai ser gerenciado por este ReplicaSet.

Esse metadata (name: portal-noticias) é do Pod de dentro do ReplicaSet e este metadata (name: portal-noticias-replicaset) é do nosso ReplicaSet. O trecho copiado anteriormente já pode ser apagado, inclusive.

E, agora, precisamos definir o que? Quais são as especificações do nosso Pod. Então, basta pegarmos o mesmo trecho do arquivo portal-noticias.yaml e colocar alinhado com o nosso metadata.

Nós temos todas as informações do nosso Pod, que vai ser gerenciado pelo nosso ReplicaSet. Então, dentro de template nós vamos definir todas as informações do nosso Pod.

Agora falta o que? Falta definirmos, alinhado com template, o número de réplicas que queremos para nossa aplicação, então, como falei para vocês nós podemos ter um ou mais Pods sendo gerenciados por um ReplicaSet.

Nós podemos definir, por padrão, se nós não informarmos esse número vai ser 1, mas, podemos colocar 1, 2, 3, 4 e podemos colocar o quanto quisermos neste cenário. Então, eu vou colocar que nós queremos três réplicas, para caso alguma delas falhe, nós ainda vamos ter duas de backup para receber as requisições do nosso usuário.

E, por fim, falta definirmos mais uma coisa que parece ser um pouco redundante, que acaba sendo, visualmente falando. Que por mais que todas essas informações estejam definidas dentro das especificações deste ReplicaSet (metadata: name: portal-noticias-replicaset), o Kubernetes não sabe que este ReplicaSet deve gerenciar este template, que definimos anteriormente.

Nós precisamos fazer o seguinte, informar que o nosso ReplicaSet, assim como um serviço, vai selecionar os recursos que tenham um matchLabels que encaixem, que batam o valor das labels com app: portal-noticias, então, esse matchLabels tem que ser igual, idêntico ao labels.

Senão, não vai funcionar. No momento que tentarmos aplicar esse arquivo de definição, ele não vai funcionar. Então, os matchLabels e labels, repara, sempre serão iguais.

Se salvarmos ele e viermos no nosso Powershell e executar o nosso kubectl apply -f .\portal-noticias-replicaset.yaml, o que vai acontecer? Ele foi criado.

E se nós usarmos o comando kubectl get pods, nós temos três Pods, como nós definimos no nosso número de réplicas, para o nosso portal de notícias. E cada um desses Pods segue a mesma receita.

Não é à toa que todos começam o nome com portal-noticias-replicaset traço um identificador único. E todos eles vão estar expondo na porta 80, como já definimos.

Todos vão utilizar as mesmas variáveis do nosso portal do configmap sem nenhuma mudança. os três são iguais, só os identificadores que são diferentes.

Não é à toa que se viermos no nosso navegador, clicando no ícone "Internet" na barra de ferramentas, e tentar acessar o nosso portal temos tudo funcionando.

Se tentarmos cadastrar uma nova notícia no nosso sistema, clicando no botão "Nova Notícia" dentro da página do Portal de Notícias, vamos colocar 'uma notícia' dentro da aba "Título" e vamos colocar 'uma informação' dentro da aba "Notícia". Podemos colocar uma nova imagem da Alura, por exemplo, indo na aba "Foto" e clicando no botão "Escolher Arquivo", selecionando a imagem "Alura", e salvar e tudo continua funcionando.

Vão ter duas notícias com a mesma imagem, mas, o conteúdo que definimos é diferente. Tudo continua funcionando sem nenhum problema.

Se tentarmos forçar a parada de um desses Pods com o comando kubectl delete pod e colocar um deles para ser removido, o que vai acontecer? Vamos colocar no comando o Pod portal-noticias-replicaset-dkppr, vamos remover e vamos confirmar se, realmente, temos dois ou três Pods em execução.

kubectl get pods, repara que agora temos um novo Pod no lugar daquele, com identificador diferente, porém, com o mesmo comportamento, sem nenhum mistério.

Se nós executarmos um outro comando que é o kubectl get rs ou replicasets o que vai acontecer: Ele vai nos mostrar que o número desejado de Pods, atualmente, por este ReplicaSet é três, que nós definimos no nosso número de réplicas, e que o nosso atual de prontos, que nós temos, também é três. Então, tudo vai correr sem nenhum problema.

Para vocês verem mais um cenário eu vou abrir outro Powershell e nós vamos fazer o seguinte. Eu vou dividir a tela entre os dois e vou limpar a tela e na da esquerda eu vou comandar kubectl get replicaset --watch e do outro lado eu vou comandar kubectl get pods e vou dar um kubectl delete pods em qualquer um dos três Pods que está sendo gerenciado pelo nosso ReplicaSet.

Vou colocar este Pod no comando kubectl delete pods, vou colar e vou parar. O que aconteceu... por um momento tivemos dois, porque um foi removido, foi interrompido, depois nós tivemos três, mas, ele ainda não estava pronto, e, por fim, nós ficamos no nosso estado desejado, sem nenhum mistério.

E ele foi criado um novo, como já vimos. Se utilizarmos o comando kubectl get pods ele vai ter criado um novo, em relação ao anterior, que nesse caso é o portal-noticias-replicaset-mzskh.

Então, utilizando ReplicaSets nós conseguimos definir que a nossa aplicação deve estar sempre disponível para o usuário, o Kubernetes tem que manter ela sempre disponível em caso de falhas ou interrupções.

E também, definir o número de réplicas para o nosso usuário conseguir acessar, caso uma dê problema e ainda não tenha voltado. Ou dividir, fazer todo o balanceamento de carga.

Então, por mais que agora, só para finalizarmos, o nosso Pod esteja dentro de um ReplicaSet, o nosso serviço continua funcionando sem nenhuma mudança porque ele seleciona por qualquer um que tenha a chave app com valor portal-noticias.

E ele continua tendo isso porque nós definimos no labels do arquivo portal-noticias-replicaset.yaml, então, não muda ele estar dentro de um ReplicaSet. Vai tudo funcionar da mesma maneira.

Agora, o nosso serviço, o que ele faz? Para a gente finalizar, vamos voltar na nossa apresentação e ver um trecho que explicita o que está acontecendo agora.

Nós temos, a grosso modo, um serviço balanceando, o nosso acesso a três diferentes Pods, que são iguais. Que, nesse caso, estamos utilizando a nossa aplicação localmente com um nodeport para fazer esse acesso.

O nosso serviço, agora, faz todo esse balanceamento sem nenhum mistério, para três Pods gerenciados por um ReplicaSet.

No próximo vídeo vamos entender o que são os Deployments, no que eles podem nos ajudar e como eles são diferentes de um ReplicaSet. Por esse vídeo é só e eu vejo vocês no próximo vídeo. Até mais!

Conhecendo ReplicaSets e Deployments - Conhecendo Deployments

Nós acabamos de ver sobre os ReplicaSets, que permitem a criação de Pods de maneira automática, em caso de falha, todo esse controle do estado desejado e do estado atual. E nós vamos falar agora sobre o segundo recurso que permite a mesma coisa, que são os Deployments.

Mas, o que muda na prática? Nós vimos que um ReplicaSet nada mais é do que esse conjunto de réplicas que permite a criação, de maneira automática, em caso de falhas de um Pod, dentro de um cluster gerenciado por um ReplicaSet.

Mas, um Deployment nada mais é do que uma camada acima de um ReplicaSet. Então, quando nós definimos um Deployment, nós estamos, automaticamente, definindo um ReplicaSet, sem nenhum mistério.

Mas, o que muda? Quando criamos um Deployment, nós criamos um ReplicaSet, mas, o que vem de novo com isso? O que ganhamos de adicional? Vamos verificar, vamos criar o nosso primeiro Deployment para entendermos.

Para isso, vamos criar um arquivo clicando no ícone de “Novo Arquivo” no canto superior esquerdo da tela e adicionar uma nova pasta na lista, que vai ser o nosso nginx-deployment.yaml e a definição dele vai ser idêntica a de um ReplicaSet. A versão apiVersion também vai ser apps/v1; vamos colocar o nosso kind, que vai ser um Deployment.

No nosso metadata vamos definir um name pra ele, que vamos chamar também de nginx-deployment.

Vamos colocar nossas especificações espec, que nós vimos que vai definir, inicialmente, o número de réplicas. Podemos colocar três, novamente, para exemplificar e vamos colocar as informações do nosso template, que vai ter um metadata, que serão as informações dos nossos Pods.

Vamos colocar um name: nginx-pod e as labels vamos colocar a chave app com um valor, também, de nginx-pod.

Nas especificações spec do nosso Pod vamos colocar as informações dos containers, que teremos um name: nginx-container e uma image que vamos colocar nginx-stable.

Por fim, só que é boa prática vamos colocar o nosso ports: containerPort: 80. E agora só falta o nosso seletor, que vai ter o nosso matchLabels, que tem que ser igual ao nosso labels do nosso metadata, então, app: nginx-pod. Nada de novo, a mesma declaração de um ReplicaSet, só trocamos em cima para Deployment.

apiVersion: apps/v1
kind: Deployment
metadata:
    name: nginx-deployment
spec:
    replicas: 3
    template:
        metadata:
            name: nginx-pod
            labels:
                app: nginx-pod
            spec:
                containers:
                    - name: nginx-container
                    - image: nginx:stable
                    - ports:
                        - containerPort: 80
    selector:
        matchLabels:
            app: nginx-pod

Se viermos na tela do Windows PowerShell e executar o comando kubectl apply –fe .\nginx-deployment.yaml, ele foi criado. Se executarmos o comando kubectl getpods, temos agora três Pods em execução, por causa deste Deployment.

Se dermos um kubectl get rs, temos dois ReplicaSets. O nosso portal-noticias-replicaset e o nosso recém criado nginx-deployment-6bf9fcdcc7, mas, ele tem um ReplicaSet, porque, como vimos, temos uma super camada, um super conjunto, que é o Deployment e dentro de um Deployment nós criamos, automaticamente, um ReplicaSet que vai gerenciar os Pods.

E se formos um pouco mais além, temos o kubectl get deployments e temos o nosso Deployment criado, o nosso nginx-deployment, que tem os três Pods em execução, sem nenhum problema.

O que vai mudar na prática agora? A grande vantagem do uso de Deployments é que, assim como temos um git, por exemplo, para o nosso controle de versionamento de código, nós temos os Deployments em Kubernetes, que permitem o nosso controle de versionamento das nossas imagens e Pods, olha que legal.

O que muda agora? Conseguimos utilizar comandos extras para validar e verificar todo o nosso fluxo. Então, por exemplo, podemos executar o comando kubectl rollout history deployment nginx-deployment e ele nos mostra que temos uma revisão, a que estamos atualmente, um estado atual, e não temos nenhuma causa de mudança, porque ela é nossa primeira, não definimos nada para ela.

Mas, e se eu quiser mudar aquela versão stable para, por exemplo, a versão latest? O que pode acontecer? Eu posso, simplesmente, agora, executar o comando kubectl apply-f nginx-deployment.yaml e eu posso utilizar a flag no final, --record e o que vai acontecer? Ele vai configurar, vai alterar para nós, se eu der um kubectl get pods, repara, recém-criados e cada um deles vai estar utilizando a versão latest.

Mas, se eu executar, de novo, o comando rollout history deployment xginx-deployment, o que vai acontecer? Ele tem, agora, a segunda revisão, a que estamos atualmente. E podemos alterar este CHANGE-CAUSE para ficar mais claro o que fizemos.

Ele está com esse comando kubectl.exe apply –filename=.\nginx-deployment.yaml –record=true, o que ele executou, mas, eu quero deixar mais claro o que foi feito.

Então, para isso, nós temos o comando kubectl annotate deploy ou kubectl annotate deployment, como você preferir, o nome do nosso Deployment que é nginx-deployment e aqui nós colocamos qual vai ser a nossa CHANGE-CAUSE, qual vai ser a nossa mudança?

Então, nós vamos definir através desse kubernetes.io/change-cause=”Definindo a imagem com versão latest, por exemplo, e ele vai anotar para nós.

Se executarmos, novamente, o comando kubectl rollout history deployment xginx-deployment o que vai acontecer é que teremos a nossa primeira revisão, que foi a de criação, e a nossa segunda, que foi Definindo a imagem com versão latest.

E podemos ir além. Se eu quiser alterar mais uma vez, por exemplo, para a versão 1 o que vai acontecer? Vamos usar o comando kubectl apply –f .\nginx.deployment.yaml com nosso arquivo de definição com flag --record e o que vai acontecer?

Temos mais uma causa de mudança, mais uma revisão com o mesmo comando. Ele grava por padrão comando que foi executado para essa alteração.

E podemos, mais uma vez, alterar para ficar mais claro. Repetindo o mesmo comando de antes, do nosso annotate, ele vai alterar para nossa revisão atual, que é a três, que nós estamos, então kubectl annotate deployment nginx-deployment, com nosso CHANGE-CAUSE sendo Definindo a imagem com versão 1.

Vou dar um "CRTL + L" para limpar a nossa tela e se dermos agora um kubectl get pods temos tudo em execução, sem nenhum mistério e se dermos um kubectl rollout history mais uma vez, temos aqui todo nosso controle de versionamento. Tudo sendo feito, exatamente, da maneira que esperávamos.

Pra validarmos se tudo está da maneira que esperamos, vamos ao comando kubectl describe pod e eu vou descrever qualquer um dos nossos Pods do nginx-deployment, vou colar ele xginx-deployment-5c6d6c6479-9qfnd e podemos ver que nas nossas configurações de imagens, o que está acontecendo: ele está utilizando a versão 1, que foi o que definimos.

Mas, e se eu quiser voltar para alguma versão específica, fazer um lowback, alguma alteração no que já tenho, invés de eu ter que alterar manualmente no meu arquivo de definição, por exemplo.

O que eu consigo fazer aqui é, simplesmente, mais uma vez executando o comando de history, digamos que eu queira voltar para versão latest, eu consigo executar o comando kubectl rollout undo deployment e passando ou não do nosso Deployment que é nginx-deployment, eu consigo voltar para alguma revisão específica.

Então --to-revision=2 eu consigo voltar para versão dois e ele vai fazer tudo isso, magicamente, se eu usar o comando kubectl get pods todos estão sendo criados e estão encerrando os anteriores e criando os novos, como, por exemplo, esse nginx-deployment-6c88c4c95c-b7k8g e se eu usar o comando kubectl describe pod, colo este Pod utilizando a versão latest.

Então, quando utilizamos nossos Deployments, o que conseguimos fazer? Conseguimos, simplesmente, ter uma camada extra acima de um ReplicaSet, que consegue gerenciar as imagens, todo o versionamento do que estamos definindo, controle de atualização em cima das nossas imagens e Pods. Que legal, não é verdade?

Então, no fim das contas, a boa prática, o mais comum que vocês irão ver quando vocês forem criar Pods é criar eles através de Deployments, que eles já vão permitir todo esse controle de versionamento e também os benefícios de um ReplicaSet.

Nada impede de criarmos manualmente, como viemos fazendo com Pods e ReplicaSets, mas, o mais comum, a boa prática, é fazer a criação através de Deployments, por conta desses benefícios de controle de versionamento e de estabilidade, disponibilidade da nossa aplicação.

Então, com esse vídeo conhecemos o que é um Deployment e no próximo iremos aplicar esses conceitos de Deployment ao nosso projeto de notícias. Vejo vocês no próximo vídeo e até lá!

Sobre o curso Kubernetes: Deployments, Volumes e Escalabilidade

O curso Kubernetes: Deployments, Volumes e Escalabilidade possui 168 minutos de vídeos, em um total de 53 atividades. Gostou? Conheça nossos outros cursos de Containers em DevOps, ou leia nossos artigos de DevOps.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Containers acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas