Recentemente executei um projeto que me ajudou a revisitar conceitos importantes de CI/CD, containerização e infraestrutura como código.
Nesse post, vou compartilhar como foi a experiência, as tecnologias envolvidas, dificuldades encontradas e os aprendizados que levei comigo. Esse post é muito mais sobre o  que aprendi do que ferramentas para utilizar, exercitando então a capacidade de projetar, desenhar e integrar ferramentas e soluções modernas e entender como e quando o momento de utiliza-los.
O Projeto
A ideia era simples: criar uma API em Python com Flask que retorna frases motivacionais aleatórias, conteinerizá-la com Docker e configurá-la para ser implantada automaticamente usando GitHub Actions e Terraform em um provedor de nuvem.
O resultado final foi um pipeline que:
- Constrói a imagem Docker da aplicação.
 - Faz o deploy automaticamente em um provedor de nuvem.
 - Provisiona a infraestrutura via Terraform.
 
Tudo isso sendo disparado sempre que um commit é feito na branch main.
Tecnologias Utilizadas
- Python + Flask – para criar a API.
 - Docker – para empacotar a aplicação e garantir portabilidade.
 - GitHub Actions – para criar o pipeline CI/CD.
 - Terraform – para gerenciar a infraestrutura como código.
 - Cloud – como provedor de hospedagem e deploy.
 
Estrutura Básica da API
O código da aplicação ficou simples, nesse exemplo abaixo suficiente para demonstrar a estrutura:
# app/advice.py
from flask import Flask, jsonify
import random
app = Flask(__name__)
frases = [
    "Acredite em você!",
    "Você é capaz de mais do que imagina.",
    "Persistência leva ao sucesso.",
    "Cada erro é uma oportunidade de aprendizado."
]
@app.route("/")
def home():
    return jsonify({"message": "Bem-vindo à API de Frases Motivacionais!"})
@app.route("/frase")
def frase():
    return jsonify({"frase": random.choice(frases)})
@app.errorhandler(404)
def not_found(error):
    return jsonify({"error": "Rota não encontrada"}), 404
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=80)
Dockerfile para Containerização
A imagem foi construída a partir de uma base Python e exposta na porta 80:
FROM python:3.10-slim
WORKDIR /app
COPY app/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app/ .
EXPOSE 80
CMD ["python", "advice.py"]
Para testar localmente:
docker build -t api-advice .
docker run -p 80:80 api-advice
Workflow do GitHub Actions
O workflow foi configurado para rodar na branch main e fluxos separados para executar build, teste e deploy:
name: CI Pipeline
on:
  pull_request:
    branches: [main]
  push:
    branches: [main]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Build da imagem Docker
        run: docker build -t test-image:latest .
      - name: Rodar testes dentro do container
        run: |
          docker run --rm -d -p 80:80 --name test-container test-image:latest
          sleep 5
          curl -f http://localhost/ || exit 1
          curl -f http://localhost/frase || exit 1
          curl -s -o /dev/null -w "%{http_code}" http://localhost/inexistente | grep -q "404" && echo "404 OK" || exit 1
          docker stop test-container
      - name: Testes passaram ✅
        run: echo "Todos os testes passaram com sucesso!"
Action para infra
name: Provisionar Infraestrutura Render
on:
  push:
    branches: [infra]
jobs:
  terraform:
    runs-on: ubuntu-latest
    environment: render
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: 1.12.2
      - name: Terraform Init
        working-directory: infra
        run: terraform init
      - name: Terraform Plan
        working-directory: infra
        env:
          TF_VAR_cloud_api_key: ${{ secrets.SECRET_API_KEY }}
          TF_VAR_cloud_owner_id: ${{ secrets.SECRET_OWNER_ID }}
        run: terraform plan -out=tfplan
      - name: Terraform Apply
        working-directory: infra
        env:
          TF_VAR_cloud_api_key: ${{ secrets.SECRET_API_KEY }}
          TF_VAR_cloud_owner_id: ${{ secrets.SECRET_OWNER_ID }}
        run: terraform apply -auto-approve
Código Terraform para o Cloud
No diretório infra/, configurei os recursos para o respectivo provedor:
terraform {
  required_providers {
    Cloud = {
      source  = "Seu-Provedor-Cloud-os/Cloud"
      version = "~> 0.2"
    }
  }
}
provider "Cloud" {
  api_key = var.Cloud_api_key
}
resource "Cloud_service" "api" {
  name    = "api-advice"
  type    = "web_service"
  plan    = "starter"
  env     = "docker"
  branch  = "main"
  repo    = "https://github.com/seu-usuario/seu-repo"
}
Principais Aprendizados
1. Containerização com Docker
Revisitei a criação de uma imagem Docker para uma aplicação Flask, expondo a porta 80 e configurando corretamente o CMD para inicializar o servidor.
Também testei chamadas à API com curl para validar o funcionamento dentro do container.
2. Automação com GitHub Actions
Configurei um workflow que:
- Faz build da imagem Docker.
 - Publica a aplicação automaticamente em um provedor de nuvem.
 - Provisiona infraestrutura com Terraform.
 
3. Infraestrutura como Código com Terraform
Reforcei conceitos de organização de arquivos (main.tf, variables.tf, outputs.tf, terraform.tfvars) e boas práticas no uso de variáveis e outputs.
4. Estrutura de Projeto
Manter a separação entre código da aplicação e código de infraestrutura facilitou bastante a manutenção.
Dificuldades Encontradas
- Revisão do Terraform: fazia algum tempo que não trabalhava com Terraform, então precisei revisar a documentação oficial para relembrar a sintaxe correta de módulos e garantir compatibilidade com as versões atuais.
 - 
Aprendendo sobre o provedor: como não conhecia o provedor definido para esse projeto, levei um tempo extra para entender como ele realiza implantações automáticas a partir de commits na branch 
main. 
Ferramentas de Apoio
Durante o desenvolvimento, utilizei algumas ferramentas de IA que ajudaram a acelerar a curva de aprendizado:
- ChatGPT (OpenAI): para esclarecer dúvidas e sugerir soluções.
 - GitHub Copilot: para agilizar a escrita de código e arquivos de configuração.
 - Claude Sonnet 3.7 (Anthropic): para revisar e sugerir melhorias na organização do projeto.
 
Conclusão
Esse projeto foi mais do que criar uma API simples — foi um exercício prático de integração entre desenvolvimento, automação e infraestrutura.
Revisitei conceitos importantes e aprendi novos fluxos de trabalho com ferramentas modernas como o Render.
Se você está começando com CI/CD, recomendo fortemente criar um projeto do zero, integrando Docker, Terraform e um pipeline de deploy automatizado.
A experiência prática é insubstituível.
Separação dos Pipelines
Foram criados dois workflows separados:
- 
Pipeline CI (
ci.yml): responsável por buildar a imagem Docker e rodar testes automatizados simples (incluindo verificação de rotas e status HTTP). O deploy no Render é acionado automaticamente via integração do próprio Render com o GitHub assim que há um push na branchmain. - 
Pipeline de Infraestrutura (
infra.yml): dedicado ao provisionamento da infraestrutura via Terraform, disparado por pushes na branchinfra. 
Essa separação garante maior organização, facilita troubleshooting e permite evoluir cada parte do processo de forma independente.
Observação: O pipeline de infraestrutura foi configurado para provisionar recursos em um provedor de cloud. No projeto original, foi utilizado o Render, mas o fluxo pode ser adaptado para outros provedores conforme necessidade.
              
    
Top comments (0)