first commit
This commit is contained in:
commit
dfa9ae0225
9
.claude/settings.local.json
Normal file
9
.claude/settings.local.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(mkdir:*)",
|
||||
"Bash(chmod:*)"
|
||||
],
|
||||
"deny": []
|
||||
}
|
||||
}
|
||||
190
README-NEW-ARCHITECTURE.md
Normal file
190
README-NEW-ARCHITECTURE.md
Normal file
@ -0,0 +1,190 @@
|
||||
# BCards Infrastructure - Nova Arquitetura Simplificada
|
||||
|
||||
## Mudanças Implementadas
|
||||
|
||||
### ❌ **Removido: Docker Swarm**
|
||||
- Eliminado problemas com caracteres especiais em tokens
|
||||
- Removida complexidade desnecessária do Swarm
|
||||
- Não mais dependente de conectividade entre servidores
|
||||
|
||||
### ✅ **Nova Arquitetura: Containers Independentes**
|
||||
|
||||
#### **Servidor 1** (129.153.123.92)
|
||||
- **Função**: Load Balancer + App Container
|
||||
- **Componentes**:
|
||||
- NGINX (Load Balancer para ambos servidores)
|
||||
- Container bcards-app-server1 na porta 8080
|
||||
- SSL/TLS com Let's Encrypt
|
||||
|
||||
#### **Servidor 2** (129.146.116.218)
|
||||
- **Função**: App Container
|
||||
- **Componentes**:
|
||||
- Container bcards-app-server2 na porta 8080
|
||||
- Funciona independentemente
|
||||
|
||||
## Scripts Atualizados
|
||||
|
||||
### 1. **setup-servers.sh**
|
||||
```bash
|
||||
# O que mudou:
|
||||
- ❌ Removido: setup_docker_swarm()
|
||||
- ❌ Removido: Portas Swarm no firewall (2377, 7946, 4789)
|
||||
- ✅ Adicionado: setup_nginx() - Instala NGINX
|
||||
- ✅ Mudado: Redes Docker agora são locais (bridge)
|
||||
```
|
||||
|
||||
### 2. **deploy-to-servers.sh**
|
||||
```bash
|
||||
# O que mudou:
|
||||
- ❌ Removido: Docker Swarm stack deployment
|
||||
- ❌ Removido: Swarm service management
|
||||
- ✅ Adicionado: Docker Compose independente por servidor
|
||||
- ✅ Mudado: Containers com portas expostas (8080)
|
||||
- ✅ Melhorado: Health checks individuais por container
|
||||
```
|
||||
|
||||
### 3. **setup-nginx-loadbalancer.sh** (NOVO)
|
||||
```bash
|
||||
# Novo script para:
|
||||
- Configurar NGINX como load balancer
|
||||
- Setup SSL com Let's Encrypt
|
||||
- Configurar redirecionamento HTTP->HTTPS
|
||||
- Testar conectividade com backends
|
||||
```
|
||||
|
||||
## Fluxo de Deploy
|
||||
|
||||
### 1. **Setup Inicial**
|
||||
```bash
|
||||
# Configurar servidores
|
||||
./scripts/setup-servers.sh
|
||||
|
||||
# Configurar NGINX Load Balancer
|
||||
./scripts/setup-nginx-loadbalancer.sh --ssl
|
||||
```
|
||||
|
||||
### 2. **Deploy da Aplicação**
|
||||
```bash
|
||||
# Deploy normal
|
||||
./scripts/deploy-to-servers.sh
|
||||
|
||||
# Deploy versão específica
|
||||
./scripts/deploy-to-servers.sh v1.2.3
|
||||
|
||||
# Deploy sem rebuild
|
||||
./scripts/deploy-to-servers.sh latest --skip-build
|
||||
```
|
||||
|
||||
## Benefícios da Nova Arquitetura
|
||||
|
||||
### ✅ **Simplicidade**
|
||||
- Sem tokens complexos do Swarm
|
||||
- Cada servidor funciona independentemente
|
||||
- Fácil debug e troubleshooting
|
||||
|
||||
### ✅ **Robustez**
|
||||
- Falha em um servidor não afeta o outro
|
||||
- Rollback independente por servidor
|
||||
- Load balancer detecta servidores down
|
||||
|
||||
### ✅ **Facilidade de Manutenção**
|
||||
- Docker Compose familiar e simples
|
||||
- Logs isolados por servidor
|
||||
- Updates independentes
|
||||
|
||||
### ✅ **Flexibilidade**
|
||||
- Fácil adicionar/remover servidores
|
||||
- Configuração por servidor personalizada
|
||||
- Escalabilidade horizontal simples
|
||||
|
||||
## Configuração do Load Balancer
|
||||
|
||||
### **NGINX Upstream**
|
||||
```nginx
|
||||
upstream bcards_backend {
|
||||
server 129.153.123.92:8080;
|
||||
server 129.146.116.218:8080;
|
||||
keepalive 32;
|
||||
}
|
||||
```
|
||||
|
||||
### **Health Checks**
|
||||
- NGINX detecta automaticamente servidores indisponíveis
|
||||
- Failover automático entre servidores
|
||||
- Health check endpoint: `/health`
|
||||
|
||||
### **SSL/TLS**
|
||||
- Let's Encrypt automático
|
||||
- Redirecionamento HTTP->HTTPS
|
||||
- Headers de segurança configurados
|
||||
|
||||
## Comandos Úteis
|
||||
|
||||
### **Verificar Status**
|
||||
```bash
|
||||
# Status dos containers
|
||||
ssh ubuntu@129.153.123.92 "sudo docker ps"
|
||||
ssh ubuntu@129.146.116.218 "sudo docker ps"
|
||||
|
||||
# Status do NGINX
|
||||
ssh ubuntu@129.153.123.92 "sudo systemctl status nginx"
|
||||
|
||||
# Logs da aplicação
|
||||
ssh ubuntu@129.153.123.92 "sudo docker logs bcards-app-server1"
|
||||
ssh ubuntu@129.146.116.218 "sudo docker logs bcards-app-server2"
|
||||
```
|
||||
|
||||
### **Troubleshooting**
|
||||
```bash
|
||||
# Teste de conectividade
|
||||
curl -f http://bcards.site/health
|
||||
curl -f https://bcards.site/health
|
||||
|
||||
# Logs do NGINX
|
||||
ssh ubuntu@129.153.123.92 "sudo tail -f /var/log/nginx/bcards_access.log"
|
||||
ssh ubuntu@129.153.123.92 "sudo tail -f /var/log/nginx/bcards_error.log"
|
||||
|
||||
# Restart individual
|
||||
ssh ubuntu@129.153.123.92 "cd ~/bcards && sudo docker compose restart"
|
||||
ssh ubuntu@129.146.116.218 "cd ~/bcards && sudo docker compose restart"
|
||||
```
|
||||
|
||||
## Migração da Arquitetura Anterior
|
||||
|
||||
### **Para migrar do Docker Swarm:**
|
||||
|
||||
1. **Backup** (se necessário):
|
||||
```bash
|
||||
# Backup de dados importantes
|
||||
ssh ubuntu@129.153.123.92 "sudo docker cp container_name:/data ./backup/"
|
||||
```
|
||||
|
||||
2. **Limpar Swarm**:
|
||||
```bash
|
||||
ssh ubuntu@129.153.123.92 "sudo docker swarm leave --force"
|
||||
ssh ubuntu@129.146.116.218 "sudo docker swarm leave --force"
|
||||
```
|
||||
|
||||
3. **Deploy nova arquitetura**:
|
||||
```bash
|
||||
./scripts/setup-servers.sh
|
||||
./scripts/setup-nginx-loadbalancer.sh --ssl
|
||||
./scripts/deploy-to-servers.sh
|
||||
```
|
||||
|
||||
## Monitoramento
|
||||
|
||||
### **Health Checks**
|
||||
- **Endpoint**: `https://bcards.site/health`
|
||||
- **Frequência**: 30s por container
|
||||
- **Timeout**: 10s
|
||||
- **Retries**: 3
|
||||
|
||||
### **Logs**
|
||||
- **NGINX**: `/var/log/nginx/bcards_*.log`
|
||||
- **Containers**: Docker logs com rotação automática
|
||||
- **Sistema**: `/var/log/bcards/`
|
||||
|
||||
---
|
||||
|
||||
**✅ Arquitetura simplificada e robusta implementada com sucesso!**
|
||||
293
README.md
Normal file
293
README.md
Normal file
@ -0,0 +1,293 @@
|
||||
# BCards Infrastructure
|
||||
|
||||
Infraestrutura completa para deploy do BCards com load balancer, SSL e zero-downtime deployment.
|
||||
|
||||
## 📋 Visão Geral
|
||||
|
||||
### Arquitetura
|
||||
- **2 Servidores OCI**: 129.153.123.92 e 129.146.116.218
|
||||
- **Load Balancer**: NGINX com SSL (Let's Encrypt)
|
||||
- **Orquestração**: Docker Swarm
|
||||
- **Domínio**: bcards.site
|
||||
- **Registry**: registry.redecarneir.us
|
||||
|
||||
### Componentes
|
||||
- **Aplicação ASP.NET Core**: App de teste com identificação de servidor
|
||||
- **NGINX**: Load balancer com SSL e health checks
|
||||
- **Docker Swarm**: Orquestração de containers
|
||||
- **Fluentd**: Agregação de logs
|
||||
- **Monitoramento**: Prometheus + Grafana (opcional)
|
||||
|
||||
## 🚀 Início Rápido
|
||||
|
||||
### 1. Setup dos Servidores
|
||||
```bash
|
||||
# Configurar servidores OCI
|
||||
./scripts/setup-servers.sh
|
||||
```
|
||||
|
||||
### 2. Configurar SSL
|
||||
```bash
|
||||
# Configurar certificados SSL
|
||||
cd nginx && ./setup-ssl.sh
|
||||
```
|
||||
|
||||
### 3. Deploy da Aplicação
|
||||
```bash
|
||||
# Deploy para produção
|
||||
./scripts/deploy-to-servers.sh
|
||||
```
|
||||
|
||||
### 4. Teste Local
|
||||
```bash
|
||||
# Testar localmente
|
||||
docker-compose -f docker-compose.test.yml up
|
||||
```
|
||||
|
||||
## 📁 Estrutura do Projeto
|
||||
|
||||
```
|
||||
bcards-infrastructure/
|
||||
├── scripts/
|
||||
│ ├── setup-servers.sh # Setup inicial dos servidores
|
||||
│ ├── deploy-to-servers.sh # Deploy automatizado
|
||||
│ ├── test-connectivity.sh # Testes de conectividade
|
||||
│ └── cleanup.sh # Limpeza de recursos
|
||||
├── test-app/ # Aplicação ASP.NET Core de teste
|
||||
│ ├── Controllers/
|
||||
│ ├── Views/
|
||||
│ ├── Program.cs
|
||||
│ ├── Dockerfile
|
||||
│ └── docker-compose.yml
|
||||
├── nginx/ # Configurações NGINX
|
||||
│ ├── nginx.conf # Configuração produção
|
||||
│ ├── nginx-test.conf # Configuração teste
|
||||
│ ├── setup-ssl.sh # Script SSL
|
||||
│ └── fluentd/ # Configurações logs
|
||||
├── monitoring/ # Monitoramento
|
||||
│ └── prometheus.yml
|
||||
├── mongodb/ # Configurações MongoDB
|
||||
│ └── init/
|
||||
└── docker-compose.test.yml # Ambiente de teste
|
||||
```
|
||||
|
||||
## 🛠️ Scripts Disponíveis
|
||||
|
||||
### Setup dos Servidores
|
||||
```bash
|
||||
./scripts/setup-servers.sh
|
||||
```
|
||||
- Instala Docker se necessário
|
||||
- Configura Docker Swarm
|
||||
- Configura firewall básico
|
||||
- Cria estrutura de diretórios
|
||||
|
||||
### Deploy Automatizado
|
||||
```bash
|
||||
# Deploy versão latest
|
||||
./scripts/deploy-to-servers.sh
|
||||
|
||||
# Deploy versão específica
|
||||
./scripts/deploy-to-servers.sh v1.2.3
|
||||
|
||||
# Deploy sem rebuild
|
||||
./scripts/deploy-to-servers.sh latest --skip-build
|
||||
|
||||
# Deploy com rollback automático
|
||||
./scripts/deploy-to-servers.sh latest --auto-rollback
|
||||
```
|
||||
|
||||
### Testes de Conectividade
|
||||
```bash
|
||||
# Teste completo
|
||||
./scripts/test-connectivity.sh
|
||||
|
||||
# Gerar relatório
|
||||
./scripts/test-connectivity.sh --report
|
||||
```
|
||||
|
||||
### Limpeza de Recursos
|
||||
```bash
|
||||
# Limpeza básica
|
||||
./scripts/cleanup.sh
|
||||
|
||||
# Parar serviços e limpar
|
||||
./scripts/cleanup.sh --stop-services
|
||||
|
||||
# Limpeza completa (cuidado!)
|
||||
./scripts/cleanup.sh --full
|
||||
```
|
||||
|
||||
## 🌐 Endpoints
|
||||
|
||||
### Produção (bcards.site)
|
||||
- **Aplicação**: https://bcards.site
|
||||
- **Health Check**: https://bcards.site/health
|
||||
- **Server Info**: https://bcards.site/server-info
|
||||
- **NGINX Status**: https://bcards.site/nginx-health
|
||||
|
||||
### Teste Local (localhost)
|
||||
- **Aplicação**: http://localhost
|
||||
- **NGINX Status**: http://localhost:8081/nginx_status
|
||||
- **Prometheus**: http://localhost:9090
|
||||
- **Grafana**: http://localhost:3000 (admin/bcards123)
|
||||
|
||||
## 🔧 Configuração
|
||||
|
||||
### Variáveis de Ambiente
|
||||
|
||||
#### Aplicação
|
||||
- `SERVER_NAME`: Nome do servidor (ex: "BCards Server 1")
|
||||
- `SERVER_COLOR`: Cor do tema (ex: "#28a745")
|
||||
- `ASPNETCORE_ENVIRONMENT`: Ambiente (Production/Development)
|
||||
|
||||
#### Docker Swarm
|
||||
- Labels dos nodes: `server_id=server1` ou `server_id=server2`
|
||||
|
||||
### Portas Utilizadas
|
||||
|
||||
#### Produção
|
||||
- **80**: HTTP (redirect para HTTPS)
|
||||
- **443**: HTTPS
|
||||
- **2377**: Docker Swarm management
|
||||
- **7946**: Docker Swarm communication
|
||||
- **4789**: Docker overlay network
|
||||
|
||||
#### Teste Local
|
||||
- **80**: NGINX Load Balancer
|
||||
- **3000**: Grafana
|
||||
- **6379**: Redis
|
||||
- **9090**: Prometheus
|
||||
- **24224**: Fluentd
|
||||
- **27017**: MongoDB
|
||||
|
||||
## 📊 Monitoramento
|
||||
|
||||
### Logs
|
||||
- **NGINX**: `/var/log/nginx/`
|
||||
- **Aplicação**: Docker logs via Fluentd
|
||||
- **Sistema**: journalctl
|
||||
|
||||
### Health Checks
|
||||
- **Aplicação**: `/health` endpoint
|
||||
- **NGINX**: `/nginx-health` endpoint
|
||||
- **Docker**: Container health checks
|
||||
|
||||
### Métricas
|
||||
- **Prometheus**: Coleta de métricas
|
||||
- **Grafana**: Visualização de dashboards
|
||||
|
||||
## 🔒 Segurança
|
||||
|
||||
### SSL/TLS
|
||||
- **Let's Encrypt**: Certificados automáticos
|
||||
- **Renovação**: Automática via cron
|
||||
- **HSTS**: Habilitado
|
||||
- **Strong Ciphers**: TLS 1.2+
|
||||
|
||||
### Firewall
|
||||
- **SSH**: Porta 22
|
||||
- **HTTP/HTTPS**: Portas 80/443
|
||||
- **Docker Swarm**: Portas necessárias
|
||||
- **Resto**: Bloqueado
|
||||
|
||||
### Docker
|
||||
- **Usuário não-root**: Containers executam como usuário limitado
|
||||
- **Resources limits**: Limites de CPU/memória
|
||||
- **Health checks**: Monitoramento de saúde
|
||||
|
||||
## 🚨 Troubleshooting
|
||||
|
||||
### Problemas Comuns
|
||||
|
||||
#### SSH não conecta
|
||||
```bash
|
||||
# Verificar conectividade
|
||||
ssh -o ConnectTimeout=10 ubuntu@129.153.123.92 "echo 'ok'"
|
||||
```
|
||||
|
||||
#### Docker Swarm não funciona
|
||||
```bash
|
||||
# Verificar status do swarm
|
||||
ssh ubuntu@129.153.123.92 "sudo docker node ls"
|
||||
|
||||
# Reinicializar se necessário
|
||||
./scripts/setup-servers.sh
|
||||
```
|
||||
|
||||
#### SSL não funciona
|
||||
```bash
|
||||
# Verificar certificados
|
||||
sudo openssl x509 -in /etc/letsencrypt/live/bcards.site/fullchain.pem -text -noout
|
||||
|
||||
# Renovar certificados
|
||||
sudo /usr/local/bin/renew-ssl.sh
|
||||
```
|
||||
|
||||
#### Load balancer não balanceia
|
||||
```bash
|
||||
# Testar múltiplas requisições
|
||||
for i in {1..10}; do curl -s http://bcards.site/server-info | jq -r '.ServerName'; done
|
||||
```
|
||||
|
||||
### Logs Úteis
|
||||
```bash
|
||||
# Logs do NGINX
|
||||
sudo docker service logs bcards-nginx
|
||||
|
||||
# Logs da aplicação
|
||||
sudo docker service logs bcards-app_app-server1
|
||||
sudo docker service logs bcards-app_app-server2
|
||||
|
||||
# Logs do sistema
|
||||
sudo journalctl -u docker -f
|
||||
```
|
||||
|
||||
## 📚 Recursos Adicionais
|
||||
|
||||
### Comandos Docker Swarm
|
||||
```bash
|
||||
# Listar serviços
|
||||
sudo docker service ls
|
||||
|
||||
# Escalar serviço
|
||||
sudo docker service scale bcards-app_app-server1=2
|
||||
|
||||
# Atualizar serviço
|
||||
sudo docker service update --image registry.redecarneir.us/bcards-test-app:v2 bcards-app_app-server1
|
||||
|
||||
# Rollback
|
||||
sudo docker service rollback bcards-app_app-server1
|
||||
```
|
||||
|
||||
### Backup e Restore
|
||||
```bash
|
||||
# Backup da configuração
|
||||
tar -czf bcards-backup-$(date +%Y%m%d).tar.gz scripts/ nginx/ test-app/
|
||||
|
||||
# Backup do banco (se usando MongoDB)
|
||||
docker exec bcards-mongodb mongodump --out /backup
|
||||
```
|
||||
|
||||
## 🤝 Contribuição
|
||||
|
||||
1. Fork o projeto
|
||||
2. Crie uma branch para sua feature (`git checkout -b feature/AmazingFeature`)
|
||||
3. Commit suas mudanças (`git commit -m 'Add some AmazingFeature'`)
|
||||
4. Push para a branch (`git push origin feature/AmazingFeature`)
|
||||
5. Abra um Pull Request
|
||||
|
||||
## 📄 Licença
|
||||
|
||||
Este projeto está sob a licença MIT. Veja o arquivo `LICENSE` para mais detalhes.
|
||||
|
||||
## 📞 Suporte
|
||||
|
||||
Para suporte, entre em contato:
|
||||
- **Email**: admin@bcards.site
|
||||
- **Issues**: GitHub Issues
|
||||
- **Documentação**: README.md
|
||||
|
||||
---
|
||||
|
||||
**BCards Infrastructure** - Deploy com confiança! 🚀
|
||||
24
bcards-infrastructure.sln
Normal file
24
bcards-infrastructure.sln
Normal file
@ -0,0 +1,24 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.5.2.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BCardsTestApp", "test-app\BCardsTestApp.csproj", "{D3618677-0EF3-8C7D-E6B2-197D93585C5E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{D3618677-0EF3-8C7D-E6B2-197D93585C5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D3618677-0EF3-8C7D-E6B2-197D93585C5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D3618677-0EF3-8C7D-E6B2-197D93585C5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D3618677-0EF3-8C7D-E6B2-197D93585C5E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {43F40495-4B27-4C15-A2BE-023117CD44C5}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
187
docker-compose.test.yml
Normal file
187
docker-compose.test.yml
Normal file
@ -0,0 +1,187 @@
|
||||
version: '3.8'
|
||||
|
||||
# Docker Compose para teste local da infraestrutura BCards
|
||||
# Simula o ambiente de produção com 2 servidores e load balancer
|
||||
|
||||
services:
|
||||
# Aplicação Server 1
|
||||
bcards-server1:
|
||||
build: ./test-app
|
||||
container_name: bcards-server1
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
- SERVER_NAME=BCards Server 1
|
||||
- SERVER_COLOR=#28a745
|
||||
- ASPNETCORE_URLS=http://+:8080
|
||||
networks:
|
||||
- bcards-test-network
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
depends_on:
|
||||
- mongodb
|
||||
|
||||
# Aplicação Server 2
|
||||
bcards-server2:
|
||||
build: ./test-app
|
||||
container_name: bcards-server2
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
- SERVER_NAME=BCards Server 2
|
||||
- SERVER_COLOR=#007bff
|
||||
- ASPNETCORE_URLS=http://+:8080
|
||||
networks:
|
||||
- bcards-test-network
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
depends_on:
|
||||
- mongodb
|
||||
|
||||
# NGINX Load Balancer
|
||||
nginx-lb:
|
||||
image: nginx:alpine
|
||||
container_name: bcards-nginx-lb
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx/nginx-test.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./nginx/logs:/var/log/nginx
|
||||
networks:
|
||||
- bcards-test-network
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- bcards-server1
|
||||
- bcards-server2
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/nginx-health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
|
||||
# MongoDB para testes
|
||||
mongodb:
|
||||
image: mongo:7.0
|
||||
container_name: bcards-mongodb
|
||||
environment:
|
||||
- MONGO_INITDB_ROOT_USERNAME=admin
|
||||
- MONGO_INITDB_ROOT_PASSWORD=bcards123
|
||||
- MONGO_INITDB_DATABASE=bcards
|
||||
ports:
|
||||
- "27017:27017"
|
||||
volumes:
|
||||
- mongodb_data:/data/db
|
||||
- ./mongodb/init:/docker-entrypoint-initdb.d:ro
|
||||
networks:
|
||||
- bcards-test-network
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
|
||||
# Redis para cache (opcional)
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: bcards-redis
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
- ./redis/redis.conf:/usr/local/etc/redis/redis.conf:ro
|
||||
networks:
|
||||
- bcards-test-network
|
||||
restart: unless-stopped
|
||||
command: redis-server /usr/local/etc/redis/redis.conf
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
# Fluentd para logs centralizados
|
||||
fluentd:
|
||||
image: fluent/fluentd:v1.16-debian-1
|
||||
container_name: bcards-fluentd
|
||||
volumes:
|
||||
- ./nginx/fluentd/fluent-test.conf:/fluentd/etc/fluent.conf:ro
|
||||
- ./nginx/logs:/var/log/nginx:ro
|
||||
- fluentd_logs:/fluentd/log
|
||||
ports:
|
||||
- "24224:24224"
|
||||
- "24224:24224/udp"
|
||||
networks:
|
||||
- bcards-test-network
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- FLUENTD_CONF=fluent.conf
|
||||
|
||||
# Prometheus para monitoramento (opcional)
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
container_name: bcards-prometheus
|
||||
ports:
|
||||
- "9090:9090"
|
||||
volumes:
|
||||
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
|
||||
- prometheus_data:/prometheus
|
||||
networks:
|
||||
- bcards-test-network
|
||||
restart: unless-stopped
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.path=/prometheus'
|
||||
- '--web.console.libraries=/etc/prometheus/console_libraries'
|
||||
- '--web.console.templates=/etc/prometheus/consoles'
|
||||
- '--storage.tsdb.retention.time=200h'
|
||||
- '--web.enable-lifecycle'
|
||||
|
||||
# Grafana para dashboards (opcional)
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
container_name: bcards-grafana
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- grafana_data:/var/lib/grafana
|
||||
- ./monitoring/grafana/provisioning:/etc/grafana/provisioning:ro
|
||||
networks:
|
||||
- bcards-test-network
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_PASSWORD=bcards123
|
||||
- GF_USERS_ALLOW_SIGN_UP=false
|
||||
depends_on:
|
||||
- prometheus
|
||||
|
||||
networks:
|
||||
bcards-test-network:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.20.0.0/16
|
||||
|
||||
volumes:
|
||||
mongodb_data:
|
||||
driver: local
|
||||
redis_data:
|
||||
driver: local
|
||||
fluentd_logs:
|
||||
driver: local
|
||||
prometheus_data:
|
||||
driver: local
|
||||
grafana_data:
|
||||
driver: local
|
||||
52
mongodb/init/init-bcards.js
Normal file
52
mongodb/init/init-bcards.js
Normal file
@ -0,0 +1,52 @@
|
||||
// MongoDB initialization script for BCards
|
||||
|
||||
// Create BCards database
|
||||
db = db.getSiblingDB('bcards');
|
||||
|
||||
// Create collections
|
||||
db.createCollection('users');
|
||||
db.createCollection('cards');
|
||||
db.createCollection('sessions');
|
||||
|
||||
// Create indexes
|
||||
db.users.createIndex({ "email": 1 }, { unique: true });
|
||||
db.cards.createIndex({ "userId": 1 });
|
||||
db.cards.createIndex({ "createdAt": 1 });
|
||||
db.sessions.createIndex({ "createdAt": 1 }, { expireAfterSeconds: 3600 });
|
||||
|
||||
// Insert sample data for testing
|
||||
db.users.insertMany([
|
||||
{
|
||||
_id: ObjectId(),
|
||||
email: "test1@bcards.site",
|
||||
name: "Test User 1",
|
||||
createdAt: new Date()
|
||||
},
|
||||
{
|
||||
_id: ObjectId(),
|
||||
email: "test2@bcards.site",
|
||||
name: "Test User 2",
|
||||
createdAt: new Date()
|
||||
}
|
||||
]);
|
||||
|
||||
db.cards.insertMany([
|
||||
{
|
||||
_id: ObjectId(),
|
||||
userId: db.users.findOne({"email": "test1@bcards.site"})._id,
|
||||
title: "Test Card 1",
|
||||
content: "This is a test card for infrastructure testing",
|
||||
tags: ["test", "infrastructure"],
|
||||
createdAt: new Date()
|
||||
},
|
||||
{
|
||||
_id: ObjectId(),
|
||||
userId: db.users.findOne({"email": "test2@bcards.site"})._id,
|
||||
title: "Test Card 2",
|
||||
content: "Another test card for load balancer testing",
|
||||
tags: ["test", "load-balancer"],
|
||||
createdAt: new Date()
|
||||
}
|
||||
]);
|
||||
|
||||
print("BCards database initialized successfully!");
|
||||
39
monitoring/prometheus.yml
Normal file
39
monitoring/prometheus.yml
Normal file
@ -0,0 +1,39 @@
|
||||
# Prometheus configuration for BCards monitoring
|
||||
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
evaluation_interval: 15s
|
||||
|
||||
rule_files:
|
||||
# - "first_rules.yml"
|
||||
# - "second_rules.yml"
|
||||
|
||||
scrape_configs:
|
||||
# Prometheus itself
|
||||
- job_name: 'prometheus'
|
||||
static_configs:
|
||||
- targets: ['localhost:9090']
|
||||
|
||||
# NGINX metrics (via nginx-prometheus-exporter if installed)
|
||||
- job_name: 'nginx'
|
||||
static_configs:
|
||||
- targets: ['nginx-lb:8081']
|
||||
metrics_path: /nginx_status
|
||||
scrape_interval: 30s
|
||||
|
||||
# Application health checks
|
||||
- job_name: 'bcards-app'
|
||||
static_configs:
|
||||
- targets: ['bcards-server1:8080', 'bcards-server2:8080']
|
||||
metrics_path: /health
|
||||
scrape_interval: 30s
|
||||
|
||||
# MongoDB exporter (if installed)
|
||||
# - job_name: 'mongodb'
|
||||
# static_configs:
|
||||
# - targets: ['mongodb-exporter:9216']
|
||||
|
||||
# Redis exporter (if installed)
|
||||
# - job_name: 'redis'
|
||||
# static_configs:
|
||||
# - targets: ['redis-exporter:9121']
|
||||
64
nginx/docker-compose.yml
Normal file
64
nginx/docker-compose.yml
Normal file
@ -0,0 +1,64 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# NGINX Load Balancer
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: bcards-nginx
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
# Configuração do NGINX
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
|
||||
# Certificados SSL (Let's Encrypt)
|
||||
- /etc/letsencrypt:/etc/letsencrypt:ro
|
||||
- /var/www/certbot:/var/www/certbot:ro
|
||||
|
||||
# Logs
|
||||
- ./logs:/var/log/nginx
|
||||
networks:
|
||||
- bcards-network
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- certbot
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/nginx-health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
labels:
|
||||
- "traefik.enable=false"
|
||||
|
||||
# Certbot para SSL certificates
|
||||
certbot:
|
||||
image: certbot/certbot
|
||||
container_name: bcards-certbot
|
||||
volumes:
|
||||
- /etc/letsencrypt:/etc/letsencrypt
|
||||
- /var/www/certbot:/var/www/certbot
|
||||
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
|
||||
restart: unless-stopped
|
||||
|
||||
# Log aggregator (opcional)
|
||||
fluentd:
|
||||
image: fluent/fluentd:v1.16-debian-1
|
||||
container_name: bcards-fluentd
|
||||
volumes:
|
||||
- ./fluentd/fluent.conf:/fluentd/etc/fluent.conf:ro
|
||||
- ./logs:/var/log/nginx:ro
|
||||
- ./fluentd/logs:/fluentd/log
|
||||
ports:
|
||||
- "24224:24224"
|
||||
- "24224:24224/udp"
|
||||
networks:
|
||||
- bcards-network
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- FLUENTD_CONF=fluent.conf
|
||||
|
||||
networks:
|
||||
bcards-network:
|
||||
external: true
|
||||
44
nginx/fluentd/fluent-test.conf
Normal file
44
nginx/fluentd/fluent-test.conf
Normal file
@ -0,0 +1,44 @@
|
||||
# Fluentd configuration for BCards test environment
|
||||
|
||||
<source>
|
||||
@type tail
|
||||
path /var/log/nginx/access.log
|
||||
pos_file /fluentd/log/access.log.pos
|
||||
tag nginx.access
|
||||
format nginx
|
||||
time_format %d/%b/%Y:%H:%M:%S %z
|
||||
</source>
|
||||
|
||||
<source>
|
||||
@type tail
|
||||
path /var/log/nginx/error.log
|
||||
pos_file /fluentd/log/error.log.pos
|
||||
tag nginx.error
|
||||
format /^(?<time>\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}) \[(?<level>\w+)\] (?<message>.*)/
|
||||
time_format %Y/%m/%d %H:%M:%S
|
||||
</source>
|
||||
|
||||
<filter nginx.**>
|
||||
@type record_transformer
|
||||
<record>
|
||||
hostname "#{Socket.gethostname}"
|
||||
service nginx
|
||||
environment test
|
||||
</record>
|
||||
</filter>
|
||||
|
||||
<match nginx.**>
|
||||
@type file
|
||||
path /fluentd/log/nginx-test
|
||||
append true
|
||||
time_slice_format %Y%m%d
|
||||
time_slice_wait 10m
|
||||
time_format %Y%m%dT%H%M%S%z
|
||||
buffer_type file
|
||||
buffer_path /fluentd/log/nginx.buffer
|
||||
flush_interval 30s
|
||||
</match>
|
||||
|
||||
<match **>
|
||||
@type stdout
|
||||
</match>
|
||||
40
nginx/fluentd/fluent.conf
Normal file
40
nginx/fluentd/fluent.conf
Normal file
@ -0,0 +1,40 @@
|
||||
# Fluentd configuration for BCards log aggregation
|
||||
|
||||
<source>
|
||||
@type tail
|
||||
path /var/log/nginx/access.log
|
||||
pos_file /fluentd/log/access.log.pos
|
||||
tag nginx.access
|
||||
format nginx
|
||||
time_format %d/%b/%Y:%H:%M:%S %z
|
||||
</source>
|
||||
|
||||
<source>
|
||||
@type tail
|
||||
path /var/log/nginx/error.log
|
||||
pos_file /fluentd/log/error.log.pos
|
||||
tag nginx.error
|
||||
format /^(?<time>\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}) \[(?<level>\w+)\] (?<message>.*)/
|
||||
time_format %Y/%m/%d %H:%M:%S
|
||||
</source>
|
||||
|
||||
<filter nginx.**>
|
||||
@type record_transformer
|
||||
<record>
|
||||
hostname "#{Socket.gethostname}"
|
||||
service nginx
|
||||
environment production
|
||||
</record>
|
||||
</filter>
|
||||
|
||||
<match nginx.**>
|
||||
@type file
|
||||
path /fluentd/log/nginx
|
||||
append true
|
||||
time_slice_format %Y%m%d
|
||||
time_slice_wait 10m
|
||||
time_format %Y%m%dT%H%M%S%z
|
||||
buffer_type file
|
||||
buffer_path /fluentd/log/nginx.buffer
|
||||
flush_interval 30s
|
||||
</match>
|
||||
74
nginx/nginx-loadbalancer-http.conf
Normal file
74
nginx/nginx-loadbalancer-http.conf
Normal file
@ -0,0 +1,74 @@
|
||||
upstream bcards_backend {
|
||||
server 141.148.162.114:8080;
|
||||
server 129.146.116.218:8080;
|
||||
|
||||
# Health check settings
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name bcards.site;
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options DENY;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
|
||||
# Gzip compression
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
|
||||
|
||||
# Load balancer configuration
|
||||
location / {
|
||||
proxy_pass http://bcards_backend;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# Connection settings
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_send_timeout 30s;
|
||||
proxy_read_timeout 30s;
|
||||
|
||||
# Buffer settings
|
||||
proxy_buffering on;
|
||||
proxy_buffer_size 4k;
|
||||
proxy_buffers 8 4k;
|
||||
|
||||
# Health check
|
||||
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
|
||||
proxy_next_upstream_tries 2;
|
||||
proxy_next_upstream_timeout 30s;
|
||||
}
|
||||
|
||||
# Health check endpoint
|
||||
location /health {
|
||||
access_log off;
|
||||
proxy_pass http://bcards_backend;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Static files (if any)
|
||||
location /static {
|
||||
proxy_pass http://bcards_backend;
|
||||
proxy_cache_valid 200 1h;
|
||||
expires 1h;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# Let's Encrypt ACME challenge
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/html;
|
||||
}
|
||||
|
||||
# Logging
|
||||
access_log /var/log/nginx/bcards_access.log;
|
||||
error_log /var/log/nginx/bcards_error.log;
|
||||
}
|
||||
87
nginx/nginx-loadbalancer.conf
Normal file
87
nginx/nginx-loadbalancer.conf
Normal file
@ -0,0 +1,87 @@
|
||||
upstream bcards_backend {
|
||||
server 141.148.162.114:8080;
|
||||
server 129.146.116.218:8080;
|
||||
|
||||
# Health check settings
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name bcards.site www.bcards.site;
|
||||
|
||||
# Redirect HTTP to HTTPS
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name bcards.site www.bcards.site;
|
||||
|
||||
# SSL Configuration
|
||||
ssl_certificate /etc/letsencrypt/live/bcards.site/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/bcards.site/privkey.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options DENY;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
|
||||
# Gzip compression
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
|
||||
|
||||
# Load balancer configuration
|
||||
location / {
|
||||
proxy_pass http://bcards_backend;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# Connection settings
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_send_timeout 30s;
|
||||
proxy_read_timeout 30s;
|
||||
|
||||
# Buffer settings
|
||||
proxy_buffering on;
|
||||
proxy_buffer_size 4k;
|
||||
proxy_buffers 8 4k;
|
||||
|
||||
# Health check
|
||||
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
|
||||
proxy_next_upstream_tries 2;
|
||||
proxy_next_upstream_timeout 30s;
|
||||
}
|
||||
|
||||
# Health check endpoint
|
||||
location /health {
|
||||
access_log off;
|
||||
proxy_pass http://bcards_backend;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Static files (if any)
|
||||
location /static {
|
||||
proxy_pass http://bcards_backend;
|
||||
proxy_cache_valid 200 1h;
|
||||
expires 1h;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# Logging
|
||||
access_log /var/log/nginx/bcards_access.log;
|
||||
error_log /var/log/nginx/bcards_error.log;
|
||||
}
|
||||
50
nginx/nginx-local.conf
Normal file
50
nginx/nginx-local.conf
Normal file
@ -0,0 +1,50 @@
|
||||
# NGINX Configuration for Local Development
|
||||
# Configuração simplificada para testes locais
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# Log format
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
error_log /var/log/nginx/error.log;
|
||||
|
||||
# Upstream para desenvolvimento local
|
||||
upstream bcards_local {
|
||||
server bcards-test-app:8080;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
# Health check do NGINX
|
||||
location = /nginx-health {
|
||||
access_log off;
|
||||
return 200 "nginx ok\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
|
||||
# Proxy para aplicação
|
||||
location / {
|
||||
proxy_pass http://bcards_local;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# Timeouts para desenvolvimento
|
||||
proxy_connect_timeout 10s;
|
||||
proxy_send_timeout 10s;
|
||||
proxy_read_timeout 10s;
|
||||
}
|
||||
}
|
||||
}
|
||||
127
nginx/nginx-test.conf
Normal file
127
nginx/nginx-test.conf
Normal file
@ -0,0 +1,127 @@
|
||||
# NGINX Configuration for Local Testing
|
||||
# Simula o ambiente de produção para testes locais
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# Log format
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for" '
|
||||
'rt=$request_time uct="$upstream_connect_time" '
|
||||
'uht="$upstream_header_time" urt="$upstream_response_time"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
error_log /var/log/nginx/error.log;
|
||||
|
||||
# Gzip compression
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
|
||||
# Upstream configuration para load balancing
|
||||
upstream bcards_backend {
|
||||
least_conn;
|
||||
server bcards-server1:8080 max_fails=3 fail_timeout=30s;
|
||||
server bcards-server2:8080 max_fails=3 fail_timeout=30s;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
# Rate limiting
|
||||
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
# Rate limiting
|
||||
limit_req zone=general burst=20 nodelay;
|
||||
|
||||
# Health check do NGINX
|
||||
location = /nginx-health {
|
||||
access_log off;
|
||||
return 200 "nginx ok\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
|
||||
# Backend health check
|
||||
location = /backend-health {
|
||||
access_log off;
|
||||
proxy_pass http://bcards_backend/health;
|
||||
proxy_connect_timeout 5s;
|
||||
proxy_read_timeout 5s;
|
||||
}
|
||||
|
||||
# Main application proxy
|
||||
location / {
|
||||
proxy_pass http://bcards_backend;
|
||||
|
||||
# Headers para proxy reverso
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
|
||||
# Timeouts
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_send_timeout 30s;
|
||||
proxy_read_timeout 30s;
|
||||
|
||||
# Buffer settings
|
||||
proxy_buffering on;
|
||||
proxy_buffer_size 4k;
|
||||
proxy_buffers 8 4k;
|
||||
|
||||
# Retry configuration
|
||||
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
|
||||
proxy_next_upstream_tries 2;
|
||||
proxy_next_upstream_timeout 10s;
|
||||
}
|
||||
|
||||
# Static files caching
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
|
||||
proxy_pass http://bcards_backend;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
expires 1h;
|
||||
add_header Cache-Control "public";
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# Status page para monitoramento
|
||||
location = /status {
|
||||
access_log off;
|
||||
return 200 "{\n \"status\": \"ok\",\n \"timestamp\": \"$time_iso8601\",\n \"server\": \"nginx-test\"\n}";
|
||||
add_header Content-Type application/json;
|
||||
}
|
||||
|
||||
# Error pages
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
}
|
||||
|
||||
# Monitoring endpoint
|
||||
server {
|
||||
listen 8081;
|
||||
server_name localhost;
|
||||
|
||||
location /nginx_status {
|
||||
stub_status on;
|
||||
access_log off;
|
||||
allow all;
|
||||
}
|
||||
}
|
||||
}
|
||||
239
nginx/nginx.conf
Normal file
239
nginx/nginx.conf
Normal file
@ -0,0 +1,239 @@
|
||||
# NGINX Configuration for BCards Load Balancer
|
||||
# Configuração principal para produção com SSL e load balancing
|
||||
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
# Otimizações de performance
|
||||
worker_rlimit_nofile 65535;
|
||||
|
||||
events {
|
||||
worker_connections 4096;
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
# Configurações básicas
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# Logging format
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for" '
|
||||
'rt=$request_time uct="$upstream_connect_time" '
|
||||
'uht="$upstream_header_time" urt="$upstream_response_time"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
# Performance settings
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
client_max_body_size 20M;
|
||||
|
||||
# Gzip compression
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/xml
|
||||
text/javascript
|
||||
application/json
|
||||
application/javascript
|
||||
application/xml+rss
|
||||
application/atom+xml
|
||||
image/svg+xml;
|
||||
|
||||
# Rate limiting
|
||||
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
|
||||
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
|
||||
|
||||
# Upstream configuration for load balancing
|
||||
upstream bcards_backend {
|
||||
# Configuração de load balancing com health checks
|
||||
least_conn;
|
||||
|
||||
# Servidores backend
|
||||
server 172.18.0.2:8080 max_fails=3 fail_timeout=30s;
|
||||
server 172.18.0.3:8080 max_fails=3 fail_timeout=30s;
|
||||
|
||||
# Manter conexões vivas
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
# Configuração para health checks dos backends
|
||||
upstream bcards_health {
|
||||
server 172.18.0.2:8080;
|
||||
server 172.18.0.3:8080;
|
||||
}
|
||||
|
||||
# Rate limiting
|
||||
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
|
||||
|
||||
# Configuração SSL/TLS
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options DENY always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
|
||||
# Redirect HTTP to HTTPS
|
||||
server {
|
||||
listen 80;
|
||||
server_name bcards.site www.bcards.site;
|
||||
|
||||
# ACME challenge para Let's Encrypt
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
# Redirect para HTTPS
|
||||
location / {
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
# Main HTTPS server configuration
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name bcards.site www.bcards.site;
|
||||
|
||||
# SSL certificates
|
||||
ssl_certificate /etc/letsencrypt/live/bcards.site/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/bcards.site/privkey.pem;
|
||||
|
||||
# Trusted certificate for OCSP stapling
|
||||
ssl_trusted_certificate /etc/letsencrypt/live/bcards.site/chain.pem;
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
|
||||
# DNS resolver
|
||||
resolver 8.8.8.8 8.8.4.4 valid=300s;
|
||||
resolver_timeout 5s;
|
||||
|
||||
# Rate limiting
|
||||
limit_req zone=general burst=20 nodelay;
|
||||
|
||||
# Health check endpoint (não passar pelo backend)
|
||||
location = /nginx-health {
|
||||
access_log off;
|
||||
return 200 "nginx ok\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
|
||||
# Backend health check
|
||||
location = /backend-health {
|
||||
access_log off;
|
||||
proxy_pass http://bcards_health/health;
|
||||
proxy_connect_timeout 5s;
|
||||
proxy_read_timeout 5s;
|
||||
}
|
||||
|
||||
# Main application proxy
|
||||
location / {
|
||||
# Proxy para o backend
|
||||
proxy_pass http://bcards_backend;
|
||||
|
||||
# Headers para proxy reverso
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
|
||||
# Timeouts
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_send_timeout 30s;
|
||||
proxy_read_timeout 30s;
|
||||
|
||||
# Buffer settings
|
||||
proxy_buffering on;
|
||||
proxy_buffer_size 4k;
|
||||
proxy_buffers 8 4k;
|
||||
|
||||
# Retry configuration
|
||||
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
|
||||
proxy_next_upstream_tries 2;
|
||||
proxy_next_upstream_timeout 10s;
|
||||
}
|
||||
|
||||
# Static files caching
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
|
||||
proxy_pass http://bcards_backend;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# Cache headers
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
|
||||
# Disable logging for static files
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# Error pages
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
}
|
||||
|
||||
# Servidor para monitoramento interno (apenas localhost)
|
||||
server {
|
||||
listen 127.0.0.1:8081;
|
||||
server_name localhost;
|
||||
|
||||
# Status do NGINX
|
||||
location /nginx_status {
|
||||
stub_status on;
|
||||
access_log off;
|
||||
allow 127.0.0.1;
|
||||
deny all;
|
||||
}
|
||||
|
||||
# Status detalhado dos upstreams
|
||||
location /upstream_status {
|
||||
access_log off;
|
||||
allow 127.0.0.1;
|
||||
deny all;
|
||||
|
||||
return 200 "Backend Status Check\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Stream configuration for TCP load balancing (se necessário)
|
||||
# stream {
|
||||
# upstream tcp_backend {
|
||||
# server 172.18.0.2:9000;
|
||||
# server 172.18.0.3:9000;
|
||||
# }
|
||||
#
|
||||
# server {
|
||||
# listen 9000;
|
||||
# proxy_pass tcp_backend;
|
||||
# proxy_timeout 1s;
|
||||
# proxy_responses 1;
|
||||
# }
|
||||
# }
|
||||
148
nginx/setup-ssl.sh
Normal file
148
nginx/setup-ssl.sh
Normal file
@ -0,0 +1,148 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script para configurar SSL com Let's Encrypt para bcards.site
|
||||
|
||||
set -e
|
||||
|
||||
DOMAIN="bcards.site"
|
||||
EMAIL="admin@bcards.site" # Altere para um email válido
|
||||
|
||||
# Cores para output
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
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}"
|
||||
}
|
||||
|
||||
# Verificar se Docker está rodando
|
||||
if ! docker info >/dev/null 2>&1; then
|
||||
error "Docker não está rodando"
|
||||
fi
|
||||
|
||||
# Criar diretórios necessários
|
||||
log "Criando diretórios para SSL..."
|
||||
sudo mkdir -p /etc/letsencrypt /var/www/certbot
|
||||
|
||||
# Criar configuração temporária do NGINX para validação
|
||||
log "Criando configuração temporária do NGINX..."
|
||||
cat > /tmp/nginx-temp.conf << EOF
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
server {
|
||||
listen 80;
|
||||
server_name $DOMAIN www.$DOMAIN;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://\$server_name\$request_uri;
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Parar NGINX se estiver rodando
|
||||
log "Parando NGINX existente..."
|
||||
docker stop bcards-nginx 2>/dev/null || true
|
||||
docker rm bcards-nginx 2>/dev/null || true
|
||||
|
||||
# Iniciar NGINX temporário para validação
|
||||
log "Iniciando NGINX temporário para validação Let's Encrypt..."
|
||||
docker run -d \
|
||||
--name nginx-temp \
|
||||
-p 80:80 \
|
||||
-v /tmp/nginx-temp.conf:/etc/nginx/nginx.conf:ro \
|
||||
-v /var/www/certbot:/var/www/certbot \
|
||||
nginx:alpine
|
||||
|
||||
# Aguardar NGINX inicializar
|
||||
sleep 5
|
||||
|
||||
# Obter certificado SSL
|
||||
log "Obtendo certificado SSL para $DOMAIN..."
|
||||
docker run --rm \
|
||||
-v /etc/letsencrypt:/etc/letsencrypt \
|
||||
-v /var/www/certbot:/var/www/certbot \
|
||||
certbot/certbot \
|
||||
certonly \
|
||||
--webroot \
|
||||
--webroot-path=/var/www/certbot \
|
||||
--email $EMAIL \
|
||||
--agree-tos \
|
||||
--no-eff-email \
|
||||
-d $DOMAIN \
|
||||
-d www.$DOMAIN
|
||||
|
||||
# Verificar se o certificado foi criado
|
||||
if [ ! -f "/etc/letsencrypt/live/$DOMAIN/fullchain.pem" ]; then
|
||||
error "Falha ao obter certificado SSL"
|
||||
fi
|
||||
|
||||
log "Certificado SSL obtido com sucesso!"
|
||||
|
||||
# Parar NGINX temporário
|
||||
docker stop nginx-temp
|
||||
docker rm nginx-temp
|
||||
|
||||
# Testar configuração NGINX principal
|
||||
log "Testando configuração NGINX principal..."
|
||||
docker run --rm \
|
||||
-v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \
|
||||
-v /etc/letsencrypt:/etc/letsencrypt:ro \
|
||||
nginx:alpine \
|
||||
nginx -t
|
||||
|
||||
log "Configuração NGINX válida!"
|
||||
|
||||
# Criar script de renovação automática
|
||||
log "Criando script de renovação automática..."
|
||||
cat > /tmp/renew-ssl.sh << 'EOF'
|
||||
#!/bin/bash
|
||||
|
||||
# Script de renovação automática de certificados SSL
|
||||
|
||||
docker run --rm \
|
||||
-v /etc/letsencrypt:/etc/letsencrypt \
|
||||
-v /var/www/certbot:/var/www/certbot \
|
||||
certbot/certbot renew
|
||||
|
||||
# Recarregar NGINX se certificados foram renovados
|
||||
if [ $? -eq 0 ]; then
|
||||
docker exec bcards-nginx nginx -s reload
|
||||
fi
|
||||
EOF
|
||||
|
||||
sudo mv /tmp/renew-ssl.sh /usr/local/bin/renew-ssl.sh
|
||||
sudo chmod +x /usr/local/bin/renew-ssl.sh
|
||||
|
||||
# Configurar cron para renovação automática
|
||||
log "Configurando renovação automática..."
|
||||
(crontab -l 2>/dev/null; echo "0 2 * * * /usr/local/bin/renew-ssl.sh >> /var/log/letsencrypt/renew.log 2>&1") | crontab -
|
||||
|
||||
# Criar diretório de logs
|
||||
sudo mkdir -p /var/log/letsencrypt
|
||||
|
||||
log "SSL configurado com sucesso!"
|
||||
log "Certificados localizados em: /etc/letsencrypt/live/$DOMAIN/"
|
||||
log "Renovação automática configurada para executar diariamente às 02:00"
|
||||
|
||||
# Mostrar informações do certificado
|
||||
log "Informações do certificado:"
|
||||
sudo openssl x509 -in /etc/letsencrypt/live/$DOMAIN/fullchain.pem -text -noout | grep -A 2 "Validity"
|
||||
33
redis/redis.conf
Normal file
33
redis/redis.conf
Normal file
@ -0,0 +1,33 @@
|
||||
# Redis configuration for BCards
|
||||
|
||||
# Network
|
||||
bind 0.0.0.0
|
||||
port 6379
|
||||
protected-mode no
|
||||
|
||||
# General
|
||||
daemonize no
|
||||
pidfile /var/run/redis_6379.pid
|
||||
loglevel notice
|
||||
logfile ""
|
||||
|
||||
# Memory
|
||||
maxmemory 256mb
|
||||
maxmemory-policy allkeys-lru
|
||||
|
||||
# Persistence
|
||||
save 900 1
|
||||
save 300 10
|
||||
save 60 10000
|
||||
|
||||
# Security
|
||||
# requirepass bcards123
|
||||
|
||||
# Performance
|
||||
tcp-keepalive 300
|
||||
timeout 0
|
||||
|
||||
# Append only mode
|
||||
appendonly yes
|
||||
appendfilename "appendonly.aof"
|
||||
appendfsync everysec
|
||||
337
scripts/cleanup.sh
Normal file
337
scripts/cleanup.sh
Normal file
@ -0,0 +1,337 @@
|
||||
#!/bin/bash
|
||||
|
||||
# BCards Cleanup Script
|
||||
# Limpeza de containers antigos e recursos não utilizados
|
||||
|
||||
set -e
|
||||
|
||||
# Configurações
|
||||
SERVER_IPS=("129.153.123.92" "129.146.116.218")
|
||||
SSH_USER="ubuntu"
|
||||
SERVICE_NAME="bcards-app"
|
||||
|
||||
# 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}"
|
||||
}
|
||||
|
||||
success() {
|
||||
echo -e "${GREEN}[SUCCESS] $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"
|
||||
}
|
||||
|
||||
# Função para executar comando apenas no manager
|
||||
run_manager() {
|
||||
local command=$1
|
||||
run_remote ${SERVER_IPS[0]} "$command"
|
||||
}
|
||||
|
||||
# Verificar conectividade
|
||||
check_connectivity() {
|
||||
log "Verificando conectividade com 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 "✓ Conectado: $server_ip"
|
||||
done
|
||||
}
|
||||
|
||||
# Mostrar uso atual de espaço
|
||||
show_disk_usage() {
|
||||
log "Verificando uso atual de disco..."
|
||||
|
||||
for server_ip in "${SERVER_IPS[@]}"; do
|
||||
info "Servidor $server_ip:"
|
||||
run_remote $server_ip "
|
||||
echo ' Espaço total em disco:'
|
||||
df -h / | tail -1 | awk '{print \" Total: \" \$2 \", Usado: \" \$3 \", Livre: \" \$4 \", Uso: \" \$5}'
|
||||
echo ' Espaço usado pelo Docker:'
|
||||
sudo docker system df 2>/dev/null || echo ' Docker não disponível'
|
||||
"
|
||||
done
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Listar containers e imagens antes da limpeza
|
||||
show_before_cleanup() {
|
||||
log "Status antes da limpeza..."
|
||||
|
||||
for server_ip in "${SERVER_IPS[@]}"; do
|
||||
info "Servidor $server_ip:"
|
||||
echo " Containers:"
|
||||
run_remote $server_ip "sudo docker ps -a --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.CreatedAt}}'" || true
|
||||
echo " Imagens:"
|
||||
run_remote $server_ip "sudo docker images --format 'table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}'" | head -10 || true
|
||||
echo ""
|
||||
done
|
||||
}
|
||||
|
||||
# Parar serviços específicos (se solicitado)
|
||||
stop_services() {
|
||||
if [[ "$1" == "--stop-services" ]]; then
|
||||
log "Parando serviços BCards..."
|
||||
|
||||
if run_manager "sudo docker service ls --filter name=${SERVICE_NAME}" | grep -q "${SERVICE_NAME}"; then
|
||||
run_manager "sudo docker service rm ${SERVICE_NAME}_app-server1 ${SERVICE_NAME}_app-server2" || true
|
||||
info "Serviços BCards parados"
|
||||
|
||||
# Aguardar containers pararem
|
||||
sleep 10
|
||||
else
|
||||
info "Nenhum serviço BCards encontrado"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Limpeza de containers parados
|
||||
cleanup_containers() {
|
||||
log "Limpando containers parados..."
|
||||
|
||||
for server_ip in "${SERVER_IPS[@]}"; do
|
||||
info "Limpando containers no servidor $server_ip..."
|
||||
|
||||
# Remover containers parados
|
||||
local stopped_containers=$(run_remote $server_ip "sudo docker ps -aq --filter 'status=exited'")
|
||||
if [ -n "$stopped_containers" ]; then
|
||||
run_remote $server_ip "sudo docker rm \$(sudo docker ps -aq --filter 'status=exited')" || true
|
||||
success " ✓ Containers parados removidos"
|
||||
else
|
||||
info " Nenhum container parado encontrado"
|
||||
fi
|
||||
|
||||
# Remover containers órfãos
|
||||
run_remote $server_ip "sudo docker container prune -f" || true
|
||||
done
|
||||
}
|
||||
|
||||
# Limpeza de imagens não utilizadas
|
||||
cleanup_images() {
|
||||
log "Limpando imagens não utilizadas..."
|
||||
|
||||
local keep_latest=${1:-true}
|
||||
|
||||
for server_ip in "${SERVER_IPS[@]}"; do
|
||||
info "Limpando imagens no servidor $server_ip..."
|
||||
|
||||
if [[ "$keep_latest" == "true" ]]; then
|
||||
# Remover apenas imagens dangling (sem tag)
|
||||
run_remote $server_ip "sudo docker image prune -f" || true
|
||||
success " ✓ Imagens dangling removidas"
|
||||
else
|
||||
# Remover todas as imagens não utilizadas
|
||||
run_remote $server_ip "sudo docker image prune -af" || true
|
||||
success " ✓ Todas as imagens não utilizadas removidas"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Limpeza de volumes não utilizados
|
||||
cleanup_volumes() {
|
||||
log "Limpando volumes não utilizados..."
|
||||
|
||||
for server_ip in "${SERVER_IPS[@]}"; do
|
||||
info "Limpando volumes no servidor $server_ip..."
|
||||
|
||||
local unused_volumes=$(run_remote $server_ip "sudo docker volume ls -qf dangling=true")
|
||||
if [ -n "$unused_volumes" ]; then
|
||||
run_remote $server_ip "sudo docker volume prune -f" || true
|
||||
success " ✓ Volumes não utilizados removidos"
|
||||
else
|
||||
info " Nenhum volume não utilizado encontrado"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Limpeza de redes não utilizadas
|
||||
cleanup_networks() {
|
||||
log "Limpando redes não utilizadas..."
|
||||
|
||||
for server_ip in "${SERVER_IPS[@]}"; do
|
||||
info "Limpando redes no servidor $server_ip..."
|
||||
|
||||
run_remote $server_ip "sudo docker network prune -f" || true
|
||||
success " ✓ Redes não utilizadas removidas"
|
||||
done
|
||||
}
|
||||
|
||||
# Limpeza de build cache
|
||||
cleanup_build_cache() {
|
||||
log "Limpando build cache..."
|
||||
|
||||
for server_ip in "${SERVER_IPS[@]}"; do
|
||||
info "Limpando build cache no servidor $server_ip..."
|
||||
|
||||
run_remote $server_ip "sudo docker builder prune -f" || true
|
||||
success " ✓ Build cache limpo"
|
||||
done
|
||||
}
|
||||
|
||||
# Limpeza de logs antigos
|
||||
cleanup_logs() {
|
||||
log "Limpando logs antigos..."
|
||||
|
||||
for server_ip in "${SERVER_IPS[@]}"; do
|
||||
info "Limpando logs no servidor $server_ip..."
|
||||
|
||||
# Limpar logs do Docker (mais de 7 dias)
|
||||
run_remote $server_ip "
|
||||
sudo find /var/lib/docker/containers/ -name '*.log' -type f -mtime +7 -delete 2>/dev/null || true
|
||||
sudo find /var/log/bcards/ -name '*.log' -type f -mtime +30 -delete 2>/dev/null || true
|
||||
sudo journalctl --vacuum-time=7d 2>/dev/null || true
|
||||
"
|
||||
success " ✓ Logs antigos removidos"
|
||||
done
|
||||
}
|
||||
|
||||
# Limpeza do sistema operacional
|
||||
cleanup_system() {
|
||||
if [[ "$1" == "--system" ]]; then
|
||||
log "Limpando sistema operacional..."
|
||||
|
||||
for server_ip in "${SERVER_IPS[@]}"; do
|
||||
info "Limpando sistema no servidor $server_ip..."
|
||||
|
||||
run_remote $server_ip "
|
||||
sudo apt-get autoremove -y 2>/dev/null || true
|
||||
sudo apt-get autoclean 2>/dev/null || true
|
||||
sudo apt-get clean 2>/dev/null || true
|
||||
"
|
||||
success " ✓ Sistema limpo"
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# Limpeza completa do Docker
|
||||
full_docker_cleanup() {
|
||||
if [[ "$1" == "--full" ]]; then
|
||||
warn "ATENÇÃO: Limpeza completa irá remover TUDO (containers, imagens, volumes, redes)"
|
||||
read -p "Tem certeza? Digite 'yes' para continuar: " confirm
|
||||
|
||||
if [[ "$confirm" == "yes" ]]; then
|
||||
log "Executando limpeza completa do Docker..."
|
||||
|
||||
for server_ip in "${SERVER_IPS[@]}"; do
|
||||
info "Limpeza completa no servidor $server_ip..."
|
||||
|
||||
run_remote $server_ip "
|
||||
sudo docker system prune -af --volumes
|
||||
"
|
||||
success " ✓ Limpeza completa executada"
|
||||
done
|
||||
else
|
||||
info "Limpeza completa cancelada"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Mostrar estatísticas após limpeza
|
||||
show_after_cleanup() {
|
||||
log "Status após limpeza..."
|
||||
|
||||
for server_ip in "${SERVER_IPS[@]}"; do
|
||||
info "Servidor $server_ip:"
|
||||
echo " Espaço em disco:"
|
||||
run_remote $server_ip "df -h / | tail -1 | awk '{print \" Total: \" \$2 \", Usado: \" \$3 \", Livre: \" \$4 \", Uso: \" \$5}'"
|
||||
|
||||
echo " Docker:"
|
||||
run_remote $server_ip "sudo docker system df 2>/dev/null || echo ' Docker não disponível'"
|
||||
|
||||
echo " Containers ativos:"
|
||||
local active_containers=$(run_remote $server_ip "sudo docker ps -q | wc -l")
|
||||
echo " $active_containers containers rodando"
|
||||
|
||||
echo " Imagens:"
|
||||
local images_count=$(run_remote $server_ip "sudo docker images -q | wc -l")
|
||||
echo " $images_count imagens armazenadas"
|
||||
echo ""
|
||||
done
|
||||
}
|
||||
|
||||
# Função principal
|
||||
main() {
|
||||
log "Iniciando limpeza da infraestrutura BCards..."
|
||||
|
||||
check_connectivity
|
||||
show_disk_usage
|
||||
show_before_cleanup
|
||||
|
||||
stop_services "$@"
|
||||
cleanup_containers
|
||||
cleanup_images "$2"
|
||||
cleanup_volumes
|
||||
cleanup_networks
|
||||
cleanup_build_cache
|
||||
cleanup_logs
|
||||
cleanup_system "$@"
|
||||
full_docker_cleanup "$@"
|
||||
|
||||
show_after_cleanup
|
||||
|
||||
success "Limpeza concluída!"
|
||||
}
|
||||
|
||||
# Função de ajuda
|
||||
show_help() {
|
||||
echo "BCards Cleanup Script"
|
||||
echo ""
|
||||
echo "Usage: $0 [OPTIONS]"
|
||||
echo ""
|
||||
echo "OPTIONS:"
|
||||
echo " --stop-services Para os serviços BCards antes da limpeza"
|
||||
echo " --system Inclui limpeza do sistema operacional (apt clean, etc)"
|
||||
echo " --full Limpeza completa (REMOVE TUDO - containers, imagens, volumes)"
|
||||
echo " --keep-all-images Mantém todas as imagens (remove apenas dangling)"
|
||||
echo " --help Mostra esta ajuda"
|
||||
echo ""
|
||||
echo "Operações de limpeza:"
|
||||
echo "- Remove containers parados"
|
||||
echo "- Remove imagens não utilizadas"
|
||||
echo "- Remove volumes órfãos"
|
||||
echo "- Remove redes não utilizadas"
|
||||
echo "- Limpa build cache do Docker"
|
||||
echo "- Remove logs antigos"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 # Limpeza básica"
|
||||
echo " $0 --stop-services # Para serviços e limpa"
|
||||
echo " $0 --system # Inclui limpeza do sistema"
|
||||
echo " $0 --full # Limpeza completa (cuidado!)"
|
||||
echo ""
|
||||
echo "Servers: ${SERVER_IPS[*]}"
|
||||
}
|
||||
|
||||
# Parse argumentos
|
||||
if [[ "$1" == "--help" || "$1" == "-h" ]]; then
|
||||
show_help
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Executar função principal
|
||||
main "$@"
|
||||
342
scripts/deploy-to-servers.sh
Normal file
342
scripts/deploy-to-servers.sh
Normal file
@ -0,0 +1,342 @@
|
||||
#!/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 "$@"
|
||||
207
scripts/fix-nginx-ssl.sh
Normal file
207
scripts/fix-nginx-ssl.sh
Normal file
@ -0,0 +1,207 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Fix NGINX Load Balancer SSL Configuration
|
||||
# Corrige problemas de SSL do NGINX Load Balancer
|
||||
|
||||
set -e
|
||||
|
||||
LOADBALANCER_IP="141.148.162.114"
|
||||
SSH_USER="ubuntu"
|
||||
DOMAIN="bcards.site"
|
||||
|
||||
# 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}"
|
||||
}
|
||||
|
||||
run_remote() {
|
||||
local server_ip=$1
|
||||
local command=$2
|
||||
ssh -o StrictHostKeyChecking=no ${SSH_USER}@${server_ip} "$command"
|
||||
}
|
||||
|
||||
# Etapa 1: Configurar NGINX apenas com HTTP
|
||||
fix_nginx_http() {
|
||||
log "Configurando NGINX apenas com HTTP..."
|
||||
|
||||
# Copiar configuração HTTP
|
||||
scp nginx/nginx-loadbalancer-http.conf ${SSH_USER}@${LOADBALANCER_IP}:/tmp/
|
||||
|
||||
run_remote $LOADBALANCER_IP "
|
||||
# Parar NGINX
|
||||
sudo systemctl stop nginx || true
|
||||
|
||||
# Backup da configuração atual
|
||||
sudo mkdir -p /etc/nginx/backup
|
||||
sudo cp /etc/nginx/sites-available/bcards /etc/nginx/backup/bcards-ssl.bak 2>/dev/null || true
|
||||
|
||||
# Instalar configuração HTTP
|
||||
sudo cp /tmp/nginx-loadbalancer-http.conf /etc/nginx/sites-available/bcards
|
||||
|
||||
# Criar diretório para ACME challenge
|
||||
sudo mkdir -p /var/www/html
|
||||
sudo chown www-data:www-data /var/www/html
|
||||
|
||||
# Testar configuração
|
||||
sudo nginx -t
|
||||
|
||||
# Iniciar NGINX
|
||||
sudo systemctl start nginx
|
||||
sudo systemctl enable nginx
|
||||
"
|
||||
|
||||
info "✓ NGINX configurado apenas com HTTP"
|
||||
}
|
||||
|
||||
# Etapa 2: Testar se o domínio está acessível
|
||||
test_domain_connectivity() {
|
||||
log "Testando conectividade do domínio..."
|
||||
|
||||
# Primeiro, verificar se os backends estão rodando
|
||||
info "Verificando se os backends estão rodando..."
|
||||
for backend in "129.153.123.92:8080" "129.146.116.218:8080"; do
|
||||
if curl -s --connect-timeout 5 "http://$backend/health" >/dev/null 2>&1; then
|
||||
info "✓ Backend $backend está respondendo"
|
||||
else
|
||||
warn "Backend $backend não está respondendo"
|
||||
fi
|
||||
done
|
||||
|
||||
# Testar conectividade local do load balancer
|
||||
info "Testando NGINX localmente no load balancer..."
|
||||
run_remote $LOADBALANCER_IP "
|
||||
# Testar localmente
|
||||
curl -s -o /dev/null -w 'Status: %{http_code}\n' http://localhost/health || echo 'Local test failed'
|
||||
"
|
||||
|
||||
# Aguardar propagação DNS
|
||||
info "Aguardando 30 segundos para propagação..."
|
||||
sleep 30
|
||||
|
||||
# Testar acesso externo
|
||||
info "Testando acesso externo ao domínio..."
|
||||
local status=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 10 "http://$DOMAIN/health" 2>/dev/null || echo "000")
|
||||
|
||||
if [ "$status" = "200" ]; then
|
||||
info "✓ Domínio $DOMAIN está acessível"
|
||||
return 0
|
||||
else
|
||||
warn "Domínio $DOMAIN não está acessível (status: $status)"
|
||||
|
||||
# Diagnóstico adicional
|
||||
info "Executando diagnóstico..."
|
||||
nslookup $DOMAIN || true
|
||||
info "Tentando ping..."
|
||||
ping -c 3 $DOMAIN || true
|
||||
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Etapa 3: Configurar SSL (apenas se domínio estiver acessível)
|
||||
setup_ssl_proper() {
|
||||
log "Configurando SSL com Let's Encrypt..."
|
||||
|
||||
run_remote $LOADBALANCER_IP "
|
||||
# Obter certificado SSL apenas para domínio principal (sem www)
|
||||
sudo certbot certonly --webroot -w /var/www/html -d $DOMAIN --non-interactive --agree-tos --email admin@$DOMAIN
|
||||
|
||||
# Verificar se certificado foi criado
|
||||
if [ ! -f /etc/letsencrypt/live/$DOMAIN/fullchain.pem ]; then
|
||||
echo 'Certificado não foi criado!'
|
||||
exit 1
|
||||
fi
|
||||
"
|
||||
|
||||
# Agora configurar NGINX com SSL
|
||||
scp nginx/nginx-loadbalancer.conf ${SSH_USER}@${LOADBALANCER_IP}:/tmp/
|
||||
|
||||
run_remote $LOADBALANCER_IP "
|
||||
# Atualizar configuração para SSL (remover www do server_name)
|
||||
sed -i 's/server_name bcards.site www.bcards.site;/server_name bcards.site;/g' /tmp/nginx-loadbalancer.conf
|
||||
|
||||
# Aplicar configuração SSL
|
||||
sudo cp /tmp/nginx-loadbalancer.conf /etc/nginx/sites-available/bcards
|
||||
|
||||
# Testar configuração
|
||||
sudo nginx -t
|
||||
|
||||
# Reload NGINX
|
||||
sudo systemctl reload nginx
|
||||
|
||||
# Configurar renovação automática (apenas se não existir)
|
||||
if ! crontab -l 2>/dev/null | grep -q certbot; then
|
||||
echo '0 2 * * * certbot renew --quiet && systemctl reload nginx' | sudo crontab -
|
||||
fi
|
||||
"
|
||||
|
||||
info "✓ SSL configurado com sucesso"
|
||||
}
|
||||
|
||||
# Função principal
|
||||
main() {
|
||||
log "Corrigindo configuração NGINX SSL para BCards..."
|
||||
|
||||
# Etapa 1: Configurar HTTP primeiro
|
||||
fix_nginx_http
|
||||
|
||||
# Etapa 2: Testar conectividade
|
||||
if test_domain_connectivity; then
|
||||
# Etapa 3: Se domínio estiver acessível, configurar SSL
|
||||
if [[ "$1" == "--ssl" ]]; then
|
||||
setup_ssl_proper
|
||||
info "Acesso: https://$DOMAIN"
|
||||
else
|
||||
info "SSL não configurado. Use --ssl para configurar."
|
||||
info "Acesso: http://$DOMAIN"
|
||||
fi
|
||||
else
|
||||
warn "Domínio não está acessível. Verifique:"
|
||||
warn "1. DNS está apontando para $LOADBALANCER_IP"
|
||||
warn "2. Backends estão rodando nas portas 8080"
|
||||
warn "3. Firewall permite tráfego HTTP (porta 80)"
|
||||
info "Por enquanto, acesso apenas local: http://$LOADBALANCER_IP"
|
||||
fi
|
||||
|
||||
log "Correção concluída!"
|
||||
}
|
||||
|
||||
# Mostrar ajuda
|
||||
if [[ "$1" == "--help" || "$1" == "-h" ]]; then
|
||||
echo "Fix NGINX Load Balancer SSL Configuration"
|
||||
echo ""
|
||||
echo "Usage: $0 [OPTIONS]"
|
||||
echo ""
|
||||
echo "OPTIONS:"
|
||||
echo " --ssl Configurar SSL após verificar conectividade"
|
||||
echo " --help Mostrar esta ajuda"
|
||||
echo ""
|
||||
echo "Este script:"
|
||||
echo "1. Configura NGINX apenas com HTTP primeiro"
|
||||
echo "2. Testa se o domínio está acessível"
|
||||
echo "3. Só configura SSL se domínio estiver funcionando"
|
||||
echo ""
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Executar função principal
|
||||
main "$@"
|
||||
196
scripts/setup-nginx-loadbalancer.sh
Normal file
196
scripts/setup-nginx-loadbalancer.sh
Normal file
@ -0,0 +1,196 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Setup NGINX Load Balancer for BCards
|
||||
# Configura NGINX para fazer load balance entre os servidores
|
||||
|
||||
set -e
|
||||
|
||||
LOADBALANCER_IP="141.148.162.114" # Usar primeiro servidor como load balancer
|
||||
SSH_USER="ubuntu"
|
||||
DOMAIN="bcards.site"
|
||||
|
||||
# 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
|
||||
check_connectivity() {
|
||||
log "Verificando conectividade com o load balancer..."
|
||||
|
||||
if ! ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no ${SSH_USER}@${LOADBALANCER_IP} "echo 'ok'" >/dev/null 2>&1; then
|
||||
error "Não foi possível conectar ao servidor $LOADBALANCER_IP"
|
||||
fi
|
||||
|
||||
info "✓ Conectividade OK"
|
||||
}
|
||||
|
||||
# Configurar NGINX como load balancer
|
||||
setup_nginx_loadbalancer() {
|
||||
log "Configurando NGINX Load Balancer..."
|
||||
|
||||
# Copiar arquivo de configuração
|
||||
scp nginx/nginx-loadbalancer.conf ${SSH_USER}@${LOADBALANCER_IP}:/tmp/
|
||||
|
||||
# Configurar NGINX
|
||||
run_remote $LOADBALANCER_IP "
|
||||
# Backup da configuração atual
|
||||
sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.backup 2>/dev/null || true
|
||||
|
||||
# Instalar configuração do load balancer
|
||||
sudo cp /tmp/nginx-loadbalancer.conf /etc/nginx/sites-available/bcards
|
||||
sudo ln -sf /etc/nginx/sites-available/bcards /etc/nginx/sites-enabled/
|
||||
|
||||
# Remover site padrão
|
||||
sudo rm -f /etc/nginx/sites-enabled/default
|
||||
|
||||
# Testar configuração
|
||||
sudo nginx -t
|
||||
|
||||
# Restart NGINX
|
||||
sudo systemctl restart nginx
|
||||
sudo systemctl enable nginx
|
||||
"
|
||||
|
||||
info "✓ NGINX Load Balancer configurado"
|
||||
}
|
||||
|
||||
# Configurar SSL com Let's Encrypt
|
||||
setup_ssl() {
|
||||
log "Configurando SSL com Let's Encrypt..."
|
||||
|
||||
run_remote $LOADBALANCER_IP "
|
||||
# Parar NGINX temporariamente para certbot
|
||||
sudo systemctl stop nginx
|
||||
|
||||
# Obter certificado SSL
|
||||
sudo certbot certonly --standalone -d $DOMAIN -d www.$DOMAIN --non-interactive --agree-tos --email admin@$DOMAIN
|
||||
|
||||
# Restart NGINX
|
||||
sudo systemctl start nginx
|
||||
|
||||
# Configurar renovação automática
|
||||
echo '0 2 * * * root certbot renew --quiet && systemctl reload nginx' | sudo tee -a /etc/crontab
|
||||
"
|
||||
|
||||
info "✓ SSL configurado com Let's Encrypt"
|
||||
}
|
||||
|
||||
# Configurar firewall para load balancer
|
||||
configure_firewall() {
|
||||
log "Configurando firewall para load balancer..."
|
||||
|
||||
run_remote $LOADBALANCER_IP "
|
||||
sudo ufw allow 80/tcp
|
||||
sudo ufw allow 443/tcp
|
||||
sudo ufw reload
|
||||
"
|
||||
|
||||
info "✓ Firewall configurado"
|
||||
}
|
||||
|
||||
# Testar load balancer
|
||||
test_loadbalancer() {
|
||||
log "Testando load balancer..."
|
||||
|
||||
# Teste HTTP (deve redirecionar para HTTPS)
|
||||
info "Testando redirecionamento HTTP para HTTPS..."
|
||||
local http_status=$(curl -s -o /dev/null -w "%{http_code}" -L http://$DOMAIN/health)
|
||||
if [ "$http_status" = "200" ]; then
|
||||
info "✓ Redirecionamento HTTP->HTTPS funcionando"
|
||||
else
|
||||
warn "HTTP test retornou status: $http_status"
|
||||
fi
|
||||
|
||||
# Teste HTTPS
|
||||
info "Testando HTTPS..."
|
||||
local https_status=$(curl -s -o /dev/null -w "%{http_code}" -k https://$DOMAIN/health)
|
||||
if [ "$https_status" = "200" ]; then
|
||||
info "✓ HTTPS funcionando"
|
||||
else
|
||||
warn "HTTPS test retornou status: $https_status"
|
||||
fi
|
||||
|
||||
# Mostrar logs do NGINX
|
||||
info "Últimos logs do NGINX:"
|
||||
run_remote $LOADBALANCER_IP "sudo tail -n 20 /var/log/nginx/bcards_access.log" || true
|
||||
run_remote $LOADBALANCER_IP "sudo tail -n 10 /var/log/nginx/bcards_error.log" || true
|
||||
}
|
||||
|
||||
# Função principal
|
||||
main() {
|
||||
log "Configurando NGINX Load Balancer para BCards..."
|
||||
|
||||
check_connectivity
|
||||
setup_nginx_loadbalancer
|
||||
configure_firewall
|
||||
|
||||
if [[ "$1" == "--ssl" ]]; then
|
||||
setup_ssl
|
||||
else
|
||||
warn "SSL não configurado. Use --ssl para configurar automaticamente."
|
||||
info "Para configurar SSL manualmente:"
|
||||
info " sudo certbot --nginx -d $DOMAIN -d www.$DOMAIN"
|
||||
fi
|
||||
|
||||
test_loadbalancer
|
||||
|
||||
log "Setup do Load Balancer concluído!"
|
||||
info "Load Balancer: $LOADBALANCER_IP"
|
||||
info "Domain: $DOMAIN"
|
||||
info "Backends: 129.153.123.92:8080, 129.146.116.218:8080"
|
||||
|
||||
if [[ "$1" == "--ssl" ]]; then
|
||||
info "Acesso: https://$DOMAIN"
|
||||
else
|
||||
info "Acesso: http://$DOMAIN (configurar SSL depois)"
|
||||
fi
|
||||
}
|
||||
|
||||
# Mostrar help
|
||||
if [[ "$1" == "--help" || "$1" == "-h" ]]; then
|
||||
echo "Setup NGINX Load Balancer for BCards"
|
||||
echo ""
|
||||
echo "Usage: $0 [OPTIONS]"
|
||||
echo ""
|
||||
echo "OPTIONS:"
|
||||
echo " --ssl Configurar SSL automaticamente com Let's Encrypt"
|
||||
echo " --help Mostrar esta ajuda"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 # Setup sem SSL"
|
||||
echo " $0 --ssl # Setup com SSL automático"
|
||||
echo ""
|
||||
echo "Load Balancer: $LOADBALANCER_IP"
|
||||
echo "Domain: $DOMAIN"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Executar função principal
|
||||
main "$@"
|
||||
206
scripts/setup-servers.sh
Normal file
206
scripts/setup-servers.sh
Normal file
@ -0,0 +1,206 @@
|
||||
#!/bin/bash
|
||||
|
||||
# BCards Infrastructure Setup Script
|
||||
# Configura os servidores OCI para o ambiente de produção
|
||||
|
||||
set -e
|
||||
|
||||
SERVER_IPS=("141.148.162.114" "129.146.116.218")
|
||||
SSH_USER="ubuntu"
|
||||
|
||||
# Cores para output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
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}"
|
||||
}
|
||||
|
||||
# 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"
|
||||
}
|
||||
|
||||
# Instalar Docker se não existir
|
||||
install_docker() {
|
||||
local server_ip=$1
|
||||
log "Verificando Docker no servidor $server_ip..."
|
||||
|
||||
if run_remote $server_ip "command -v docker >/dev/null 2>&1"; then
|
||||
log "Docker já está instalado no servidor $server_ip"
|
||||
else
|
||||
log "Instalando Docker no servidor $server_ip..."
|
||||
run_remote $server_ip "
|
||||
sudo apt-get update &&
|
||||
sudo apt-get install -y ca-certificates curl gnupg lsb-release &&
|
||||
sudo mkdir -p /etc/apt/keyrings &&
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg &&
|
||||
echo \"deb [arch=\$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \$(lsb_release -cs) stable\" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null &&
|
||||
sudo apt-get update &&
|
||||
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin &&
|
||||
sudo usermod -aG docker $SSH_USER
|
||||
"
|
||||
log "Docker instalado com sucesso no servidor $server_ip"
|
||||
fi
|
||||
}
|
||||
|
||||
# Configurar NGINX para load balancing
|
||||
setup_nginx() {
|
||||
local server_ip=$1
|
||||
log "Configurando NGINX no servidor $server_ip..."
|
||||
|
||||
run_remote $server_ip "
|
||||
sudo apt-get install -y nginx &&
|
||||
sudo systemctl enable nginx &&
|
||||
sudo systemctl start nginx
|
||||
"
|
||||
|
||||
log "NGINX configurado no servidor $server_ip"
|
||||
}
|
||||
|
||||
# Criar redes Docker locais
|
||||
setup_docker_networks() {
|
||||
local server_ip=$1
|
||||
log "Configurando redes Docker no servidor $server_ip..."
|
||||
|
||||
run_remote $server_ip "
|
||||
sudo docker network create --driver bridge bcards-network 2>/dev/null || true
|
||||
"
|
||||
}
|
||||
|
||||
# Configurar firewall básico
|
||||
configure_firewall() {
|
||||
local server_ip=$1
|
||||
log "Configurando firewall no servidor $server_ip..."
|
||||
|
||||
run_remote $server_ip "
|
||||
sudo ufw --force reset &&
|
||||
sudo ufw default deny incoming &&
|
||||
sudo ufw default allow outgoing &&
|
||||
sudo ufw allow ssh &&
|
||||
sudo ufw allow 80/tcp &&
|
||||
sudo ufw allow 443/tcp &&
|
||||
sudo ufw --force enable
|
||||
"
|
||||
|
||||
log "Firewall configurado no servidor $server_ip"
|
||||
}
|
||||
|
||||
# Instalar utilitários essenciais
|
||||
install_utilities() {
|
||||
local server_ip=$1
|
||||
log "Instalando utilitários no servidor $server_ip..."
|
||||
|
||||
run_remote $server_ip "
|
||||
sudo apt-get update &&
|
||||
sudo apt-get install -y \
|
||||
curl \
|
||||
wget \
|
||||
git \
|
||||
htop \
|
||||
nano \
|
||||
unzip \
|
||||
jq \
|
||||
certbot \
|
||||
python3-certbot-nginx
|
||||
"
|
||||
}
|
||||
|
||||
# Criar diretórios necessários
|
||||
create_directories() {
|
||||
local server_ip=$1
|
||||
log "Criando diretórios no servidor $server_ip..."
|
||||
|
||||
run_remote $server_ip "
|
||||
mkdir -p ~/bcards/{nginx,logs,data,ssl} &&
|
||||
sudo mkdir -p /var/log/bcards &&
|
||||
sudo chown -R $SSH_USER:$SSH_USER /var/log/bcards
|
||||
"
|
||||
}
|
||||
|
||||
# Configurar log rotation
|
||||
setup_log_rotation() {
|
||||
local server_ip=$1
|
||||
log "Configurando rotação de logs no servidor $server_ip..."
|
||||
|
||||
run_remote $server_ip "
|
||||
sudo tee /etc/logrotate.d/bcards > /dev/null <<EOF
|
||||
/var/log/bcards/*.log {
|
||||
daily
|
||||
missingok
|
||||
rotate 30
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 644 $SSH_USER $SSH_USER
|
||||
}
|
||||
EOF
|
||||
"
|
||||
}
|
||||
|
||||
# Função principal
|
||||
main() {
|
||||
log "Iniciando setup da infraestrutura BCards..."
|
||||
|
||||
# Verificar conectividade com os servidores
|
||||
for server_ip in "${SERVER_IPS[@]}"; do
|
||||
log "Testando conectividade com $server_ip..."
|
||||
if ! ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no ${SSH_USER}@${server_ip} "echo 'Conectado com sucesso'" >/dev/null 2>&1; then
|
||||
error "Não foi possível conectar ao servidor $server_ip"
|
||||
fi
|
||||
done
|
||||
|
||||
# Setup em cada servidor
|
||||
for server_ip in "${SERVER_IPS[@]}"; do
|
||||
log "Configurando servidor $server_ip..."
|
||||
|
||||
install_utilities $server_ip
|
||||
install_docker $server_ip
|
||||
configure_firewall $server_ip
|
||||
create_directories $server_ip
|
||||
setup_log_rotation $server_ip
|
||||
setup_docker_networks $server_ip
|
||||
setup_nginx $server_ip
|
||||
done
|
||||
|
||||
log "Setup completo! Servidores prontos para deploy."
|
||||
log "Servidor 1: ${SERVER_IPS[0]}"
|
||||
log "Servidor 2: ${SERVER_IPS[1]}"
|
||||
|
||||
log "Cada servidor rodará containers Docker independentes"
|
||||
log "NGINX fará load balance entre os servidores"
|
||||
}
|
||||
|
||||
# Verificar se o script está sendo executado com argumentos
|
||||
if [[ "$1" == "--help" || "$1" == "-h" ]]; then
|
||||
echo "BCards Infrastructure Setup Script"
|
||||
echo "Usage: $0"
|
||||
echo ""
|
||||
echo "Este script configura os servidores OCI para o ambiente BCards:"
|
||||
echo "- Instala Docker e utilitários"
|
||||
echo "- Configura Docker Swarm"
|
||||
echo "- Configura firewall básico"
|
||||
echo "- Cria estrutura de diretórios"
|
||||
echo ""
|
||||
echo "Servidores configurados:"
|
||||
for server_ip in "${SERVER_IPS[@]}"; do
|
||||
echo " - $server_ip"
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Executar função principal
|
||||
main "$@"
|
||||
374
scripts/test-connectivity.sh
Normal file
374
scripts/test-connectivity.sh
Normal file
@ -0,0 +1,374 @@
|
||||
#!/bin/bash
|
||||
|
||||
# BCards Connectivity Test Script
|
||||
# Testa conectividade e saúde dos serviços
|
||||
|
||||
set -e
|
||||
|
||||
# Configurações
|
||||
SERVER_IPS=("141.148.162.114" "129.146.116.218")
|
||||
SSH_USER="ubuntu"
|
||||
DOMAIN="bcards.site"
|
||||
SERVICE_NAME="bcards-app"
|
||||
|
||||
# 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}"
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo -e "${YELLOW}[WARNING] $1${NC}"
|
||||
}
|
||||
|
||||
info() {
|
||||
echo -e "${BLUE}[INFO] $1${NC}"
|
||||
}
|
||||
|
||||
success() {
|
||||
echo -e "${GREEN}[SUCCESS] $1${NC}"
|
||||
}
|
||||
|
||||
# Função para executar comando em servidor remoto
|
||||
run_remote() {
|
||||
local server_ip=$1
|
||||
local command=$2
|
||||
ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no ${SSH_USER}@${server_ip} "$command" 2>/dev/null
|
||||
}
|
||||
|
||||
# Teste de conectividade SSH
|
||||
test_ssh_connectivity() {
|
||||
log "Testando conectividade SSH..."
|
||||
|
||||
local passed=0
|
||||
local total=${#SERVER_IPS[@]}
|
||||
|
||||
for server_ip in "${SERVER_IPS[@]}"; do
|
||||
if run_remote $server_ip "echo 'SSH OK'" >/dev/null 2>&1; then
|
||||
success "✓ SSH conectado: $server_ip"
|
||||
((passed++))
|
||||
else
|
||||
error "✗ SSH falhou: $server_ip"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
info "SSH Connectivity: $passed/$total servidores"
|
||||
}
|
||||
|
||||
# Teste de status do Docker
|
||||
test_docker_status() {
|
||||
log "Testando status do Docker..."
|
||||
|
||||
local passed=0
|
||||
local total=${#SERVER_IPS[@]}
|
||||
|
||||
for server_ip in "${SERVER_IPS[@]}"; do
|
||||
if run_remote $server_ip "sudo docker info" >/dev/null 2>&1; then
|
||||
success "✓ Docker ativo: $server_ip"
|
||||
((passed++))
|
||||
else
|
||||
error "✗ Docker inativo: $server_ip"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
info "Docker Status: $passed/$total servidores"
|
||||
}
|
||||
|
||||
# Teste de status do Docker Swarm
|
||||
test_swarm_status() {
|
||||
log "Testando status do Docker Swarm..."
|
||||
|
||||
local manager_ip=${SERVER_IPS[0]}
|
||||
|
||||
if run_remote $manager_ip "sudo docker node ls" >/dev/null 2>&1; then
|
||||
success "✓ Docker Swarm ativo"
|
||||
|
||||
# Mostrar status dos nodes
|
||||
info "Status dos nodes:"
|
||||
run_remote $manager_ip "sudo docker node ls" || true
|
||||
else
|
||||
error "✗ Docker Swarm inativo"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Teste de serviços Docker
|
||||
test_docker_services() {
|
||||
log "Testando serviços Docker..."
|
||||
|
||||
local manager_ip=${SERVER_IPS[0]}
|
||||
|
||||
if run_remote $manager_ip "sudo docker service ls" >/dev/null 2>&1; then
|
||||
info "Serviços ativos:"
|
||||
run_remote $manager_ip "sudo docker service ls" || true
|
||||
|
||||
# Verificar serviços específicos do BCards
|
||||
if run_remote $manager_ip "sudo docker service ls --filter name=${SERVICE_NAME}" | grep -q "${SERVICE_NAME}"; then
|
||||
success "✓ Serviços BCards encontrados"
|
||||
|
||||
# Status detalhado dos serviços BCards
|
||||
info "Status detalhado dos serviços BCards:"
|
||||
run_remote $manager_ip "sudo docker service ps ${SERVICE_NAME}_app-server1 --no-trunc" || true
|
||||
run_remote $manager_ip "sudo docker service ps ${SERVICE_NAME}_app-server2 --no-trunc" || true
|
||||
else
|
||||
warn "Serviços BCards não encontrados"
|
||||
fi
|
||||
else
|
||||
error "✗ Falha ao listar serviços Docker"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Teste de health checks internos
|
||||
test_internal_health() {
|
||||
log "Testando health checks internos..."
|
||||
|
||||
for server_ip in "${SERVER_IPS[@]}"; do
|
||||
info "Testando servidor $server_ip..."
|
||||
|
||||
# Verificar se há containers rodando
|
||||
local containers=$(run_remote $server_ip "sudo docker ps --filter status=running --format '{{.Names}}'" | wc -l)
|
||||
info " Containers rodando: $containers"
|
||||
|
||||
# Teste de conectividade de rede interna
|
||||
if run_remote $server_ip "sudo docker network ls | grep bcards" >/dev/null 2>&1; then
|
||||
success " ✓ Rede bcards-network existe"
|
||||
else
|
||||
warn " ✗ Rede bcards-network não encontrada"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Teste de conectividade externa HTTP/HTTPS
|
||||
test_external_connectivity() {
|
||||
log "Testando conectividade externa..."
|
||||
|
||||
# Teste HTTP
|
||||
info "Testando HTTP..."
|
||||
if curl -f -s --max-time 10 "http://$DOMAIN/nginx-health" >/dev/null 2>&1; then
|
||||
success "✓ HTTP funcionando (http://$DOMAIN)"
|
||||
else
|
||||
error "✗ HTTP falhou (http://$DOMAIN)"
|
||||
fi
|
||||
|
||||
# Teste HTTPS
|
||||
info "Testando HTTPS..."
|
||||
if curl -f -s --max-time 10 "https://$DOMAIN/nginx-health" >/dev/null 2>&1; then
|
||||
success "✓ HTTPS funcionando (https://$DOMAIN)"
|
||||
else
|
||||
warn "✗ HTTPS falhou (https://$DOMAIN)"
|
||||
fi
|
||||
|
||||
# Teste health check da aplicação
|
||||
info "Testando health check da aplicação..."
|
||||
if curl -f -s --max-time 10 "http://$DOMAIN/health" >/dev/null 2>&1; then
|
||||
success "✓ Health check da aplicação passou"
|
||||
else
|
||||
error "✗ Health check da aplicação falhou"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Teste de load balancing
|
||||
test_load_balancing() {
|
||||
log "Testando load balancing..."
|
||||
|
||||
local servers_found=()
|
||||
|
||||
for i in {1..10}; do
|
||||
local response=$(curl -s --max-time 5 "http://$DOMAIN/server-info" 2>/dev/null | jq -r '.ServerName' 2>/dev/null || echo "Error")
|
||||
|
||||
if [[ "$response" != "Error" && "$response" != "null" ]]; then
|
||||
servers_found+=("$response")
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
done
|
||||
|
||||
if [ ${#servers_found[@]} -gt 0 ]; then
|
||||
local unique_servers=$(printf '%s\n' "${servers_found[@]}" | sort -u | wc -l)
|
||||
|
||||
info "Servidores detectados em 10 requests:"
|
||||
printf '%s\n' "${servers_found[@]}" | sort | uniq -c
|
||||
|
||||
if [ $unique_servers -gt 1 ]; then
|
||||
success "✓ Load balancing funcionando ($unique_servers servidores diferentes)"
|
||||
else
|
||||
warn "Load balancing pode não estar funcionando (apenas 1 servidor detectado)"
|
||||
fi
|
||||
else
|
||||
error "✗ Falha ao testar load balancing"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Teste de DNS
|
||||
test_dns_resolution() {
|
||||
log "Testando resolução DNS..."
|
||||
|
||||
if nslookup $DOMAIN >/dev/null 2>&1; then
|
||||
local ip=$(nslookup $DOMAIN | grep -A1 "Name:" | tail -1 | awk '{print $2}')
|
||||
success "✓ DNS funcionando: $DOMAIN -> $ip"
|
||||
else
|
||||
error "✗ Falha na resolução DNS para $DOMAIN"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Teste de certificado SSL
|
||||
test_ssl_certificate() {
|
||||
log "Testando certificado SSL..."
|
||||
|
||||
if command -v openssl >/dev/null 2>&1; then
|
||||
local ssl_info=$(echo | timeout 10 openssl s_client -servername $DOMAIN -connect $DOMAIN:443 2>/dev/null | openssl x509 -noout -dates 2>/dev/null)
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
success "✓ Certificado SSL válido"
|
||||
info "Informações do certificado:"
|
||||
echo "$ssl_info" | sed 's/^/ /'
|
||||
else
|
||||
warn "Certificado SSL não encontrado ou inválido"
|
||||
fi
|
||||
else
|
||||
warn "OpenSSL não disponível para teste de certificado"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Mostrar métricas de performance
|
||||
show_performance_metrics() {
|
||||
log "Coletando métricas de performance..."
|
||||
|
||||
for server_ip in "${SERVER_IPS[@]}"; do
|
||||
info "Métricas do servidor $server_ip:"
|
||||
|
||||
# CPU e Memória
|
||||
local cpu_mem=$(run_remote $server_ip "top -bn1 | grep 'Cpu(s)' | awk '{print \$2}' | awk -F'%' '{print \$1}'; free -m | awk 'NR==2{printf \"%.1f%%\", \$3*100/\$2}'")
|
||||
info " CPU/Memória: $cpu_mem"
|
||||
|
||||
# Disk usage
|
||||
local disk=$(run_remote $server_ip "df -h / | awk 'NR==2 {print \$5}'")
|
||||
info " Uso do disco: $disk"
|
||||
|
||||
# Docker stats
|
||||
local docker_containers=$(run_remote $server_ip "sudo docker ps --format 'table {{.Names}}\t{{.Status}}' | tail -n +2 | wc -l")
|
||||
info " Containers Docker ativos: $docker_containers"
|
||||
done
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Gerar relatório detalhado
|
||||
generate_report() {
|
||||
local timestamp=$(date +'%Y-%m-%d %H:%M:%S')
|
||||
local report_file="connectivity-report-$(date +'%Y%m%d_%H%M%S').txt"
|
||||
|
||||
log "Gerando relatório detalhado..."
|
||||
|
||||
{
|
||||
echo "BCards Infrastructure Connectivity Report"
|
||||
echo "Generated: $timestamp"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
echo "Infrastructure Overview:"
|
||||
echo "- Domain: $DOMAIN"
|
||||
echo "- Servers: ${SERVER_IPS[*]}"
|
||||
echo "- Service: $SERVICE_NAME"
|
||||
echo ""
|
||||
|
||||
echo "Test Results Summary:"
|
||||
echo "- SSH Connectivity: $(test_ssh_connectivity 2>&1 | grep -c "SSH OK")/${#SERVER_IPS[@]} servers"
|
||||
echo "- Docker Status: $(test_docker_status 2>&1 | grep -c "Docker ativo")/${#SERVER_IPS[@]} servers"
|
||||
echo "- External HTTP: $(curl -f -s "http://$DOMAIN/nginx-health" >/dev/null 2>&1 && echo "PASS" || echo "FAIL")"
|
||||
echo "- External HTTPS: $(curl -f -s "https://$DOMAIN/nginx-health" >/dev/null 2>&1 && echo "PASS" || echo "FAIL")"
|
||||
echo "- App Health Check: $(curl -f -s "http://$DOMAIN/health" >/dev/null 2>&1 && echo "PASS" || echo "FAIL")"
|
||||
|
||||
} > $report_file
|
||||
|
||||
info "Relatório salvo em: $report_file"
|
||||
}
|
||||
|
||||
# Função principal
|
||||
main() {
|
||||
log "Iniciando testes de conectividade BCards..."
|
||||
echo ""
|
||||
|
||||
test_ssh_connectivity
|
||||
test_docker_status
|
||||
test_swarm_status
|
||||
test_docker_services
|
||||
test_internal_health
|
||||
test_dns_resolution
|
||||
test_external_connectivity
|
||||
test_load_balancing
|
||||
test_ssl_certificate
|
||||
show_performance_metrics
|
||||
|
||||
if [[ "$1" == "--report" ]]; then
|
||||
generate_report
|
||||
fi
|
||||
|
||||
log "Testes de conectividade concluídos!"
|
||||
}
|
||||
|
||||
# Função de ajuda
|
||||
show_help() {
|
||||
echo "BCards Connectivity Test Script"
|
||||
echo ""
|
||||
echo "Usage: $0 [OPTIONS]"
|
||||
echo ""
|
||||
echo "OPTIONS:"
|
||||
echo " --report Gera relatório detalhado em arquivo"
|
||||
echo " --help Mostra esta ajuda"
|
||||
echo ""
|
||||
echo "Este script testa:"
|
||||
echo "- Conectividade SSH com os servidores"
|
||||
echo "- Status do Docker e Docker Swarm"
|
||||
echo "- Saúde dos serviços em execução"
|
||||
echo "- Conectividade HTTP/HTTPS externa"
|
||||
echo "- Funcionamento do load balancing"
|
||||
echo "- Resolução DNS e certificados SSL"
|
||||
echo "- Métricas de performance dos servidores"
|
||||
echo ""
|
||||
echo "Servers: ${SERVER_IPS[*]}"
|
||||
echo "Domain: $DOMAIN"
|
||||
}
|
||||
|
||||
# Parse argumentos
|
||||
if [[ "$1" == "--help" || "$1" == "-h" ]]; then
|
||||
show_help
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Verificar dependências
|
||||
if ! command -v curl >/dev/null 2>&1; then
|
||||
error "curl não está instalado"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v jq >/dev/null 2>&1; then
|
||||
warn "jq não está instalado - alguns testes serão limitados"
|
||||
fi
|
||||
|
||||
# Executar função principal
|
||||
main "$@"
|
||||
14
test-app/BCardsTestApp.csproj
Normal file
14
test-app/BCardsTestApp.csproj
Normal file
@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
47
test-app/Controllers/HomeController.cs
Normal file
47
test-app/Controllers/HomeController.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace BCardsTestApp.Controllers;
|
||||
|
||||
public class HomeController : Controller
|
||||
{
|
||||
private readonly ILogger<HomeController> _logger;
|
||||
|
||||
public HomeController(ILogger<HomeController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public IActionResult Index()
|
||||
{
|
||||
var serverName = Environment.GetEnvironmentVariable("SERVER_NAME") ?? "Unknown Server";
|
||||
var serverColor = Environment.GetEnvironmentVariable("SERVER_COLOR") ?? "#007bff";
|
||||
|
||||
ViewBag.ServerName = serverName;
|
||||
ViewBag.ServerColor = serverColor;
|
||||
ViewBag.Hostname = Environment.MachineName;
|
||||
ViewBag.Timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss UTC");
|
||||
|
||||
_logger.LogInformation("Home page accessed from server {ServerName}", serverName);
|
||||
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult About()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public IActionResult Error()
|
||||
{
|
||||
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
||||
}
|
||||
}
|
||||
|
||||
public class ErrorViewModel
|
||||
{
|
||||
public string? RequestId { get; set; }
|
||||
|
||||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||
}
|
||||
51
test-app/Dockerfile
Normal file
51
test-app/Dockerfile
Normal file
@ -0,0 +1,51 @@
|
||||
# BCards Test App - Multi-stage Docker build com suporte ARM64
|
||||
FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||
WORKDIR /app
|
||||
EXPOSE 8080
|
||||
|
||||
# Criar usuário não-root para segurança
|
||||
RUN addgroup --group appgroup --gid 1001 && \
|
||||
adduser --uid 1001 --gid 1001 --disabled-password --gecos "" appuser
|
||||
|
||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
ARG TARGETARCH
|
||||
WORKDIR /src
|
||||
|
||||
# Copiar arquivo de projeto e restaurar dependências
|
||||
COPY ["BCardsTestApp.csproj", "."]
|
||||
RUN dotnet restore "BCardsTestApp.csproj"
|
||||
|
||||
# Copiar código fonte e compilar
|
||||
COPY . .
|
||||
RUN dotnet build "BCardsTestApp.csproj" -c Release -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
RUN dotnet publish "BCardsTestApp.csproj" -c Release -o /app/publish /p:UseAppHost=false -a $TARGETARCH
|
||||
|
||||
# Imagem final
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
|
||||
# Copiar aplicação compilada
|
||||
COPY --from=publish /app/publish .
|
||||
|
||||
# Configurar usuário não-root
|
||||
RUN chown -R appuser:appgroup /app
|
||||
USER appuser
|
||||
|
||||
# Labels para metadados
|
||||
LABEL maintainer="BCards Team"
|
||||
LABEL version="1.0"
|
||||
LABEL description="BCards Test Application for Infrastructure Testing"
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost:8080/health || exit 1
|
||||
|
||||
# Configurar variáveis de ambiente padrão
|
||||
ENV ASPNETCORE_ENVIRONMENT=Production
|
||||
ENV ASPNETCORE_URLS=http://+:8080
|
||||
ENV SERVER_NAME="Unknown Server"
|
||||
ENV SERVER_COLOR="#007bff"
|
||||
|
||||
ENTRYPOINT ["dotnet", "BCardsTestApp.dll"]
|
||||
51
test-app/Program.cs
Normal file
51
test-app/Program.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Configurar para escutar na porta 8080
|
||||
builder.WebHost.UseUrls("http://0.0.0.0:8080");
|
||||
|
||||
// Configurar serviços
|
||||
builder.Services.AddControllersWithViews();
|
||||
builder.Services.AddHealthChecks();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configurar headers para proxy reverso
|
||||
app.UseForwardedHeaders(new ForwardedHeadersOptions
|
||||
{
|
||||
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
|
||||
});
|
||||
|
||||
if (!app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseExceptionHandler("/Home/Error");
|
||||
}
|
||||
|
||||
app.UseStaticFiles();
|
||||
app.UseRouting();
|
||||
|
||||
// Health check endpoint
|
||||
app.MapHealthChecks("/health");
|
||||
|
||||
// Endpoint para identificar o servidor
|
||||
app.MapGet("/server-info", () =>
|
||||
{
|
||||
var serverName = Environment.GetEnvironmentVariable("SERVER_NAME") ?? "Unknown";
|
||||
var hostname = Environment.MachineName;
|
||||
var timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss UTC");
|
||||
|
||||
return Results.Json(new
|
||||
{
|
||||
ServerName = serverName,
|
||||
Hostname = hostname,
|
||||
Timestamp = timestamp,
|
||||
Environment = app.Environment.EnvironmentName
|
||||
});
|
||||
});
|
||||
|
||||
app.MapControllerRoute(
|
||||
name: "default",
|
||||
pattern: "{controller=Home}/{action=Index}/{id?}");
|
||||
|
||||
app.Run();
|
||||
103
test-app/Views/Home/About.cshtml
Normal file
103
test-app/Views/Home/About.cshtml
Normal file
@ -0,0 +1,103 @@
|
||||
@{
|
||||
ViewData["Title"] = "About";
|
||||
}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2><i class="fas fa-info-circle"></i> About BCards Infrastructure</h2>
|
||||
<hr>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Infrastructure Overview</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h6>Architecture Components:</h6>
|
||||
<ul>
|
||||
<li><strong>Load Balancer:</strong> NGINX reverse proxy with SSL termination</li>
|
||||
<li><strong>Application Servers:</strong> 2x OCI instances running Docker containers</li>
|
||||
<li><strong>Container Orchestration:</strong> Docker Swarm for service management</li>
|
||||
<li><strong>Domain:</strong> bcards.site with automatic SSL certificates</li>
|
||||
<li><strong>Registry:</strong> Private container registry at registry.redecarneir.us</li>
|
||||
</ul>
|
||||
|
||||
<h6 class="mt-4">Key Features:</h6>
|
||||
<ul>
|
||||
<li>Zero-downtime deployments</li>
|
||||
<li>Automatic health checks and failover</li>
|
||||
<li>Centralized logging and monitoring</li>
|
||||
<li>SSL/TLS encryption</li>
|
||||
<li>Horizontal scaling capability</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Server Information</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Current Server:</strong></p>
|
||||
<div class="alert alert-primary">
|
||||
@ViewBag.ServerName
|
||||
</div>
|
||||
|
||||
<p><strong>Container Host:</strong></p>
|
||||
<div class="alert alert-secondary">
|
||||
@ViewBag.Hostname
|
||||
</div>
|
||||
|
||||
<p><strong>Timestamp:</strong></p>
|
||||
<div class="alert alert-info">
|
||||
@ViewBag.Timestamp
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5><i class="fas fa-network-wired"></i> Network Architecture</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h6>Production Servers:</h6>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Server 1 (Manager)
|
||||
<span class="badge bg-primary rounded-pill">129.153.123.92</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Server 2 (Worker)
|
||||
<span class="badge bg-secondary rounded-pill">129.146.116.218</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h6>Service Endpoints:</h6>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Public Domain
|
||||
<span class="badge bg-success rounded-pill">bcards.site</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Container Registry
|
||||
<span class="badge bg-warning rounded-pill">registry.redecarneir.us</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
153
test-app/Views/Home/Index.cshtml
Normal file
153
test-app/Views/Home/Index.cshtml
Normal file
@ -0,0 +1,153 @@
|
||||
@{
|
||||
ViewData["Title"] = "Home";
|
||||
}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="jumbotron bg-primary text-white p-5 rounded" style="background-color: @ViewBag.ServerColor !important;">
|
||||
<div class="container-fluid text-center">
|
||||
<h1 class="display-4">
|
||||
<i class="fas fa-server"></i>
|
||||
@ViewBag.ServerName
|
||||
</h1>
|
||||
<p class="lead">BCards Infrastructure Test Application</p>
|
||||
<hr class="my-4 bg-white">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<h5><i class="fas fa-computer"></i> Hostname</h5>
|
||||
<p class="font-monospace">@ViewBag.Hostname</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h5><i class="fas fa-clock"></i> Timestamp</h5>
|
||||
<p class="font-monospace">@ViewBag.Timestamp</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h5><i class="fas fa-network-wired"></i> Load Balancer</h5>
|
||||
<p>Status: <span class="badge bg-success">Active</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5><i class="fas fa-info-circle"></i> Server Information</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm">
|
||||
<tr>
|
||||
<td><strong>Server Name:</strong></td>
|
||||
<td>@ViewBag.ServerName</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Container Host:</strong></td>
|
||||
<td>@ViewBag.Hostname</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Generated At:</strong></td>
|
||||
<td>@ViewBag.Timestamp</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Environment:</strong></td>
|
||||
<td><span class="badge bg-info">Production</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5><i class="fas fa-chart-line"></i> Quick Tests</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-outline-primary" onclick="testServerInfo()">
|
||||
<i class="fas fa-server"></i> Test Server Info API
|
||||
</button>
|
||||
<button class="btn btn-outline-success" onclick="testHealthCheck()">
|
||||
<i class="fas fa-heart"></i> Test Health Check
|
||||
</button>
|
||||
<button class="btn btn-outline-warning" onclick="refreshPage()">
|
||||
<i class="fas fa-refresh"></i> Refresh Page (Test Load Balancer)
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="testResults" class="mt-3"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info">
|
||||
<h6><i class="fas fa-lightbulb"></i> Infrastructure Test Info</h6>
|
||||
<p class="mb-0">
|
||||
Esta aplicação está sendo servida através de um load balancer NGINX configurado para distribuir
|
||||
requisições entre dois servidores OCI. Cada refresh da página pode mostrar um servidor diferente,
|
||||
demonstrando o balanceamento de carga em funcionamento.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<script>
|
||||
async function testServerInfo() {
|
||||
const resultDiv = document.getElementById('testResults');
|
||||
try {
|
||||
const response = await fetch('/server-info');
|
||||
const data = await response.json();
|
||||
resultDiv.innerHTML = `
|
||||
<div class="alert alert-success">
|
||||
<strong>Server Info API Response:</strong><br>
|
||||
<pre>${JSON.stringify(data, null, 2)}</pre>
|
||||
</div>
|
||||
`;
|
||||
} catch (error) {
|
||||
resultDiv.innerHTML = `
|
||||
<div class="alert alert-danger">
|
||||
<strong>Error:</strong> ${error.message}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
async function testHealthCheck() {
|
||||
const resultDiv = document.getElementById('testResults');
|
||||
try {
|
||||
const response = await fetch('/health');
|
||||
const status = response.ok ? 'Healthy' : 'Unhealthy';
|
||||
resultDiv.innerHTML = `
|
||||
<div class="alert alert-${response.ok ? 'success' : 'danger'}">
|
||||
<strong>Health Check:</strong> ${status} (${response.status})
|
||||
</div>
|
||||
`;
|
||||
} catch (error) {
|
||||
resultDiv.innerHTML = `
|
||||
<div class="alert alert-danger">
|
||||
<strong>Health Check Error:</strong> ${error.message}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
function refreshPage() {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
// Auto-refresh a cada 30 segundos para demonstrar load balancing
|
||||
setInterval(() => {
|
||||
const autoRefresh = document.getElementById('autoRefresh');
|
||||
if (autoRefresh && autoRefresh.checked) {
|
||||
refreshPage();
|
||||
}
|
||||
}, 30000);
|
||||
</script>
|
||||
}
|
||||
56
test-app/Views/Shared/_Layout.cshtml
Normal file
56
test-app/Views/Shared/_Layout.cshtml
Normal file
@ -0,0 +1,56 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - BCards Test App</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-dark bg-dark border-bottom box-shadow mb-3">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">
|
||||
<strong>BCards</strong> Test App
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
|
||||
<ul class="navbar-nav flex-grow-1">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-light" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-light" asp-area="" asp-controller="Home" asp-action="About">About</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="navbar-text text-light">
|
||||
<i class="fas fa-server"></i> @ViewBag.ServerName
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<div class="container-fluid">
|
||||
<main role="main" class="pb-3">
|
||||
@RenderBody()
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<footer class="border-top footer text-muted bg-light">
|
||||
<div class="container-fluid text-center py-3">
|
||||
<small>
|
||||
BCards Infrastructure Test |
|
||||
Host: @ViewBag.Hostname |
|
||||
Generated at: @ViewBag.Timestamp
|
||||
</small>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://kit.fontawesome.com/your-fontawesome-kit.js" crossorigin="anonymous"></script>
|
||||
@await RenderSectionAsync("Scripts", required: false)
|
||||
</body>
|
||||
</html>
|
||||
2
test-app/Views/_ViewImports.cshtml
Normal file
2
test-app/Views/_ViewImports.cshtml
Normal file
@ -0,0 +1,2 @@
|
||||
@using BCardsTestApp
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
3
test-app/Views/_ViewStart.cshtml
Normal file
3
test-app/Views/_ViewStart.cshtml
Normal file
@ -0,0 +1,3 @@
|
||||
@{
|
||||
Layout = "_Layout";
|
||||
}
|
||||
38
test-app/docker-compose.yml
Normal file
38
test-app/docker-compose.yml
Normal file
@ -0,0 +1,38 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# Aplicação para teste local
|
||||
bcards-test-app:
|
||||
build: .
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
- SERVER_NAME=Local Development Server
|
||||
- SERVER_COLOR=#28a745
|
||||
networks:
|
||||
- bcards-local
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
# NGINX para teste local do load balancer
|
||||
nginx-local:
|
||||
image: nginx:alpine
|
||||
ports:
|
||||
- "80:80"
|
||||
volumes:
|
||||
- ../nginx/nginx-local.conf:/etc/nginx/nginx.conf:ro
|
||||
depends_on:
|
||||
- bcards-test-app
|
||||
networks:
|
||||
- bcards-local
|
||||
restart: unless-stopped
|
||||
|
||||
networks:
|
||||
bcards-local:
|
||||
driver: bridge
|
||||
83
test-app/obj/BCardsTestApp.csproj.nuget.dgspec.json
Normal file
83
test-app/obj/BCardsTestApp.csproj.nuget.dgspec.json
Normal file
@ -0,0 +1,83 @@
|
||||
{
|
||||
"format": 1,
|
||||
"restore": {
|
||||
"C:\\vscode\\bcards-infrastructure\\test-app\\BCardsTestApp.csproj": {}
|
||||
},
|
||||
"projects": {
|
||||
"C:\\vscode\\bcards-infrastructure\\test-app\\BCardsTestApp.csproj": {
|
||||
"version": "1.0.0",
|
||||
"restore": {
|
||||
"projectUniqueName": "C:\\vscode\\bcards-infrastructure\\test-app\\BCardsTestApp.csproj",
|
||||
"projectName": "BCardsTestApp",
|
||||
"projectPath": "C:\\vscode\\bcards-infrastructure\\test-app\\BCardsTestApp.csproj",
|
||||
"packagesPath": "C:\\Users\\ricar\\.nuget\\packages\\",
|
||||
"outputPath": "C:\\vscode\\bcards-infrastructure\\test-app\\obj\\",
|
||||
"projectStyle": "PackageReference",
|
||||
"fallbackFolders": [
|
||||
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
|
||||
],
|
||||
"configFilePaths": [
|
||||
"C:\\Users\\ricar\\AppData\\Roaming\\NuGet\\NuGet.Config",
|
||||
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
|
||||
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
|
||||
],
|
||||
"originalTargetFrameworks": [
|
||||
"net8.0"
|
||||
],
|
||||
"sources": {
|
||||
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
|
||||
"C:\\Program Files\\dotnet\\library-packs": {},
|
||||
"https://api.nuget.org/v3/index.json": {}
|
||||
},
|
||||
"frameworks": {
|
||||
"net8.0": {
|
||||
"targetAlias": "net8.0",
|
||||
"projectReferences": {}
|
||||
}
|
||||
},
|
||||
"warningProperties": {
|
||||
"warnAsError": [
|
||||
"NU1605"
|
||||
]
|
||||
},
|
||||
"restoreAuditProperties": {
|
||||
"enableAudit": "true",
|
||||
"auditLevel": "low",
|
||||
"auditMode": "direct"
|
||||
},
|
||||
"SdkAnalysisLevel": "9.0.200"
|
||||
},
|
||||
"frameworks": {
|
||||
"net8.0": {
|
||||
"targetAlias": "net8.0",
|
||||
"dependencies": {
|
||||
"Microsoft.AspNetCore.HealthChecks": {
|
||||
"target": "Package",
|
||||
"version": "[1.0.0, )"
|
||||
}
|
||||
},
|
||||
"imports": [
|
||||
"net461",
|
||||
"net462",
|
||||
"net47",
|
||||
"net471",
|
||||
"net472",
|
||||
"net48",
|
||||
"net481"
|
||||
],
|
||||
"assetTargetFallback": true,
|
||||
"warn": true,
|
||||
"frameworkReferences": {
|
||||
"Microsoft.AspNetCore.App": {
|
||||
"privateAssets": "none"
|
||||
},
|
||||
"Microsoft.NETCore.App": {
|
||||
"privateAssets": "all"
|
||||
}
|
||||
},
|
||||
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.200/PortableRuntimeIdentifierGraph.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
20
test-app/obj/BCardsTestApp.csproj.nuget.g.props
Normal file
20
test-app/obj/BCardsTestApp.csproj.nuget.g.props
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
|
||||
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
|
||||
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
|
||||
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
||||
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\ricar\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
||||
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.0</NuGetToolVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<SourceRoot Include="C:\Users\ricar\.nuget\packages\" />
|
||||
<SourceRoot Include="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<PkgNewtonsoft_Json Condition=" '$(PkgNewtonsoft_Json)' == '' ">C:\Users\ricar\.nuget\packages\newtonsoft.json\9.0.1</PkgNewtonsoft_Json>
|
||||
<PkgMicrosoft_CodeAnalysis_Analyzers Condition=" '$(PkgMicrosoft_CodeAnalysis_Analyzers)' == '' ">C:\Users\ricar\.nuget\packages\microsoft.codeanalysis.analyzers\1.1.0</PkgMicrosoft_CodeAnalysis_Analyzers>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
2
test-app/obj/BCardsTestApp.csproj.nuget.g.targets
Normal file
2
test-app/obj/BCardsTestApp.csproj.nuget.g.targets
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
|
||||
@ -0,0 +1,4 @@
|
||||
// <autogenerated />
|
||||
using System;
|
||||
using System.Reflection;
|
||||
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")]
|
||||
22
test-app/obj/Debug/net8.0/BCardsTestApp.AssemblyInfo.cs
Normal file
22
test-app/obj/Debug/net8.0/BCardsTestApp.AssemblyInfo.cs
Normal file
@ -0,0 +1,22 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("BCardsTestApp")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("BCardsTestApp")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("BCardsTestApp")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
// Generated by the MSBuild WriteCodeFragment class.
|
||||
|
||||
@ -0,0 +1 @@
|
||||
789d0a40f649e56edcc5a31f053113bc14cc0f66ea14b7a3531c6f932e11104d
|
||||
@ -0,0 +1,41 @@
|
||||
is_global = true
|
||||
build_property.TargetFramework = net8.0
|
||||
build_property.TargetPlatformMinVersion =
|
||||
build_property.UsingMicrosoftNETSdkWeb = true
|
||||
build_property.ProjectTypeGuids =
|
||||
build_property.InvariantGlobalization =
|
||||
build_property.PlatformNeutralAssembly =
|
||||
build_property.EnforceExtendedAnalyzerRules =
|
||||
build_property._SupportedPlatformList = Linux,macOS,Windows
|
||||
build_property.RootNamespace = BCardsTestApp
|
||||
build_property.RootNamespace = BCardsTestApp
|
||||
build_property.ProjectDir = C:\vscode\bcards-infrastructure\test-app\
|
||||
build_property.EnableComHosting =
|
||||
build_property.EnableGeneratedComInterfaceComImportInterop =
|
||||
build_property.RazorLangVersion = 8.0
|
||||
build_property.SupportLocalizedComponentNames =
|
||||
build_property.GenerateRazorMetadataSourceChecksumAttributes =
|
||||
build_property.MSBuildProjectDirectory = C:\vscode\bcards-infrastructure\test-app
|
||||
build_property._RazorSourceGeneratorDebug =
|
||||
build_property.EffectiveAnalysisLevelStyle = 8.0
|
||||
build_property.EnableCodeStyleSeverity =
|
||||
|
||||
[C:/vscode/bcards-infrastructure/test-app/Views/Home/About.cshtml]
|
||||
build_metadata.AdditionalFiles.TargetPath = Vmlld3NcSG9tZVxBYm91dC5jc2h0bWw=
|
||||
build_metadata.AdditionalFiles.CssScope =
|
||||
|
||||
[C:/vscode/bcards-infrastructure/test-app/Views/Home/Index.cshtml]
|
||||
build_metadata.AdditionalFiles.TargetPath = Vmlld3NcSG9tZVxJbmRleC5jc2h0bWw=
|
||||
build_metadata.AdditionalFiles.CssScope =
|
||||
|
||||
[C:/vscode/bcards-infrastructure/test-app/Views/Shared/_Layout.cshtml]
|
||||
build_metadata.AdditionalFiles.TargetPath = Vmlld3NcU2hhcmVkXF9MYXlvdXQuY3NodG1s
|
||||
build_metadata.AdditionalFiles.CssScope =
|
||||
|
||||
[C:/vscode/bcards-infrastructure/test-app/Views/_ViewImports.cshtml]
|
||||
build_metadata.AdditionalFiles.TargetPath = Vmlld3NcX1ZpZXdJbXBvcnRzLmNzaHRtbA==
|
||||
build_metadata.AdditionalFiles.CssScope =
|
||||
|
||||
[C:/vscode/bcards-infrastructure/test-app/Views/_ViewStart.cshtml]
|
||||
build_metadata.AdditionalFiles.TargetPath = Vmlld3NcX1ZpZXdTdGFydC5jc2h0bWw=
|
||||
build_metadata.AdditionalFiles.CssScope =
|
||||
17
test-app/obj/Debug/net8.0/BCardsTestApp.GlobalUsings.g.cs
Normal file
17
test-app/obj/Debug/net8.0/BCardsTestApp.GlobalUsings.g.cs
Normal file
@ -0,0 +1,17 @@
|
||||
// <auto-generated/>
|
||||
global using global::Microsoft.AspNetCore.Builder;
|
||||
global using global::Microsoft.AspNetCore.Hosting;
|
||||
global using global::Microsoft.AspNetCore.Http;
|
||||
global using global::Microsoft.AspNetCore.Routing;
|
||||
global using global::Microsoft.Extensions.Configuration;
|
||||
global using global::Microsoft.Extensions.DependencyInjection;
|
||||
global using global::Microsoft.Extensions.Hosting;
|
||||
global using global::Microsoft.Extensions.Logging;
|
||||
global using global::System;
|
||||
global using global::System.Collections.Generic;
|
||||
global using global::System.IO;
|
||||
global using global::System.Linq;
|
||||
global using global::System.Net.Http;
|
||||
global using global::System.Net.Http.Json;
|
||||
global using global::System.Threading;
|
||||
global using global::System.Threading.Tasks;
|
||||
@ -0,0 +1 @@
|
||||
d5ac7ab69059af111e9d7125adeb7b174ca570725d4b64a544cca7bd11ac7ca0
|
||||
17
test-app/obj/Debug/net8.0/BCardsTestApp.RazorAssemblyInfo.cs
Normal file
17
test-app/obj/Debug/net8.0/BCardsTestApp.RazorAssemblyInfo.cs
Normal file
@ -0,0 +1,17 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: Microsoft.AspNetCore.Mvc.ApplicationParts.ProvideApplicationPartFactoryAttribute(("Microsoft.AspNetCore.Mvc.ApplicationParts.ConsolidatedAssemblyApplicationPartFact" +
|
||||
"ory, Microsoft.AspNetCore.Mvc.Razor"))]
|
||||
|
||||
// Generated by the MSBuild WriteCodeFragment class.
|
||||
|
||||
BIN
test-app/obj/Debug/net8.0/BCardsTestApp.assets.cache
Normal file
BIN
test-app/obj/Debug/net8.0/BCardsTestApp.assets.cache
Normal file
Binary file not shown.
Binary file not shown.
8737
test-app/obj/project.assets.json
Normal file
8737
test-app/obj/project.assets.json
Normal file
File diff suppressed because it is too large
Load Diff
162
test-app/obj/project.nuget.cache
Normal file
162
test-app/obj/project.nuget.cache
Normal file
@ -0,0 +1,162 @@
|
||||
{
|
||||
"version": 2,
|
||||
"dgSpecHash": "znQK0+PCGGU=",
|
||||
"success": true,
|
||||
"projectFilePath": "C:\\vscode\\bcards-infrastructure\\test-app\\BCardsTestApp.csproj",
|
||||
"expectedPackageFiles": [
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\libuv\\1.9.1\\libuv.1.9.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.aspnetcore.healthchecks\\1.0.0\\microsoft.aspnetcore.healthchecks.1.0.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.aspnetcore.hosting\\1.0.2\\microsoft.aspnetcore.hosting.1.0.2.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.aspnetcore.hosting.abstractions\\1.0.2\\microsoft.aspnetcore.hosting.abstractions.1.0.2.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.aspnetcore.hosting.server.abstractions\\1.0.2\\microsoft.aspnetcore.hosting.server.abstractions.1.0.2.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.aspnetcore.http\\1.0.2\\microsoft.aspnetcore.http.1.0.2.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.aspnetcore.http.abstractions\\1.0.2\\microsoft.aspnetcore.http.abstractions.1.0.2.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.aspnetcore.http.extensions\\1.0.2\\microsoft.aspnetcore.http.extensions.1.0.2.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.aspnetcore.http.features\\1.0.2\\microsoft.aspnetcore.http.features.1.0.2.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.aspnetcore.webutilities\\1.0.2\\microsoft.aspnetcore.webutilities.1.0.2.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.codeanalysis.analyzers\\1.1.0\\microsoft.codeanalysis.analyzers.1.1.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.codeanalysis.common\\1.3.0\\microsoft.codeanalysis.common.1.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.codeanalysis.csharp\\1.3.0\\microsoft.codeanalysis.csharp.1.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.codeanalysis.visualbasic\\1.3.0\\microsoft.codeanalysis.visualbasic.1.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.csharp\\4.0.1\\microsoft.csharp.4.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.extensions.configuration\\1.0.2\\microsoft.extensions.configuration.1.0.2.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.extensions.configuration.abstractions\\1.0.2\\microsoft.extensions.configuration.abstractions.1.0.2.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.extensions.configuration.environmentvariables\\1.0.2\\microsoft.extensions.configuration.environmentvariables.1.0.2.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.extensions.dependencyinjection\\1.0.2\\microsoft.extensions.dependencyinjection.1.0.2.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.extensions.dependencyinjection.abstractions\\1.0.2\\microsoft.extensions.dependencyinjection.abstractions.1.0.2.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.extensions.fileproviders.abstractions\\1.0.1\\microsoft.extensions.fileproviders.abstractions.1.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.extensions.fileproviders.physical\\1.0.1\\microsoft.extensions.fileproviders.physical.1.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.extensions.filesystemglobbing\\1.0.1\\microsoft.extensions.filesystemglobbing.1.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.extensions.healthchecks\\1.0.0\\microsoft.extensions.healthchecks.1.0.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.extensions.logging\\1.0.2\\microsoft.extensions.logging.1.0.2.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.extensions.logging.abstractions\\1.0.2\\microsoft.extensions.logging.abstractions.1.0.2.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.extensions.objectpool\\1.0.1\\microsoft.extensions.objectpool.1.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.extensions.options\\1.0.2\\microsoft.extensions.options.1.0.2.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.extensions.platformabstractions\\1.0.0\\microsoft.extensions.platformabstractions.1.0.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.extensions.primitives\\1.0.1\\microsoft.extensions.primitives.1.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.net.http.headers\\1.0.2\\microsoft.net.http.headers.1.0.2.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.netcore.app\\1.0.5\\microsoft.netcore.app.1.0.5.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.netcore.dotnethost\\1.0.1\\microsoft.netcore.dotnethost.1.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.netcore.dotnethostpolicy\\1.0.5\\microsoft.netcore.dotnethostpolicy.1.0.5.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.netcore.dotnethostresolver\\1.0.1\\microsoft.netcore.dotnethostresolver.1.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.netcore.jit\\1.0.7\\microsoft.netcore.jit.1.0.7.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.netcore.platforms\\1.1.0\\microsoft.netcore.platforms.1.1.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.netcore.runtime.coreclr\\1.0.7\\microsoft.netcore.runtime.coreclr.1.0.7.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.netcore.targets\\1.1.0\\microsoft.netcore.targets.1.1.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.netcore.windows.apisets\\1.0.1\\microsoft.netcore.windows.apisets.1.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.visualbasic\\10.0.1\\microsoft.visualbasic.10.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.win32.primitives\\4.3.0\\microsoft.win32.primitives.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\microsoft.win32.registry\\4.3.0\\microsoft.win32.registry.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\netstandard.library\\1.6.1\\netstandard.library.1.6.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\newtonsoft.json\\9.0.1\\newtonsoft.json.9.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\runtime.debian.8-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.debian.8-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\runtime.fedora.23-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.fedora.23-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\runtime.fedora.24-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.fedora.24-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\runtime.native.system\\4.3.0\\runtime.native.system.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\runtime.native.system.io.compression\\4.3.0\\runtime.native.system.io.compression.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\runtime.native.system.net.http\\4.3.0\\runtime.native.system.net.http.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\runtime.native.system.net.security\\4.0.1\\runtime.native.system.net.security.4.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\runtime.native.system.security.cryptography\\4.0.1\\runtime.native.system.security.cryptography.4.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\runtime.native.system.security.cryptography.apple\\4.3.0\\runtime.native.system.security.cryptography.apple.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\runtime.opensuse.13.2-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.opensuse.13.2-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\runtime.opensuse.42.1-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.opensuse.42.1-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\runtime.osx.10.10-x64.runtime.native.system.security.cryptography.apple\\4.3.0\\runtime.osx.10.10-x64.runtime.native.system.security.cryptography.apple.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\runtime.osx.10.10-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.osx.10.10-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\runtime.rhel.7-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.rhel.7-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\runtime.ubuntu.14.04-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.ubuntu.14.04-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\runtime.ubuntu.16.04-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.ubuntu.16.04-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\runtime.ubuntu.16.10-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.ubuntu.16.10-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.appcontext\\4.3.0\\system.appcontext.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.buffers\\4.3.0\\system.buffers.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.collections\\4.3.0\\system.collections.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.collections.concurrent\\4.3.0\\system.collections.concurrent.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.collections.immutable\\1.2.0\\system.collections.immutable.1.2.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.componentmodel\\4.0.1\\system.componentmodel.4.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.componentmodel.annotations\\4.1.0\\system.componentmodel.annotations.4.1.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.console\\4.3.0\\system.console.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.diagnostics.contracts\\4.0.1\\system.diagnostics.contracts.4.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.diagnostics.debug\\4.3.0\\system.diagnostics.debug.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.diagnostics.diagnosticsource\\4.3.0\\system.diagnostics.diagnosticsource.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.diagnostics.fileversioninfo\\4.0.0\\system.diagnostics.fileversioninfo.4.0.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.diagnostics.process\\4.3.0\\system.diagnostics.process.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.diagnostics.stacktrace\\4.0.1\\system.diagnostics.stacktrace.4.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.diagnostics.tools\\4.3.0\\system.diagnostics.tools.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.diagnostics.tracing\\4.3.0\\system.diagnostics.tracing.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.dynamic.runtime\\4.0.11\\system.dynamic.runtime.4.0.11.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.globalization\\4.3.0\\system.globalization.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.globalization.calendars\\4.3.0\\system.globalization.calendars.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.globalization.extensions\\4.3.0\\system.globalization.extensions.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.io\\4.3.0\\system.io.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.io.compression\\4.3.0\\system.io.compression.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.io.compression.zipfile\\4.3.0\\system.io.compression.zipfile.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.io.filesystem\\4.3.0\\system.io.filesystem.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.io.filesystem.primitives\\4.3.0\\system.io.filesystem.primitives.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.io.filesystem.watcher\\4.0.0\\system.io.filesystem.watcher.4.0.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.io.memorymappedfiles\\4.0.0\\system.io.memorymappedfiles.4.0.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.io.unmanagedmemorystream\\4.0.1\\system.io.unmanagedmemorystream.4.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.linq\\4.3.0\\system.linq.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.linq.expressions\\4.3.0\\system.linq.expressions.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.linq.parallel\\4.0.1\\system.linq.parallel.4.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.linq.queryable\\4.0.1\\system.linq.queryable.4.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.net.http\\4.3.0\\system.net.http.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.net.nameresolution\\4.0.0\\system.net.nameresolution.4.0.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.net.primitives\\4.3.0\\system.net.primitives.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.net.requests\\4.0.11\\system.net.requests.4.0.11.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.net.security\\4.0.1\\system.net.security.4.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.net.sockets\\4.3.0\\system.net.sockets.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.net.webheadercollection\\4.0.1\\system.net.webheadercollection.4.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.net.websockets\\4.0.0\\system.net.websockets.4.0.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.numerics.vectors\\4.1.1\\system.numerics.vectors.4.1.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.objectmodel\\4.3.0\\system.objectmodel.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.reflection\\4.3.0\\system.reflection.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.reflection.dispatchproxy\\4.0.1\\system.reflection.dispatchproxy.4.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.reflection.emit\\4.3.0\\system.reflection.emit.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.reflection.emit.ilgeneration\\4.3.0\\system.reflection.emit.ilgeneration.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.reflection.emit.lightweight\\4.3.0\\system.reflection.emit.lightweight.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.reflection.extensions\\4.3.0\\system.reflection.extensions.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.reflection.metadata\\1.3.0\\system.reflection.metadata.1.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.reflection.primitives\\4.3.0\\system.reflection.primitives.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.reflection.typeextensions\\4.3.0\\system.reflection.typeextensions.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.resources.reader\\4.0.0\\system.resources.reader.4.0.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.resources.resourcemanager\\4.3.0\\system.resources.resourcemanager.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.runtime\\4.3.0\\system.runtime.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.runtime.extensions\\4.3.0\\system.runtime.extensions.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.runtime.handles\\4.3.0\\system.runtime.handles.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.runtime.interopservices\\4.3.0\\system.runtime.interopservices.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.runtime.interopservices.runtimeinformation\\4.3.0\\system.runtime.interopservices.runtimeinformation.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.runtime.loader\\4.0.0\\system.runtime.loader.4.0.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.runtime.numerics\\4.3.0\\system.runtime.numerics.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.runtime.serialization.primitives\\4.1.1\\system.runtime.serialization.primitives.4.1.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.security.claims\\4.0.1\\system.security.claims.4.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.security.cryptography.algorithms\\4.3.0\\system.security.cryptography.algorithms.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.security.cryptography.cng\\4.3.0\\system.security.cryptography.cng.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.security.cryptography.csp\\4.3.0\\system.security.cryptography.csp.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.security.cryptography.encoding\\4.3.0\\system.security.cryptography.encoding.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.security.cryptography.openssl\\4.3.0\\system.security.cryptography.openssl.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.security.cryptography.primitives\\4.3.0\\system.security.cryptography.primitives.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.security.cryptography.x509certificates\\4.3.0\\system.security.cryptography.x509certificates.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.security.principal\\4.0.1\\system.security.principal.4.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.security.principal.windows\\4.0.0\\system.security.principal.windows.4.0.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.text.encoding\\4.3.0\\system.text.encoding.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.text.encoding.codepages\\4.0.1\\system.text.encoding.codepages.4.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.text.encoding.extensions\\4.3.0\\system.text.encoding.extensions.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.text.encodings.web\\4.0.0\\system.text.encodings.web.4.0.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.text.regularexpressions\\4.3.0\\system.text.regularexpressions.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.threading\\4.3.0\\system.threading.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.threading.overlapped\\4.0.1\\system.threading.overlapped.4.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.threading.tasks\\4.3.0\\system.threading.tasks.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.threading.tasks.dataflow\\4.6.0\\system.threading.tasks.dataflow.4.6.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.threading.tasks.extensions\\4.3.0\\system.threading.tasks.extensions.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.threading.tasks.parallel\\4.3.0\\system.threading.tasks.parallel.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.threading.thread\\4.3.0\\system.threading.thread.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.threading.threadpool\\4.3.0\\system.threading.threadpool.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.threading.timer\\4.3.0\\system.threading.timer.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.xml.readerwriter\\4.3.0\\system.xml.readerwriter.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.xml.xdocument\\4.3.0\\system.xml.xdocument.4.3.0.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.xml.xmldocument\\4.0.1\\system.xml.xmldocument.4.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.xml.xpath\\4.0.1\\system.xml.xpath.4.0.1.nupkg.sha512",
|
||||
"C:\\Users\\ricar\\.nuget\\packages\\system.xml.xpath.xdocument\\4.0.1\\system.xml.xpath.xdocument.4.0.1.nupkg.sha512"
|
||||
],
|
||||
"logs": []
|
||||
}
|
||||
135
test-app/wwwroot/css/site.css
Normal file
135
test-app/wwwroot/css/site.css
Normal file
@ -0,0 +1,135 @@
|
||||
/* BCards Test App Styles */
|
||||
|
||||
html {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
html {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
html {
|
||||
position: relative;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin-bottom: 60px;
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
line-height: 60px;
|
||||
}
|
||||
|
||||
.jumbotron {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border: none;
|
||||
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.card {
|
||||
border: none;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
.btn {
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.alert {
|
||||
border-radius: 8px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.badge {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #f8f9fa;
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: 4px;
|
||||
padding: 1rem;
|
||||
font-size: 0.875rem;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.list-group-item {
|
||||
border: none;
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.list-group-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* Loading animation */
|
||||
.loading {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 3px solid rgba(255,255,255,.3);
|
||||
border-radius: 50%;
|
||||
border-top-color: #fff;
|
||||
animation: spin 1s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* Server status indicators */
|
||||
.server-status {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.server-status.online {
|
||||
background-color: #28a745;
|
||||
box-shadow: 0 0 0 2px rgba(40, 167, 69, 0.3);
|
||||
}
|
||||
|
||||
.server-status.offline {
|
||||
background-color: #dc3545;
|
||||
box-shadow: 0 0 0 2px rgba(220, 53, 69, 0.3);
|
||||
}
|
||||
|
||||
/* Dark theme support */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.card {
|
||||
background-color: #2d3748;
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
.alert {
|
||||
background-color: #4a5568;
|
||||
color: #e2e8f0;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user