Em DevOps, a gestão de ambientes é fundamental para garantir que o software se comporte de forma consistente desde o desenvolvimento até a produção. Ambientes separados — desenvolvimento (dev), homologação (staging) e produção (prod) — permitem testar em diferentes estágios, mas também introduzem desafios de consistência e configuração. Nesta aula, você aprenderá a lidar com esses desafios, desde a paridade entre ambientes até a promoção de código e configuração específica por ambiente.

Vamos explorar como a falta de paridade pode causar bugs que só aparecem em produção, como a promoção automatizada reduz riscos e como gerenciar configurações sensíveis sem comprometer a segurança. Ao final, você terá um guia prático para implementar esses conceitos no seu fluxo de trabalho.

Paridade entre ambientes

A paridade entre ambientes significa que dev, staging e prod devem ser o mais semelhantes possível em termos de infraestrutura, bibliotecas, versões de sistema operacional e configurações. Quando há diferenças, o comportamento do software pode variar, levando a bugs que só se manifestam em produção. Por exemplo, um código que funciona em dev com uma versão mais nova de uma biblioteca pode falhar em prod com uma versão antiga.

Para alcançar a paridade, é essencial usar ferramentas de infraestrutura como código (IaC), como Terraform ou CloudFormation, que permitem provisionar ambientes idênticos. Além disso, contêineres (Docker) e orquestradores (Kubernetes) ajudam a empacotar a aplicação com todas as suas dependências, garantindo que o mesmo artefato seja executado em todos os lugares. A paridade também inclui dados: usar dados de teste realistas em staging pode revelar problemas de performance e integração que não aparecem com dados sintéticos.

Um exemplo prático: se você usa um banco de dados PostgreSQL, a versão deve ser a mesma em todos os ambientes. Caso contrário, uma query que funciona em dev com PostgreSQL 15 pode falhar em prod com PostgreSQL 12 devido a diferenças de sintaxe ou otimização. Portanto, versione a infraestrutura e mantenha-a consistente.

# Exemplo de docker-compose para garantir paridade de versão do PostgreSQL
services:
  db:
    image: postgres:15.3
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: appdb

Promoção

Promoção é o processo de mover código de um ambiente para outro, geralmente de dev para staging e de staging para produção. A promoção deve ser automatizada e baseada em artefatos versionados, não em recompilação. Isso significa que o mesmo pacote (por exemplo, uma imagem Docker ou um JAR) que foi testado em staging é promovido para produção, sem alterações.

Automatizar a promoção reduz erros humanos e garante que o que foi testado é exatamente o que será implantado. Ferramentas como Jenkins, GitLab CI/CD ou GitHub Actions podem ser configuradas para disparar a promoção após a aprovação em um ambiente. Por exemplo, após os testes em staging passarem, um job pode promover a imagem para o registro de produção e atualizar o deployment no cluster.

Uma prática comum é usar tags ou versionamento semântico nos artefatos. Por exemplo, uma imagem Docker pode ter a tag v1.2.3 e ser promovida de staging para prod usando essa mesma tag. Isso permite rastrear qual versão está em cada ambiente.

# Exemplo de promoção com Docker e Git tag
# No pipeline de CI/CD, após testes em staging:
docker tag minha-app:staging minha-app:v1.2.3
docker push registry.example.com/minha-app:v1.2.3
# Em produção, deploy usando a mesma imagem:
kubectl set image deployment/app app=registry.example.com/minha-app:v1.2.3 --record

Configuração por ambiente

Embora a paridade seja desejável, algumas configurações precisam variar entre ambientes, como URLs de serviços, credenciais de banco de dados e chaves de API. A configuração por ambiente deve ser externalizada, ou seja, não embutida no código, para permitir essa variação sem recompilação.

Ferramentas como variáveis de ambiente, arquivos de configuração (por exemplo, .env) ou sistemas de gerenciamento de segredos (como Vault) são usadas para fornecer configurações específicas. Em contêineres, é comum passar variáveis de ambiente no momento da execução. Em Kubernetes, ConfigMaps e Secrets são recursos dedicados para isso.

É importante que a configuração seja versionada e auditada. Por exemplo, você pode ter um arquivo config/dev.yaml, config/staging.yaml e config/prod.yaml, mas nunca versionar segredos reais. Em vez disso, use referências a segredos gerenciados externamente.

# Exemplo de uso de variáveis de ambiente em um deploy
# Em dev:
export DATABASE_URL="postgres://user:pass@localhost:5432/devdb"
export API_KEY="dev-key"

# Em staging:
export DATABASE_URL="postgres://user:pass@staging-db:5432/appdb"
export API_KEY="staging-key"

# Em produção:
export DATABASE_URL="postgres://user:pass@prod-db:5432/appdb"
export API_KEY="$(cat /etc/secrets/api_key)"

Boas práticas

Algumas boas práticas ajudam a manter ambientes saudáveis e o fluxo de entrega eficiente. Primeiro, mantenha o ambiente de staging o mais próximo possível de produção, incluindo dados e tráfego simulados. Isso aumenta a confiança de que o código funcionará em produção. Segundo, automatize tudo: desde o provisionamento até a promoção, para reduzir erros manuais.

Terceiro, use estratégias de deploy como blue-green ou canary para minimizar o impacto de falhas em produção. Quarto, monitore e registre logs de todos os ambientes para facilitar o diagnóstico. Por fim, documente o processo de promoção e as diferenças de configuração, para que novos membros do time entendam o fluxo.

Outra prática importante é realizar testes de rollback: saiba como reverter uma versão problemática rapidamente. Manter ambientes efêmeros (criados e destruídos sob demanda) também é uma tendência, especialmente com o uso de pull requests que geram ambientes de revisão.

# Exemplo de script para criar um ambiente efêmero de review
# Em um CI/CD, ao abrir um PR:
terraform apply -var="env=pr-$PR_NUMBER" -auto-approve
# Após merge, destruir:
terraform destroy -var="env=pr-$PR_NUMBER" -auto-approve

Referências

Exercícios

  1. Exercício 1: Explique por que a paridade entre ambientes é importante e cite duas práticas para alcançá-la.

    ✓ Resposta: A paridade é importante porque reduz a probabilidade de bugs que só aparecem em produção, garantindo que o comportamento do software seja consistente. Duas práticas: usar infraestrutura como código (IaC) para provisionar ambientes idênticos e usar contêineres para empacotar a aplicação com todas as dependências.
  2. Exercício 2: Descreva o processo de promoção de código usando um pipeline de CI/CD e um artefato versionado. Dê um exemplo de comando de promoção.

    ✓ Resposta: O processo envolve compilar o código uma vez, gerar um artefato (ex.: imagem Docker) e testá-lo em staging. Após aprovação, o mesmo artefato é promovido para produção. Exemplo: docker tag app:staging app:v1.2.3 && docker push registry/app:v1.2.3 e depois kubectl set image deployment/app app=registry/app:v1.2.3.
  3. Exercício 3: Como você externalizaria a configuração de uma aplicação que usa um banco de dados e uma API externa? Dê um exemplo de variáveis de ambiente para dev e prod.

    ✓ Resposta: Usaria variáveis de ambiente ou arquivos de configuração. Exemplo: DATABASE_URL e API_KEY. Em dev: DATABASE_URL=postgres://user:pass@localhost/devdb e API_KEY=dev-key. Em prod: DATABASE_URL=postgres://user:pass@prod-db/appdb e API_KEY=prod-key (proveniente de um secret manager).
  4. Exercício 4: Cite três boas práticas para gerenciar ambientes e explique brevemente cada uma.

    ✓ Resposta: 1) Automatizar provisionamento e deploy para reduzir erros; 2) Usar estratégias de deploy como blue-green para minimizar impacto de falhas; 3) Manter staging idêntico a produção, incluindo dados e tráfego, para maior confiabilidade.
  5. Exercício 5: Escreva um comando bash para criar um ambiente efêmero de review usando Terraform, dado que o código está em um pull request.

    ✓ Resposta:
    terraform apply -var="env=pr-$PR_NUMBER" -auto-approve

Boas práticas e observações finais

Gerenciar ambientes é um equilíbrio entre consistência e flexibilidade. Sempre busque a maior paridade possível, mas reconheça que algumas configurações precisam variar. Automatize a promoção e use ferramentas de IaC para garantir reprodutibilidade. Lembre-se de que a segurança é crucial: nunca exponha segredos em código ou em logs. Por fim, monitore seus ambientes e esteja preparado para reverter rapidamente se algo der errado.