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)