Container orchestration scripts: docker-compose em Bash
1. Introdução à Automação de Docker-Compose com Bash
Automatizar o gerenciamento de ambientes Docker Compose com scripts Bash é uma prática essencial para equipes que buscam eficiência e reprodutibilidade. O Bash oferece simplicidade, portabilidade e controle fino sobre o ciclo de vida dos containers, sendo ideal para cenários como ambientes de desenvolvimento, pipelines de CI/CD e deploys rápidos em servidores.
Os pré-requisitos para acompanhar este artigo incluem Docker e Docker Compose instalados, além de conhecimento básico de Bash (variáveis, funções, condicionais). Vamos explorar scripts práticos que resolvem problemas reais de orquestração.
2. Scripts para Inicialização e Parada Controlada
A função start_services() verifica a existência do arquivo docker-compose.yml e carrega variáveis de ambiente antes de iniciar os serviços:
#!/bin/bash
start_services() {
local compose_file="${1:-docker-compose.yml}"
local env_file="${2:-.env}"
if [[ ! -f "$compose_file" ]]; then
echo "Erro: $compose_file não encontrado."
exit 1
fi
if [[ -f "$env_file" ]]; then
set -a
source "$env_file"
set +a
fi
echo "Iniciando serviços com $compose_file..."
docker-compose -f "$compose_file" up -d
if [[ $? -eq 0 ]]; then
echo "Serviços iniciados com sucesso."
else
echo "Falha ao iniciar serviços."
exit 1
fi
}
Para parada controlada, a função stop_services() inclui timeout e logs:
stop_services() {
local compose_file="${1:-docker-compose.yml}"
local timeout="${2:-30}"
echo "Parando serviços (timeout: ${timeout}s)..."
docker-compose -f "$compose_file" stop -t "$timeout"
if docker-compose -f "$compose_file" ps -q | grep -q .; then
echo "Containers ainda em execução. Forçando parada..."
docker-compose -f "$compose_file" down
else
echo "Todos os serviços parados com sucesso."
fi
}
O tratamento de erros inclui verificação de containers em execução antes de iniciar novos:
if docker-compose -f "$compose_file" ps -q 2>/dev/null | grep -q .; then
echo "Aviso: Containers já em execução. Execute stop primeiro."
exit 1
fi
3. Gerenciamento de Múltiplos Ambientes (dev, staging, prod)
Para alternar entre ambientes, usamos seleção dinâmica de arquivos de compose:
select_environment() {
local env="${1:-dev}"
local base_file="docker-compose.yml"
local override_file="docker-compose.${env}.yml"
if [[ ! -f "$override_file" ]]; then
echo "Erro: Arquivo $override_file não encontrado."
exit 1
fi
export COMPOSE_FILE="${base_file}:${override_file}"
echo "Ambiente $env configurado. Arquivos: $COMPOSE_FILE"
# Validação da configuração
docker-compose config -q
if [[ $? -eq 0 ]]; then
echo "Configuração válida."
else
echo "Configuração inválida. Corrija os erros."
exit 1
fi
}
Exemplo de uso com variáveis de ambiente:
# Uso: ./manage.sh dev up
case "${1:-dev}" in
dev|staging|prod)
select_environment "$1"
shift
docker-compose "$@"
;;
*)
echo "Ambiente inválido. Use: dev, staging ou prod."
exit 1
;;
esac
4. Atualização e Rollback de Serviços
A função update_service() realiza pull de imagens, recreate e health check:
update_service() {
local service="$1"
local compose_file="${2:-docker-compose.yml}"
echo "Atualizando serviço $service..."
docker-compose -f "$compose_file" pull "$service"
if [[ $? -ne 0 ]]; then
echo "Falha ao baixar imagem. Abortando."
return 1
fi
docker-compose -f "$compose_file" up -d --no-deps "$service"
# Health check com timeout
local timeout=60
local elapsed=0
while [[ $elapsed -lt $timeout ]]; do
if docker-compose -f "$compose_file" ps "$service" | grep -q "Up"; then
echo "Serviço $service atualizado e saudável."
return 0
fi
sleep 5
elapsed=$((elapsed + 5))
done
echo "Timeout: serviço $service não ficou saudável."
return 1
}
Para rollback, salvamos logs antes da restauração:
rollback_to_version() {
local service="$1"
local version="$2"
local compose_file="${3:-docker-compose.yml}"
# Salva logs atuais
docker-compose -f "$compose_file" logs --tail=50 "$service" > "rollback_${service}_$(date +%Y%m%d_%H%M%S).log"
# Altera a tag no arquivo compose (exemplo simples)
sed -i "s|image: ${service}:.*|image: ${service}:${version}|" "$compose_file"
docker-compose -f "$compose_file" up -d --no-deps "$service"
echo "Rollback do serviço $service para versão $version concluído."
}
5. Logs e Diagnóstico Automatizado
Coleta centralizada de logs com filtragem por serviço:
collect_logs() {
local service="$1"
local lines="${2:-100}"
local output_file="logs_${service}_$(date +%Y%m%d_%H%M%S).log"
docker-compose logs --tail="$lines" "$service" > "$output_file"
echo "Logs salvos em $output_file"
}
Geração de relatório de saúde dos serviços:
health_report() {
echo "=== Relatório de Saúde dos Serviços ==="
echo "Data: $(date)"
echo ""
docker-compose ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}"
echo ""
echo "Uso de recursos (últimos 30 segundos):"
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}"
}
6. Backup e Restauração de Volumes
Função para backup de volumes nomeados:
backup_volumes() {
local backup_dir="${1:-./backups}"
local timestamp=$(date +%Y%m%d_%H%M%S)
mkdir -p "$backup_dir"
docker volume ls --format "{{.Name}}" | while read volume; do
echo "Backup do volume: $volume"
docker run --rm -v "$volume:/source" -v "$backup_dir:/backup" alpine \
tar czf "/backup/${volume}_${timestamp}.tar.gz" -C /source .
done
echo "Backups concluídos em $backup_dir"
}
Restauração com validação de integridade:
restore_volumes() {
local backup_file="$1"
local volume_name="$2"
if [[ ! -f "$backup_file" ]]; then
echo "Erro: Arquivo de backup não encontrado."
exit 1
fi
# Valida integridade do arquivo
tar tzf "$backup_file" > /dev/null 2>&1
if [[ $? -ne 0 ]]; then
echo "Erro: Arquivo de backup corrompido."
exit 1
fi
docker volume create "$volume_name"
docker run --rm -v "$volume_name:/target" -v "$(pwd):/backup" alpine \
tar xzf "/backup/$backup_file" -C /target
echo "Volume $volume_name restaurado de $backup_file"
}
Integração com cron para backups periódicos:
# No crontab: 0 2 * * * /path/to/backup_volumes.sh /backups
7. Deploy Contínuo com Git Hooks e CI/CD
Script de deploy automático via Git hook (post-receive):
#!/bin/bash
# .git/hooks/post-receive
while read oldrev newrev refname; do
if [[ "$refname" == "refs/heads/main" ]]; then
echo "Deploy automático iniciado para branch main..."
# Verifica mudanças no docker-compose.yml
if git diff --name-only "$oldrev" "$newrev" | grep -q "docker-compose.yml"; then
echo "Arquivo docker-compose.yml modificado. Recriando serviços..."
docker-compose up -d --force-recreate
else
echo "Apenas código alterado. Reconstruindo imagens..."
docker-compose build
docker-compose up -d
fi
# Health check
sleep 10
if docker-compose ps | grep -q "Exit"; then
echo "Falha no deploy. Iniciando rollback..."
git revert --no-edit "$newrev"
docker-compose up -d
else
echo "Deploy bem-sucedido!"
fi
fi
done
Pipeline CI/CD simplificado:
# test.sh
docker-compose run --rm test
# build.sh
docker-compose build
# deploy.sh
docker-compose up -d
# rollback.sh (em caso de falha)
git revert HEAD --no-edit
docker-compose up -d --force-recreate
8. Boas Práticas e Extensões
Modularização com biblioteca de funções reutilizáveis:
# lib/docker-compose-lib.sh
check_docker() {
if ! command -v docker &> /dev/null; then
echo "Docker não encontrado."
exit 1
fi
}
check_compose() {
if ! command -v docker-compose &> /dev/null; then
echo "Docker Compose não encontrado."
exit 1
fi
}
cleanup() {
echo "Limpando recursos..."
docker-compose down -v
}
trap cleanup EXIT INT TERM
Dicas de segurança:
# Evitar hardcoded secrets: usar .env com permissões restritas
# Exemplo: chmod 600 .env
# Usar docker secrets em modo swarm
# docker secret create db_password /path/to/secret
# Validar variáveis de ambiente obrigatórias
required_vars=("DB_PASSWORD" "API_KEY")
for var in "${required_vars[@]}"; do
if [[ -z "${!var}" ]]; then
echo "Erro: Variável $var não definida."
exit 1
fi
done
Referências
- Documentação Oficial do Docker Compose — Guia completo de referência para docker-compose, incluindo comandos, arquivos YAML e boas práticas.
- Bash Scripting Tutorial — Tutorial introdutório de Bash scripting, cobrindo variáveis, funções, condicionais e loops.
- Docker Compose em Produção — Artigo técnico da DigitalOcean sobre deploy de aplicações com Docker Compose em servidores Ubuntu.
- Automação de Containers com Bash — Guia prático no Dev.to sobre scripts Bash para gerenciamento de containers Docker.
- CI/CD com Docker Compose e Git Hooks — Documentação da Atlassian sobre Git Hooks, com exemplos de automação de deploys.
- Docker Stats e Monitoramento — Referência oficial do comando
docker statspara monitoramento de recursos em tempo real. - Backup e Restauração de Volumes Docker — Tutorial do Baeldung sobre estratégias de backup e restauração de volumes Docker.