CI/CD para Flask: automatize o Deploy da sua API com Docker e GitHub Actions

Rocketseat

Rocketseat

5 min de leitura
devops
Já cansou de fazer deploy manual toda vez que atualiza seu código? Aquela sensação de "será que esqueci alguma coisa?" ou "por que funciona na minha máquina e não no servidor?" é familiar?
Bora acabar com isso agora!
Você vai aprender a criar um pipeline de CI/CD completo que automatiza todo o processo de build e deploy da sua API Python Flask usando Docker e GitHub Actions. No final, cada git push que você fizer vai desencadear um processo automático que empacota e disponibiliza sua aplicação.
O melhor de tudo? Você não precisa ser especialista em DevOps para fazer isso acontecer.

O que você vai construir

Um pipeline automatizado que:
  • Detecta mudanças no seu código automaticamente
  • Cria uma imagem Docker otimizada da sua aplicação
  • Faz o push dessa imagem para um registro (Docker Hub)
  • Deixa tudo pronto para o deploy em qualquer ambiente

O que você precisa saber antes

  • Familiaridade com Docker (saber criar um container básico)
  • Uma conta no Docker Hub (para armazenar suas imagens)
  • Vontade de automatizar suas entregas
Bora começar? 🚀

Entendendo CI/CD

CI/CD é um conjunto de práticas que mudam o jogo no desenvolvimento de software. Mas o que significa na prática?

CI: Continuous Integration (integração contínua)

Imagine que você e outras pessoas estão trabalhando no mesmo projeto. Cada um faz suas alterações e envia para o repositório principal (no GitHub, por exemplo).
A integração contínua é o processo de juntar essas alterações automaticamente e frequentemente. A cada novo commit, o sistema verifica se o novo código funciona bem com o código existente. Isso geralmente envolve rodar testes automatizados.
Benefício: você descobre bugs e conflitos muito mais cedo, antes que eles virem uma bola de neve.

CD: Continuous Delivery ou Continuous Deployment (entrega ou deploy contínuo)

Depois que o código passa pela integração (CI), entra o CD.
  • Continuous Delivery (entrega contínua): significa que seu código está testado, empacotado e pronto para ir para produção a qualquer momento. O deploy final ainda pode ser manual, mas o pacote está pronto.
  • Continuous Deployment (deploy contínuo): leva isso um passo adiante. Se o código passar por todos os testes, ele é automaticamente enviado para produção, sem intervenção humana.
Neste material, vamos focar em preparar o terreno para o CD, automatizando o build e o empacotamento da nossa aplicação Flask em uma imagem Docker.
Benefício: você entrega valor mais rápido, com menos erros manuais e muito mais confiança no seu processo.

Preparando a API Flask

Vamos começar criando uma API Flask super simples. O foco aqui não é o Python, mas sim o processo de automação.
👉
Se você está começando com Python ou quer reforçar os conceitos de Flask, você pode criar sua própria API seguindo o curso gratuito da Rocketseat: Introdução ao Python e Flask.

Estrutura do projeto

Crie uma pasta para o projeto. Sua estrutura inicial ficará assim:
flask-cicd-pipeline/ ├── app.py └── requirements.txt

O código da API

Crie o arquivo app.py e adicione o seguinte código. É uma API com uma única rota para teste.
from flask import Flask, jsonify app = Flask(__name__) @app.route('/') def index(): return jsonify({"message": "Deploy automatizado funcionando! 🚀", "status": "success"}) # O bloco abaixo só é usado local. if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=True)

Dependências

Para rodar nossa aplicação em um ambiente de produção (como um container Docker), é recomendado usar um servidor web mais robusto que o servidor de desenvolvimento do Flask. Usaremos o gunicorn.
Crie o arquivo requirements.txt e adicione:
Flask>=3.0.0 gunicorn
Você pode testar localmente instalando as dependências (preferencialmente em um ambiente virtual) e rodando python app.py.

Criando o Dockerfile

Agora vamos "containerizar" nossa aplicação. O Dockerfile é a receita que diz ao Docker como construir a imagem da nossa API Flask.
Crie um arquivo chamado Dockerfile (sem extensão) na raiz do projeto.
Vamos construir o Dockerfile passo a passo, focando em otimização de camadas:
# 1. Imagem base: Começamos com uma imagem Python oficial e leve. # 'slim' significa que ela tem apenas o necessário para rodar Python. FROM python:3.11-slim # 2. Diretório de trabalho: Define onde o código vai ficar dentro do container. WORKDIR /app # 3. Instalação de dependências: # Copiamos apenas o requirements.txt primeiro. Isso otimiza o cache do Docker. # Se o código mudar, mas os requisitos não, essa etapa não precisa ser refeita. COPY requirements.txt . # Rodamos o pip para instalar as dependências. # '--no-cache-dir' ajuda a manter a imagem final menor. RUN pip install --no-cache-dir -r requirements.txt # 4. Código da aplicação: Copiamos o restante dos arquivos do nosso projeto. COPY . . # 5. Exposição de porta: Informamos ao Docker que nossa aplicação vai usar a porta 5000. EXPOSE 5000 # 6. Comando de inicialização: O que o container deve fazer quando iniciar. # Usamos gunicorn para servir nossa aplicação Flask. # '--bind 0.0.0.0:5000' faz a aplicação escutar em todas as interfaces na porta 5000. # 'app:app' diz ao gunicorn para procurar o objeto 'app' dentro do módulo 'app.py'. CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]

Como testar o container localmente

Antes de automatizar, é sempre bom garantir que o Dockerfile funciona na sua máquina.
  1. Build da imagem: No terminal, dentro da pasta do projeto, rode o comando para construir a imagem. Vamos chamá-la de flask-api-cicd.
docker build -t flask-api-cicd .
Rodar o container:
Agora, vamos iniciar um container a partir dessa imagem. Mapeamos a porta 5000 do host para a porta 5000 do container.
docker run -p 5000:5000 flask-api-cicd
Abra seu navegador em http://localhost:5000. Você deve ver a mensagem da API. Sucesso!

Configurando o GitHub Actions

Chegou a hora da mágica acontecer. O GitHub Actions é a ferramenta de CI/CD integrada ao GitHub que nos permite automatizar fluxos de trabalho (workflows).

Componentes principais

  • Workflow: o processo automatizado completo que você define.
  • Trigger (gatilho): o evento que inicia o workflow (ex: um push na branch main).
  • Job: um conjunto de passos que rodam em um ambiente.
  • Step (passo): uma tarefa individual dentro de um job (ex: rodar um comando).

Criando o arquivo de workflow

Os workflows ficam em uma pasta específica no seu repositório. Crie a estrutura de diretórios .github/workflows/ na raiz do seu projeto, e dentro dela, crie o arquivo deploy.yml.
flask-cicd-pipeline/ ├── .github/ │ └── workflows/ │ └── deploy.yml ├── app.py ├── Dockerfile └── requirements.txt

Configuração do workflow

Vamos criar um workflow que faz o build da imagem Docker e envia para o Docker Hub toda vez que houver um push na branch main.
Abra o deploy.yml e adicione o seguinte conteúdo:
name: CI/CD Pipeline - Build and Push Docker Image # Triggers: Define quando o workflow será executado on: push: branches: [ "main" ] # Apenas na branch main pull_request: branches: [ "main" ] # Também roda quando um PR for aberto contra a main # Jobs: Os trabalhos que serão executados jobs: build-and-push: # Define o ambiente onde o job vai rodar (uma máquina virtual Ubuntu) runs-on: ubuntu-latest # Steps: Os passos do job steps: # Passo 1: Checkout do código # Usa uma action pronta para baixar o código do repositório para a máquina virtual - name: Checkout code uses: actions/checkout@v4 # Passo 2: Login no Docker Hub # Precisamos fazer login para poder enviar a imagem para o registro - name: Login to Docker Hub # Só executa este passo se for um push na main (não em PRs) if: github.event_name == 'push' uses: docker/login-action@v3 with: # Usamos secrets do GitHub para armazenar credenciais de forma segura username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} # Passo 3: Configurar o Docker Buildx # Buildx é uma ferramenta avançada do Docker para builds mais eficientes - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 # Passo 4: Build e Push da imagem # A action principal que faz o trabalho pesado - name: Build and push Docker image uses: docker/build-push-action@v5 with: context: . # Onde está o Dockerfile (na raiz) # Só faz o push se for um push na main. Em PRs, apenas faz o build (para verificar se funciona) push: ${{ github.event_name == 'push' }} # Define o nome e a tag da imagem. Ex: seuusuario/flask-api-cicd:latest tags: ${{ secrets.DOCKERHUB_USERNAME }}/flask-api-cicd:latest

Explicação do workflow

  • Adicionamos pull_request nos triggers. Isso é uma boa prática de CI: verificar se o código do PR consegue ser integrado antes do merge.
  • Usamos if: github.event_name == 'push' para garantir que o login e o push para o Docker Hub só aconteçam quando o código for efetivamente enviado para a main, não durante a verificação de um PR.

Secrets e variáveis de ambiente

Você percebeu que usamos ${{ secrets.DOCKERHUB_USERNAME }} e ${{ secrets.DOCKERHUB_TOKEN }}? Não podemos colocar nossas credenciais direto no código. O GitHub Secrets é um cofre seguro para guardar essas informações.
  1. Crie um token no Docker Hub:
      • Vá em Docker Hub > Account Settings > Security.
      • Clique em "New Access Token".
      • Dê um nome (ex: "github actions token") e gere o token.
      • Importante: Copie ele agora! Você só verá ele uma vez.
  1. Configure no GitHub:
      • No seu repositório no GitHub (você precisará subir o código que criamos até agora), vá em Settings > Secrets and variables > Actions.
      • Clique em "New repository secret".
      • Crie DOCKERHUB_USERNAME com seu nome de usuário do Docker Hub.
      • Crie DOCKERHUB_TOKEN com o token que você copiou do Docker Hub.

Testando o pipeline

Tudo configurado! Agora vamos ver a automação funcionando na prática.

Como fazer um commit que vai acionar o workflow

  1. Certifique-se de que seu projeto está no GitHub.
  1. Faça uma pequena alteração (opcional). Se quiser testar a atualização, mude a mensagem no app.py:
    1. return jsonify({"message": "Pipeline CI/CD atualizado! 💜", "status": "success"})
  1. Commit e Push: Certifique-se de que todos os arquivos (incluindo o diretório .github/workflows) foram adicionados e faça o push para a branch main.
    1. git add . git commit -m "feat: configura pipeline CI/CD" git push origin main

Onde visualizar os logs no GitHub Actions

Assim que você fizer o push, o GitHub Actions vai detectar a mudança e iniciar o workflow.
  1. Vá para a aba "Actions" no seu repositório do GitHub.
  1. Você verá seu workflow listado, provavelmente com um ícone amarelo indicando que está em execução.
  1. Clique nele para ver os detalhes e acompanhar os logs de cada step em tempo real.

Como interpretar sucessos e falhas

  • Sucesso (Verde ✅): Parabéns! Sua imagem Docker foi construída e enviada para o Docker Hub.
  • Falha (Vermelho ❌): Não se preocupe. Clique no passo que falhou para ler os logs. O GitHub Actions fornece logs detalhados que geralmente apontam a causa do problema.

Debug de problemas comuns

  • Falha no login do Docker Hub: verifique se as secrets (DOCKERHUB_USERNAME e DOCKERHUB_TOKEN) estão corretas no GitHub. Lembre-se que o token não é sua senha normal.
  • Falha no build: pode haver um erro no seu Dockerfile ou no código da aplicação. Leia os logs do step "Build and push Docker image". Teste o build localmente primeiro.
  • Workflow não inicia: verifique se o arquivo está em .github/workflows/deploy.yml e se o trigger está configurado para a branch correta (main).

Próximos passos e melhorias

Você construiu um pipeline de CI/CD funcional, mas isso é só o começo da sua jornada em DevOps. Existem várias melhorias que você pode implementar:

Adicionar testes automatizados

Este é talvez o passo mais importante para um CI robusto. Antes de fazer o build da imagem, você deve rodar seus testes (com pytest, por exemplo). Se os testes falharem, o pipeline deve parar.

Implementar diferentes ambientes

Você pode configurar workflows diferentes para branches diferentes. Por exemplo, a branch develop faz deploy em um ambiente de staging (teste), e a branch main faz deploy em produção.

Deploy (CD real)

Nosso pipeline atual faz o build e o push da imagem. O próximo passo seria adicionar um step final para fazer o deploy dessa imagem em um servidor, um cluster Kubernetes ou um serviço de nuvem (como AWS ECS, Azure Container Apps ou Google Cloud Run).

Adicionar notificações e rollback

Você pode configurar o pipeline para te notificar sobre falhas e implementar mecanismos de rollback automático caso a nova versão apresente problemas em produção.

Conclusão

Automatizar o deploy não precisa ser complicado. Com ferramentas como Docker e GitHub Actions, você pode criar pipelines robustos que economizam tempo, reduzem erros e aumentam a confiança no seu código. Você deu um passo super importante hoje.

De Automatizador a Arquiteto de Infraestrutura Cloud

O pipeline que você construiu hoje é a porta de entrada para o mundo DevOps. Ele resolve o deploy. Mas a verdadeira maestria está em orquestrar todo o ecossistema que vem antes e depois.
Na Formação DevOps da Rocketseat, você vai transformar seu conhecimento em domínio:
  • Orquestre centenas de containers como o que você acabou de criar usando Kubernetes, a ferramenta padrão da indústria para escalar aplicações.
  • Defina toda a sua infraestrutura como código com Terraform, para criar e destruir ambientes completos na AWS, Azure ou GCP com um único comando.
  • Monitore suas aplicações com Prometheus e Grafana, para antecipar problemas antes que eles afetem seus usuários.
Este é o caminho para se tornar o profissional que não apenas aperta o botão de deploy, mas que projeta, constrói e mantém a infraestrutura resiliente que sustenta as maiores empresas de tecnologia.
Artigos_

Explore conteúdos relacionados

Descubra mais artigos que complementam seu aprendizado e expandem seu conhecimento.