BCards-Scripts-Server/scripts/deploy-to-servers.sh
2025-07-22 21:24:07 -03:00

342 lines
9.5 KiB
Bash

#!/bin/bash
# BCards Deploy Script - Containers Independentes
# Deploy automatizado da aplicação nos servidores OCI com Docker Compose
set -e
# Configurações
SERVER_IPS=("141.148.162.114" "129.146.116.218")
SSH_USER="ubuntu"
REGISTRY="registry.redecarneir.us"
APP_NAME="bcards-test-app"
CONTAINER_NAME="bcards-app"
NETWORK_NAME="bcards-network"
# Versão da aplicação (pode ser passada como parâmetro)
VERSION=${1:-"latest"}
# Cores para output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log() {
echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}"
}
error() {
echo -e "${RED}[ERROR] $1${NC}"
exit 1
}
warn() {
echo -e "${YELLOW}[WARNING] $1${NC}"
}
info() {
echo -e "${BLUE}[INFO] $1${NC}"
}
# Função para executar comando em servidor remoto
run_remote() {
local server_ip=$1
local command=$2
ssh -o StrictHostKeyChecking=no ${SSH_USER}@${server_ip} "$command"
}
# Verificar conectividade com servidores
check_connectivity() {
log "Verificando conectividade com os servidores..."
for server_ip in "${SERVER_IPS[@]}"; do
if ! ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no ${SSH_USER}@${server_ip} "echo 'ok'" >/dev/null 2>&1; then
error "Não foi possível conectar ao servidor $server_ip"
fi
info "✓ Servidor $server_ip conectado"
done
}
# Verificar se Docker está ativo
check_docker() {
log "Verificando status do Docker..."
for server_ip in "${SERVER_IPS[@]}"; do
if ! run_remote $server_ip "sudo docker info" >/dev/null 2>&1; then
error "Docker não está ativo no servidor $server_ip. Execute setup-servers.sh primeiro."
fi
info "✓ Docker está ativo no servidor $server_ip"
done
}
# Build da aplicação local (se necessário)
build_application() {
log "Building aplicação localmente..."
cd test-app
# Build da imagem Docker
info "Building imagem Docker..."
docker build -t ${APP_NAME}:${VERSION} .
# Tag para registry
docker tag ${APP_NAME}:${VERSION} ${REGISTRY}/${APP_NAME}:${VERSION}
docker tag ${APP_NAME}:${VERSION} ${REGISTRY}/${APP_NAME}:latest
info "✓ Aplicação construída com sucesso"
cd ..
}
# Push da imagem para registry
push_to_registry() {
log "Enviando imagem para registry..."
# Push da imagem
docker push ${REGISTRY}/${APP_NAME}:${VERSION}
docker push ${REGISTRY}/${APP_NAME}:latest
info "✓ Imagem enviada para registry"
}
# Deploy em containers independentes
deploy_containers() {
log "Fazendo deploy dos containers independentes..."
local server_count=1
for server_ip in "${SERVER_IPS[@]}"; do
info "Deploy no servidor $server_ip (Server $server_count)..."
# Criar docker-compose específico para cada servidor
cat > /tmp/docker-compose-server${server_count}.yml << EOF
version: '3.8'
services:
bcards-app:
image: ${REGISTRY}/${APP_NAME}:${VERSION}
container_name: ${CONTAINER_NAME}-server${server_count}
restart: unless-stopped
ports:
- "8080:8080"
environment:
- ASPNETCORE_ENVIRONMENT=Production
- SERVER_NAME=BCards Server ${server_count}
- SERVER_COLOR=$([ $server_count -eq 1 ] && echo "#28a745" || echo "#007bff")
networks:
- bcards-network
mem_limit: 512m
mem_reservation: 256m
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
bcards-network:
external: true
EOF
# Copiar docker-compose para o servidor
scp /tmp/docker-compose-server${server_count}.yml ${SSH_USER}@${server_ip}:~/bcards/docker-compose.yml
# Pull da imagem
info "Fazendo pull da imagem no servidor $server_ip..."
run_remote $server_ip "sudo docker pull ${REGISTRY}/${APP_NAME}:${VERSION}"
# Parar container antigo se existir
run_remote $server_ip "sudo docker compose -f ~/bcards/docker-compose.yml down" || true
# Iniciar novo container
info "Iniciando container no servidor $server_ip..."
run_remote $server_ip "cd ~/bcards && sudo docker compose up -d"
((server_count++))
done
info "✓ Containers deployados com sucesso"
}
# Aguardar containers ficarem saudáveis
wait_for_health() {
log "Aguardando containers ficarem saudáveis..."
local max_attempts=30
local attempt=1
while [ $attempt -le $max_attempts ]; do
local healthy_containers=0
for server_ip in "${SERVER_IPS[@]}"; do
local container_health=$(run_remote $server_ip "sudo docker inspect --format='{{.State.Health.Status}}' ${CONTAINER_NAME}-server* 2>/dev/null" | grep -c "healthy" || echo "0")
((healthy_containers += container_health))
done
if [ "$healthy_containers" -eq "2" ]; then
info "✓ Todos os containers estão saudáveis"
return 0
fi
info "Tentativa $attempt/$max_attempts - Aguardando containers ficarem saudáveis... ($healthy_containers/2)"
sleep 10
((attempt++))
done
warn "Timeout aguardando containers ficarem saudáveis"
check_container_status
return 1
}
# Verificar saúde dos containers
check_container_status() {
log "Verificando saúde dos containers..."
local server_count=1
for server_ip in "${SERVER_IPS[@]}"; do
info "Status do servidor $server_ip:"
run_remote $server_ip "sudo docker ps --filter name=${CONTAINER_NAME}"
info "Health check do servidor $server_ip:"
run_remote $server_ip "sudo docker inspect --format='{{.State.Health.Status}}' ${CONTAINER_NAME}-server${server_count} 2>/dev/null" || true
info "Logs dos últimos 50 eventos do servidor $server_ip:"
run_remote $server_ip "sudo docker logs --tail 50 ${CONTAINER_NAME}-server${server_count}" || true
((server_count++))
done
}
# Teste de conectividade externa
test_connectivity() {
log "Testando conectividade externa..."
# Teste HTTP
if curl -f -s "http://bcards.site/health" >/dev/null 2>&1; then
info "✓ HTTP health check passou"
else
warn "HTTP health check falhou"
fi
# Teste HTTPS (se SSL estiver configurado)
if curl -f -s "https://bcards.site/health" >/dev/null 2>&1; then
info "✓ HTTPS health check passou"
else
warn "HTTPS health check falhou ou SSL não configurado"
fi
}
# Rollback em caso de falha
rollback() {
log "Executando rollback..."
for server_ip in "${SERVER_IPS[@]}"; do
info "Rollback no servidor $server_ip..."
# Parar container atual
run_remote $server_ip "sudo docker compose -f ~/bcards/docker-compose.yml down" || true
# Tentar usar imagem latest anterior
run_remote $server_ip "sudo docker pull ${REGISTRY}/${APP_NAME}:latest"
# Atualizar docker-compose para usar latest
run_remote $server_ip "sed -i 's/:${VERSION}/:latest/g' ~/bcards/docker-compose.yml"
# Reiniciar com versão anterior
run_remote $server_ip "cd ~/bcards && sudo docker compose up -d"
done
info "Rollback executado"
}
# Limpeza de imagens antigas
cleanup_old_images() {
log "Limpando imagens antigas..."
for server_ip in "${SERVER_IPS[@]}"; do
info "Limpando imagens no servidor $server_ip..."
run_remote $server_ip "
sudo docker image prune -f
sudo docker container prune -f
"
done
info "✓ Limpeza concluída"
}
# Função principal
main() {
log "Iniciando deploy para versão $VERSION..."
# Verificações pré-deploy
check_connectivity
check_docker
# Build e push
if [[ "$2" != "--skip-build" ]]; then
build_application
push_to_registry
else
info "Pulando build (--skip-build especificado)"
fi
# Deploy
deploy_containers
# Verificações pós-deploy
if wait_for_health; then
check_container_status
test_connectivity
cleanup_old_images
log "Deploy concluído com sucesso!"
info "Aplicação disponível em: http://bcards.site"
info "Health check: http://bcards.site/health"
else
error "Deploy falhou - serviços não ficaram saudáveis"
if [[ "$3" == "--auto-rollback" ]]; then
rollback
fi
fi
}
# Mostrar help
show_help() {
echo "BCards Deploy Script"
echo ""
echo "Usage: $0 [VERSION] [OPTIONS]"
echo ""
echo "VERSION:"
echo " Versão da aplicação para deploy (default: latest)"
echo ""
echo "OPTIONS:"
echo " --skip-build Pula o build local da aplicação"
echo " --auto-rollback Executa rollback automático em caso de falha"
echo " --help Mostra esta ajuda"
echo ""
echo "Examples:"
echo " $0 # Deploy versão latest"
echo " $0 v1.2.3 # Deploy versão específica"
echo " $0 latest --skip-build # Deploy sem rebuild"
echo ""
echo "Servers: ${SERVER_IPS[*]}"
echo "Registry: $REGISTRY"
}
# Parse argumentos
if [[ "$1" == "--help" || "$1" == "-h" ]]; then
show_help
exit 0
fi
# Executar função principal
main "$@"