┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ NGINX Proxy │ │ PHP-FPM App │ │ MySQL Database │
│ (Port 80/443) │◄──►│ (Port 9000) │◄──►│ (Port 3306) │
│ │ │ │ │ │
│ - Load Balancer │ │ - Apache/Nginx │ │ - Persistent Vol│
│ - SSL Termination│ │ - PHP 7.4+ │ │ - Backups │
│ - Static Assets │ │ - Inmobiliaria │ │ - Replication │
└─────────────────┘ └─────────────────┘ └─────────────────┘
✅ Consistencia: Mismo entorno en desarrollo, testing y producción
✅ Escalabilidad: Fácil escalado horizontal con múltiples contenedores
✅ Aislamiento: Dependencias encapsuladas, sin conflictos
✅ Portabilidad: Funciona en cualquier servidor con Docker
✅ CI/CD: Integración perfecta con pipelines de despliegue
✅ Rollback: Volver a versiones anteriores instantáneamente
✅ Monitoring: Logs centralizados y métricas por contenedor
INMOBILIARIA_1/
├── docker/
│ ├── nginx/
│ │ ├── nginx.conf
│ │ ├── default.conf
│ │ └── ssl/
│ ├── php/
│ │ ├── Dockerfile
│ │ ├── php.ini
│ │ └── www.conf
│ ├── mysql/
│ │ ├── init.sql
│ │ ├── my.cnf
│ │ └── backups/
│ └── scripts/
│ ├── deploy.sh
│ ├── backup.sh
│ └── setup.sh
├── docker-compose.yml
├── docker-compose.prod.yml
├── .dockerignore
├── .env.example
└── [código aplicación]
docker/php/Dockerfile)FROM php:8.1-fpm-alpine
# Información del mantenedor
LABEL maintainer="inmobiliaria@company.com"
LABEL description="Sistema de Gestión Inmobiliaria"
# Argumentos de construcción
ARG APP_ENV=production
ARG PHP_VERSION=8.1
# Variables de entorno
ENV APP_ENV=${APP_ENV}
ENV PHP_MEMORY_LIMIT=512M
ENV PHP_UPLOAD_MAX_FILESIZE=20M
ENV PHP_POST_MAX_SIZE=25M
# Instalar dependencias del sistema
RUN apk add --no-cache \
curl \
wget \
git \
unzip \
libpng-dev \
libjpeg-turbo-dev \
libwebp-dev \
freetype-dev \
icu-dev \
libzip-dev \
oniguruma-dev \
mysql-client \
nginx \
supervisor
# Instalar extensiones PHP
RUN docker-php-ext-configure gd \
--with-freetype \
--with-jpeg \
--with-webp
RUN docker-php-ext-install \
pdo \
pdo_mysql \
mysqli \
gd \
intl \
zip \
mbstring \
opcache \
bcmath \
exif
# Instalar Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Crear usuario no-root
RUN addgroup -g 1000 -S www && \
adduser -u 1000 -S www -G www
# Crear directorios de trabajo
RUN mkdir -p /var/www/html /var/log/php-fpm /run/nginx
# Copiar archivos de configuración
COPY docker/php/php.ini /usr/local/etc/php/conf.d/custom.ini
COPY docker/php/www.conf /usr/local/etc/php-fpm.d/www.conf
COPY docker/nginx/nginx.conf /etc/nginx/nginx.conf
COPY docker/nginx/default.conf /etc/nginx/conf.d/default.conf
COPY docker/supervisor/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Copiar código de la aplicación
WORKDIR /var/www/html
COPY --chown=www:www . .
# Crear directorio uploads y configurar permisos
RUN mkdir -p uploads logs cache && \
chown -R www:www uploads logs cache && \
chmod -R 755 uploads && \
chmod -R 777 uploads logs cache
# Instalar dependencias PHP si existe composer.json
RUN if [ -f composer.json ]; then \
composer install --no-dev --optimize-autoloader --no-scripts; \
fi
# Optimizaciones de producción
RUN if [ "$APP_ENV" = "production" ]; then \
# Precompilar OPcache
php -d opcache.enable_cli=1 -r "echo 'OPcache enabled';" && \
# Limpiar cache
rm -rf /tmp/* /var/tmp/*; \
fi
# Exponer puertos
EXPOSE 80 9000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost/health.php || exit 1
# Comando de inicio
CMD ["supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
docker/nginx/Dockerfile)FROM nginx:1.21-alpine
# Copiar configuración personalizada
COPY docker/nginx/nginx.conf /etc/nginx/nginx.conf
COPY docker/nginx/default.conf /etc/nginx/conf.d/default.conf
# Crear directorio para logs
RUN mkdir -p /var/log/nginx
# Copiar archivos estáticos
COPY --chown=nginx:nginx public/ /var/www/html/public/
COPY --chown=nginx:nginx uploads/ /var/www/html/uploads/
# Permisos
RUN chown -R nginx:nginx /var/www/html && \
chmod -R 755 /var/www/html
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]
docker/mysql/Dockerfile)FROM mysql:8.0
# Variables de entorno
ENV MYSQL_ROOT_PASSWORD=rootpass123
ENV MYSQL_DATABASE=inmobil
ENV MYSQL_USER=inmobil_user
ENV MYSQL_PASSWORD=inmobil_pass123
# Copiar archivos de configuración
COPY docker/mysql/my.cnf /etc/mysql/conf.d/custom.cnf
COPY docker/mysql/init.sql /docker-entrypoint-initdb.d/
# Crear directorios para backups
RUN mkdir -p /var/backups/mysql
# Script de inicialización
COPY docker/mysql/init-script.sh /docker-entrypoint-initdb.d/
RUN chmod +x /docker-entrypoint-initdb.d/init-script.sh
VOLUME ["/var/lib/mysql", "/var/backups/mysql"]
EXPOSE 3306
docker/mysql/my.cnf)[mysqld]
# Configuraciones de rendimiento
innodb_buffer_pool_size = 256M
innodb_buffer_pool_instances = 2
innodb_log_file_size = 64M
innodb_log_buffer_size = 16M
innodb_flush_log_at_trx_commit = 2
# Configuraciones de conexión
max_connections = 200
max_connect_errors = 10000
table_open_cache = 2000
table_definition_cache = 1400
# Configuraciones de query
query_cache_type = 1
query_cache_limit = 1M
query_cache_size = 32M
# Configuraciones de charset
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
# Configuraciones de binlog para replicación
log-bin = mysql-bin
binlog_format = ROW
expire_logs_days = 7
# Configuraciones de slow query log
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
# Configuraciones de seguridad
skip-name-resolve
ssl-ca = /etc/mysql/certs/ca-cert.pem
ssl-cert = /etc/mysql/certs/server-cert.pem
ssl-key = /etc/mysql/certs/server-key.pem
[mysql]
default-character-set = utf8mb4
[client]
default-character-set = utf8mb4
docker-compose.yml)version: '3.8'
services:
# Aplicación PHP-FPM
app:
build:
context: .
dockerfile: docker/php/Dockerfile
args:
APP_ENV: development
container_name: inmobiliaria_app
restart: unless-stopped
working_dir: /var/www/html
volumes:
- ./:/var/www/html
- ./docker/php/php.ini:/usr/local/etc/php/conf.d/custom.ini
- app_logs:/var/log/php-fpm
environment:
- APP_ENV=development
- DB_HOST=db
- DB_DATABASE=inmobil
- DB_USERNAME=inmobil_user
- DB_PASSWORD=inmobil_pass123
depends_on:
- db
networks:
- inmobiliaria_network
# Servidor Web Nginx
webserver:
image: nginx:1.21-alpine
container_name: inmobiliaria_webserver
restart: unless-stopped
ports:
- "8080:80"
- "8443:443"
volumes:
- ./:/var/www/html
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
- nginx_logs:/var/log/nginx
depends_on:
- app
networks:
- inmobiliaria_network
# Base de Datos MySQL
db:
build:
context: .
dockerfile: docker/mysql/Dockerfile
container_name: inmobiliaria_db
restart: unless-stopped
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: rootpass123
MYSQL_DATABASE: inmobil
MYSQL_USER: inmobil_user
MYSQL_PASSWORD: inmobil_pass123
volumes:
- mysql_data:/var/lib/mysql
- mysql_backups:/var/backups/mysql
- ./docker/mysql/init.sql:/docker-entrypoint-initdb.d/init.sql
- mysql_logs:/var/log/mysql
networks:
- inmobiliaria_network
# Redis para Cache (Opcional)
cache:
image: redis:7-alpine
container_name: inmobiliaria_cache
restart: unless-stopped
ports:
- "6379:6379"
volumes:
- redis_data:/data
command: redis-server --appendonly yes --requirepass "cache_pass123"
networks:
- inmobiliaria_network
# phpMyAdmin para desarrollo
phpmyadmin:
image: phpmyadmin/phpmyadmin:5
container_name: inmobiliaria_phpmyadmin
restart: unless-stopped
ports:
- "8081:80"
environment:
PMA_HOST: db
PMA_PORT: 3306
PMA_USER: inmobil_user
PMA_PASSWORD: inmobil_pass123
MYSQL_ROOT_PASSWORD: rootpass123
depends_on:
- db
networks:
- inmobiliaria_network
volumes:
mysql_data:
driver: local
mysql_backups:
driver: local
redis_data:
driver: local
app_logs:
driver: local
nginx_logs:
driver: local
mysql_logs:
driver: local
networks:
inmobiliaria_network:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
docker-compose.prod.yml)version: '3.8'
services:
# Load Balancer / Reverse Proxy
traefik:
image: traefik:v2.9
container_name: inmobiliaria_traefik
restart: unless-stopped
command:
- --api.dashboard=true
- --api.debug=true
- --log.level=INFO
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --certificatesresolvers.letsencrypt.acme.email=admin@inmobiliaria.com
- --certificatesresolvers.letsencrypt.acme.storage=/acme.json
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
ports:
- "80:80"
- "443:443"
- "8080:8080" # Dashboard Traefik
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- traefik_acme:/acme.json
labels:
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(`traefik.inmobiliaria.com`)"
- "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
networks:
- inmobiliaria_network
# Aplicación PHP-FPM (Escalable)
app:
build:
context: .
dockerfile: docker/php/Dockerfile
args:
APP_ENV: production
restart: unless-stopped
deploy:
replicas: 3 # 3 instancias para alta disponibilidad
resources:
limits:
memory: 512M
cpus: "0.5"
reservations:
memory: 256M
cpus: "0.25"
environment:
- APP_ENV=production
- DB_HOST=db
- DB_DATABASE=inmobil
- DB_USERNAME=inmobil_user
- DB_PASSWORD=${DB_PASSWORD}
- REDIS_HOST=cache
- REDIS_PASSWORD=${REDIS_PASSWORD}
volumes:
- app_uploads:/var/www/html/uploads
- app_logs:/var/www/html/logs
depends_on:
- db
- cache
networks:
- inmobiliaria_network
# Servidor Web Nginx
webserver:
image: nginx:1.21-alpine
restart: unless-stopped
volumes:
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
- ./docker/nginx/prod.conf:/etc/nginx/conf.d/default.conf
- app_uploads:/var/www/html/uploads:ro
- nginx_logs:/var/log/nginx
depends_on:
- app
labels:
- "traefik.enable=true"
- "traefik.http.routers.inmobiliaria.rule=Host(`inmobiliaria.com`, `www.inmobiliaria.com`)"
- "traefik.http.routers.inmobiliaria.tls.certresolver=letsencrypt"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
- "traefik.http.routers.inmobiliaria-http.rule=Host(`inmobiliaria.com`, `www.inmobiliaria.com`)"
- "traefik.http.routers.inmobiliaria-http.entrypoints=web"
- "traefik.http.routers.inmobiliaria-http.middlewares=redirect-to-https"
networks:
- inmobiliaria_network
# Base de Datos MySQL Master
db:
image: mysql:8.0
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: inmobil
MYSQL_USER: inmobil_user
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- mysql_data:/var/lib/mysql
- mysql_backups:/var/backups/mysql
- mysql_logs:/var/log/mysql
- ./docker/mysql/prod.cnf:/etc/mysql/conf.d/custom.cnf
deploy:
resources:
limits:
memory: 1G
cpus: "1.0"
reservations:
memory: 512M
cpus: "0.5"
networks:
- inmobiliaria_network
# Base de Datos MySQL Slave (Solo lectura)
db_slave:
image: mysql:8.0
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: inmobil
MYSQL_USER: inmobil_user
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- mysql_slave_data:/var/lib/mysql
- ./docker/mysql/slave.cnf:/etc/mysql/conf.d/custom.cnf
depends_on:
- db
networks:
- inmobiliaria_network
# Redis Cluster para Cache
cache:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --appendonly yes --requirepass "${REDIS_PASSWORD}"
volumes:
- redis_data:/data
deploy:
resources:
limits:
memory: 256M
cpus: "0.25"
networks:
- inmobiliaria_network
# Elasticsearch para búsquedas avanzadas (Opcional)
elasticsearch:
image: elasticsearch:7.17.0
container_name: inmobiliaria_search
restart: unless-stopped
environment:
- discovery.type=single-node
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
volumes:
- elastic_data:/usr/share/elasticsearch/data
networks:
- inmobiliaria_network
# Monitoring con Prometheus
prometheus:
image: prom/prometheus:latest
container_name: inmobiliaria_prometheus
restart: unless-stopped
ports:
- "9090:9090"
volumes:
- ./docker/monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
networks:
- inmobiliaria_network
# Grafana para dashboards
grafana:
image: grafana/grafana:latest
container_name: inmobiliaria_grafana
restart: unless-stopped
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
volumes:
- grafana_data:/var/lib/grafana
networks:
- inmobiliaria_network
volumes:
mysql_data:
mysql_slave_data:
mysql_backups:
mysql_logs:
redis_data:
elastic_data:
app_uploads:
app_logs:
nginx_logs:
traefik_acme:
prometheus_data:
grafana_data:
networks:
inmobiliaria_network:
driver: bridge
docker/php/php.ini); Configuración PHP para Producción
; Memoria y tiempo
memory_limit = 512M
max_execution_time = 300
max_input_time = 300
; Upload de archivos
upload_max_filesize = 20M
post_max_size = 25M
max_file_uploads = 20
; Sesiones
session.name = INMOBSESSID
session.auto_start = 0
session.gc_maxlifetime = 7200
session.cookie_lifetime = 0
session.cookie_httponly = 1
session.cookie_secure = 1
session.cookie_samesite = "Strict"
session.use_strict_mode = 1
; Seguridad
expose_php = Off
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /var/log/php-fpm/error.log
; OPcache para rendimiento
opcache.enable = 1
opcache.enable_cli = 0
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files = 4000
opcache.revalidate_freq = 60
opcache.validate_timestamps = 0
opcache.fast_shutdown = 1
; Timezone
date.timezone = "America/Bogota"
; Configuraciones de base de datos
pdo_mysql.default_socket = /var/run/mysqld/mysqld.sock
mysqli.default_socket = /var/run/mysqld/mysqld.sock
docker/nginx/nginx.conf)user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 2048;
use epoll;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Configuraciones de seguridad
server_tokens off;
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 Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Configuraciones de rendimiento
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
client_max_body_size 25M;
client_body_buffer_size 16K;
client_header_buffer_size 1k;
# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 10240;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/xml+rss
application/json
image/svg+xml;
# Rate limiting
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
# Configuración de logs
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;
# Cache de archivos estáticos
map $sent_http_content_type $expires {
default off;
text/html 1h;
text/css 1y;
application/javascript 1y;
~image/ 1y;
font/ 1y;
}
expires $expires;
include /etc/nginx/conf.d/*.conf;
}
docker/nginx/default.conf)upstream php_backend {
server app:9000;
# Para múltiples instancias:
# server app_1:9000 weight=3;
# server app_2:9000 weight=3;
# server app_3:9000 weight=3;
}
# Redirección HTTP a HTTPS
server {
listen 80;
server_name inmobiliaria.com www.inmobiliaria.com;
location /.well-known/acme-challenge/ {
root /var/www/html/public;
}
location / {
return 301 https://$server_name$request_uri;
}
}
# Configuración principal HTTPS
server {
listen 443 ssl http2;
server_name inmobiliaria.com www.inmobiliaria.com;
root /var/www/html;
index index.php index.html;
# Configuración SSL
ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Rate limiting por ubicación
location /auth/ {
limit_req zone=login burst=3 nodelay;
try_files $uri $uri/ /index.php$is_args$args;
}
location /public/api/ {
limit_req zone=api burst=5 nodelay;
try_files $uri $uri/ /index.php$is_args$args;
}
# Archivos estáticos
location ~* \.(jpg|jpeg|png|gif|ico|css|js|pdf|txt)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header Vary Accept-Encoding;
access_log off;
}
# Uploads con seguridad
location ^~ /uploads/ {
alias /var/www/html/uploads/;
location ~* \.(php|php5|phtml|pht|phps)$ {
deny all;
}
expires 1M;
add_header Cache-Control "public";
}
# Denegar acceso a archivos sensibles
location ~ /\.(ht|git|svn) {
deny all;
}
location ~ /(config|includes|vendor)/ {
deny all;
}
location ~ /\.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php_backend;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
# Timeouts
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 60s;
fastcgi_read_timeout 60s;
# Buffer settings
fastcgi_buffering on;
fastcgi_buffer_size 16k;
fastcgi_buffers 16 16k;
}
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
# Health check
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}
docker/scripts/deploy.sh)#!/bin/bash
# Script de despliegue automatizado
set -e
# Configuración
PROJECT_NAME="inmobiliaria"
DOCKER_REGISTRY="registry.inmobiliaria.com"
VERSION=${1:-latest}
ENVIRONMENT=${2:-production}
echo "🚀 Iniciando despliegue de $PROJECT_NAME v$VERSION en $ENVIRONMENT"
# Verificar dependencias
command -v docker >/dev/null 2>&1 || { echo "Docker no está instalado" >&2; exit 1; }
command -v docker-compose >/dev/null 2>&1 || { echo "Docker Compose no está instalado" >&2; exit 1; }
# Función de rollback
rollback() {
echo "❌ Despliegue falló. Ejecutando rollback..."
docker-compose -f docker-compose.prod.yml down
docker-compose -f docker-compose.prod.yml up -d
exit 1
}
# Trap para rollback automático
trap rollback ERR
# Backup de base de datos
echo "💾 Creando backup de base de datos..."
docker exec inmobiliaria_db mysqldump -u root -p${DB_ROOT_PASSWORD} inmobil > backup_$(date +%Y%m%d_%H%M%S).sql
# Build de nuevas imágenes
echo "🔨 Construyendo imágenes..."
docker-compose -f docker-compose.prod.yml build --no-cache
# Tag de imágenes para registry
docker tag ${PROJECT_NAME}_app:latest ${DOCKER_REGISTRY}/${PROJECT_NAME}_app:${VERSION}
docker tag ${PROJECT_NAME}_webserver:latest ${DOCKER_REGISTRY}/${PROJECT_NAME}_webserver:${VERSION}
# Push al registry
echo "📤 Subiendo imágenes al registry..."
docker push ${DOCKER_REGISTRY}/${PROJECT_NAME}_app:${VERSION}
docker push ${DOCKER_REGISTRY}/${PROJECT_NAME}_webserver:${VERSION}
# Deploy con zero-downtime
echo "🔄 Desplegando nueva versión..."
# Escalar down instancia por instancia
for i in 3 2 1; do
echo "Escalando a $i instancias..."
docker-compose -f docker-compose.prod.yml up -d --scale app=$i
# Esperar que las instancias estén healthy
for j in $(seq 1 30); do
if curl -f http://localhost/health > /dev/null 2>&1; then
break
fi
sleep 2
done
sleep 5
done
# Desplegar nueva versión
docker-compose -f docker-compose.prod.yml down
docker-compose -f docker-compose.prod.yml up -d
# Esperar que todos los servicios estén healthy
echo "🔍 Verificando health de servicios..."
for service in app webserver db; do
for i in $(seq 1 60); do
if docker-compose -f docker-compose.prod.yml ps $service | grep -q "healthy"; then
echo "✅ $service está healthy"
break
fi
sleep 2
done
done
# Tests de smoke
echo "🧪 Ejecutando tests de smoke..."
curl -f http://localhost/health || rollback
curl -f http://localhost/public/ || rollback
# Limpiar imágenes antiguas
echo "🧹 Limpiando imágenes antiguas..."
docker image prune -f --filter "until=24h"
echo "🎉 Despliegue completado exitosamente!"
echo "📊 Logs: docker-compose -f docker-compose.prod.yml logs -f"
echo "📈 Monitoring: http://monitoring.inmobiliaria.com:3000"
docker/scripts/backup.sh)#!/bin/bash
# Script de backup automatizado
set -e
BACKUP_DIR="/var/backups/inmobiliaria"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=30
mkdir -p $BACKUP_DIR
echo "📦 Iniciando backup completo..."
# Backup de base de datos
echo "💾 Backup de base de datos..."
docker exec inmobiliaria_db mysqldump \
--single-transaction \
--routines \
--triggers \
-u root -p${DB_ROOT_PASSWORD} \
inmobil > $BACKUP_DIR/db_backup_$DATE.sql
# Comprimir backup de BD
gzip $BACKUP_DIR/db_backup_$DATE.sql
# Backup de uploads
echo "📁 Backup de archivos uploads..."
tar -czf $BACKUP_DIR/uploads_backup_$DATE.tar.gz \
-C /var/lib/docker/volumes/inmobiliaria_app_uploads/_data .
# Backup de configuración
echo "⚙️ Backup de configuración..."
tar -czf $BACKUP_DIR/config_backup_$DATE.tar.gz \
docker-compose.prod.yml \
.env \
docker/
# Sincronizar con storage remoto (S3, etc.)
if command -v aws >/dev/null 2>&1; then
echo "☁️ Sincronizando con S3..."
aws s3 sync $BACKUP_DIR s3://inmobiliaria-backups/daily/ \
--exclude "*" \
--include "*$DATE*"
fi
# Limpiar backups antiguos
echo "🧹 Limpiando backups antiguos..."
find $BACKUP_DIR -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete
find $BACKUP_DIR -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete
echo "✅ Backup completado: $BACKUP_DIR"
docker/scripts/setup.sh)#!/bin/bash
# Script de configuración inicial
set -e
echo "🚀 Configurando entorno Docker para Inmobiliaria..."
# Crear directorios necesarios
mkdir -p {logs,backups,certs,data/mysql,data/redis}
# Generar archivos de configuración
if [ ! -f .env ]; then
echo "📝 Creando archivo .env..."
cat > .env << EOF
# Database
DB_ROOT_PASSWORD=$(openssl rand -base64 32)
DB_PASSWORD=$(openssl rand -base64 32)
# Redis
REDIS_PASSWORD=$(openssl rand -base64 32)
# Grafana
GRAFANA_PASSWORD=$(openssl rand -base64 32)
# Application
APP_ENV=production
APP_DEBUG=false
APP_URL=https://inmobiliaria.com
# WhatsApp
WHATSAPP_NUMBER=573001234567
EOF
echo "✅ Archivo .env creado con passwords seguros"
fi
# Configurar SSL (Let's Encrypt)
if [ ! -f docker/nginx/ssl/fullchain.pem ]; then
echo "🔒 Configurando SSL..."
# Crear certificados de desarrollo
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout docker/nginx/ssl/privkey.pem \
-out docker/nginx/ssl/fullchain.pem \
-subj "/C=CO/ST=Bogota/L=Bogota/O=Inmobiliaria/CN=localhost"
echo "✅ Certificados SSL de desarrollo creados"
fi
# Configurar permisos
sudo chown -R $USER:$USER .
sudo chmod -R 755 uploads/
sudo chmod -R 755 logs/
# Inicializar Docker Swarm (para producción)
if ! docker info | grep -q "Swarm: active"; then
echo "🐋 Inicializando Docker Swarm..."
docker swarm init
echo "✅ Docker Swarm inicializado"
fi
# Crear redes Docker
docker network create inmobiliaria_network 2>/dev/null || true
# Build inicial
echo "🔨 Construyendo imágenes iniciales..."
docker-compose -f docker-compose.yml build
echo "🎉 Setup completado!"
echo ""
echo "📋 Próximos pasos:"
echo "1. Editar .env con tus configuraciones"
echo "2. Ejecutar: docker-compose up -d"
echo "3. Visitar: http://localhost:8080"
echo ""
echo "🔧 Comandos útiles:"
echo "- Ver logs: docker-compose logs -f"
echo "- Entrar al contenedor: docker exec -it inmobiliaria_app bash"
echo "- Backup: ./docker/scripts/backup.sh"
docker/monitoring/prometheus.yml)global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files: []
scrape_configs:
- job_name: 'inmobiliaria-app'
static_configs:
- targets: ['app:9000']
metrics_path: /metrics
scrape_interval: 5s
- job_name: 'mysql'
static_configs:
- targets: ['db:9104']
- job_name: 'redis'
static_configs:
- targets: ['cache:9121']
- job_name: 'nginx'
static_configs:
- targets: ['webserver:9113']
- job_name: 'node-exporter'
static_configs:
- targets: ['node-exporter:9100']
# En docker-compose.prod.yml
services:
app:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
labels: "service,environment"
webserver:
logging:
driver: "fluentd"
options:
fluentd-address: "fluentd:24224"
tag: "nginx."
# Levantar entorno de desarrollo
docker-compose up -d
# Ver logs en tiempo real
docker-compose logs -f app
# Entrar al contenedor de la app
docker exec -it inmobiliaria_app bash
# Ejecutar comandos PHP
docker exec inmobiliaria_app php -v
docker exec inmobiliaria_app composer install
# Reiniciar servicio específico
docker-compose restart app
# Ejecutar tests
docker exec inmobiliaria_app php tests/run_all_tests.php
# Deploy completo
./docker/scripts/deploy.sh v1.2.0 production
# Backup manual
./docker/scripts/backup.sh
# Escalar aplicación
docker-compose -f docker-compose.prod.yml up -d --scale app=5
# Actualizar configuración sin downtime
docker-compose -f docker-compose.prod.yml up -d --no-deps webserver
# Ver métricas de recursos
docker stats
# Limpiar recursos no utilizados
docker system prune -af
# Verificar estado de servicios
docker-compose ps
# Logs de un servicio específico
docker-compose logs app --tail=100
# Entrar a base de datos
docker exec -it inmobiliaria_db mysql -u root -p
# Verificar conectividad entre contenedores
docker exec inmobiliaria_app ping db
# Información detallada de contenedor
docker inspect inmobiliaria_app
# Métricas de rendimiento
docker exec inmobiliaria_app top
# UFW (Ubuntu)
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80
sudo ufw allow 443
sudo ufw --force enable
# Fail2ban para Docker
sudo apt install fail2ban
# docker-compose.prod.yml - Configuraciones de seguridad
services:
app:
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp:rw,size=100M
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
user: "1000:1000"
# Usar Docker Secrets para información sensible
echo "db_password_here" | docker secret create db_password -
echo "redis_password_here" | docker secret create redis_password -
# En docker-compose.prod.yml
services:
app:
secrets:
- db_password
- redis_password
secrets:
db_password:
external: true
redis_password:
external: true
# docker-compose.prod.yml - Múltiples instancias
services:
app:
deploy:
replicas: 5
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
# Crear servicio con auto-scaling
docker service create \
--name inmobiliaria_app \
--replicas 3 \
--limit-memory 512M \
--reserve-memory 256M \
--update-parallelism 1 \
--update-delay 10s \
inmobiliaria_app:latest
# Escalar según demanda
docker service scale inmobiliaria_app=10
# Master-Slave MySQL setup
services:
db_master:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
volumes:
- mysql_master_data:/var/lib/mysql
- ./docker/mysql/master.cnf:/etc/mysql/conf.d/mysql.cnf
command: --log-bin=mysql-bin --server-id=1
db_slave:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
volumes:
- mysql_slave_data:/var/lib/mysql
- ./docker/mysql/slave.cnf:/etc/mysql/conf.d/mysql.cnf
command: --server-id=2 --relay-log=relay-bin
depends_on:
- db_master
Guía completa de despliegue Docker para el Sistema de Gestión Inmobiliaria
Versión 1.0 - Diciembre 2024