# SQL Server 2017 Express - Low RAM Edition 🐳 [![Docker Pulls](https://img.shields.io/docker/pulls/andresgarcia0313/mssql-express-lowram)](https://hub.docker.com/r/andresgarcia0313/mssql-express-lowram) [![Docker Image Size](https://img.shields.io/docker/image-size/andresgarcia0313/mssql-express-lowram/latest)](https://hub.docker.com/r/andresgarcia0313/mssql-express-lowram) Imagen de Docker optimizada para ejecutar **SQL Server 2017 Express** con **bajo consumo de RAM** (384MB - 512MB). ## ✨ Características - 🎯 **RAM mínima:** 384MB (vs 2GB oficial de Microsoft) - ⚡ **Optimizaciones automáticas** al iniciar el contenedor - 🔧 **Trace flags** preconfigurados para estabilidad - 🏥 **Health check** integrado - 📝 **Logs informativos** del proceso de optimización - 🔐 **Contraseña configurable** por variable de entorno ## 🚀 Uso Rápido ```bash docker run -d \ --name mssql \ --memory=384m \ --memory-swap=2g \ -e MSSQL_SA_PASSWORD=MiPassword123! \ -p 1433:1433 \ andresgarcia0313/mssql-express-lowram ``` --- ## 📋 Variables de Entorno ### Variables Requeridas | Variable | Descripción | |----------|-------------| | `MSSQL_SA_PASSWORD` | **REQUERIDO.** Password del usuario SA (administrador) | ### Variables Opcionales | Variable | Default | Descripción | |----------|---------|-------------| | `MSSQL_PID` | `Express` | Edición de SQL Server | | `MSSQL_MEMORY_LIMIT_MB` | `340` | Límite de memoria interna de SQL Server (MB) | | `MSSQL_COLLATION` | `SQL_Latin1_General_CP1_CI_AS` | Collation de la instancia | | `MSSQL_LCID` | `1033` | ID de idioma (1033=English, 3082=Spanish) | | `MSSQL_TCP_PORT` | `1433` | Puerto TCP de SQL Server | | `TZ` | `UTC` | Zona horaria del contenedor | | `ACCEPT_EULA` | `Y` | Ya aceptada en la imagen | ### Valores de MSSQL_PID | Valor | Descripción | Límites | |-------|-------------|---------| | `Express` | **Recomendado.** Gratuito para desarrollo y producción | 1GB RAM, 10GB DB | | `Developer` | Todas las características, solo desarrollo | Sin límites | | `Standard` | Requiere licencia | 128GB RAM | | `Enterprise` | Requiere licencia | Sin límites | ### Requisitos del Password El password de SA debe cumplir: - Mínimo **8 caracteres** - Al menos una letra **mayúscula** (A-Z) - Al menos una letra **minúscula** (a-z) - Al menos un **número** (0-9) - Al menos un **caracter especial** (!@#$%^&*) **Ejemplos válidos:** `MiPassword123!`, `Secure@Pass99`, `Dev#Server2024` --- ## 💾 Configuración de Memoria y Swap ### Parámetros de Docker para Memoria | Parámetro | Descripción | |-----------|-------------| | `--memory` | Límite de RAM física para el contenedor | | `--memory-swap` | Límite total (RAM + Swap). Debe ser mayor que `--memory` | | `--memory-reservation` | Reserva mínima de RAM (soft limit) | | `--memory-swappiness` | Preferencia de uso de swap (0-100) | | `--oom-kill-disable` | Deshabilita OOM killer (usar con cuidado) | ### Configuración Recomendada por Tipo de Disco #### 💿 Para SSD/NVMe (Recomendado) El swap en SSD es rápido, permite configuración más agresiva: ```bash docker run -d \ --name mssql \ --memory=384m \ --memory-swap=4g \ --memory-reservation=256m \ --memory-swappiness=70 \ -e MSSQL_SA_PASSWORD=MiPassword123! \ -e MSSQL_PID=Express \ -e MSSQL_MEMORY_LIMIT_MB=340 \ -p 1433:1433 \ -v mssql_data:/var/opt/mssql/data \ andresgarcia0313/mssql-express-lowram ``` | Parámetro | Valor | Razón | |-----------|-------|-------| | `--memory` | 384m | RAM mínima viable | | `--memory-swap` | 4g | Swap generoso (SSD es rápido) | | `--memory-swappiness` | 60 | Balance entre RAM y swap | #### 🗄️ Para HDD (Disco Mecánico) El swap en HDD es lento, minimizar su uso: ```bash docker run -d \ --name mssql \ --memory=512m \ --memory-swap=1g \ --memory-reservation=384m \ --memory-swappiness=10 \ -e MSSQL_SA_PASSWORD=MiPassword123! \ -e MSSQL_PID=Express \ -e MSSQL_MEMORY_LIMIT_MB=450 \ -p 1433:1433 \ -v mssql_data:/var/opt/mssql/data \ andresgarcia0313/mssql-express-lowram ``` | Parámetro | Valor | Razón | |-----------|-------|-------| | `--memory` | 512m | Más RAM para evitar swap | | `--memory-swap` | 1g | Swap mínimo (HDD lento) | | `--memory-swappiness` | 10 | Evitar swap excepto emergencia | ### Tabla de Configuraciones Recomendadas | Escenario | RAM | Swap | Swappiness | MSSQL_MEMORY_LIMIT_MB | |-----------|-----|------|------------|----------------------| | **Mínimo SSD** | 384m | 4g | 60 | 340 | | **Mínimo HDD** | 512m | 1g | 10 | 450 | | **Desarrollo** | 512m | 2g | 30 | 450 | | **CI/CD** | 512m | 2g | 30 | 450 | | **Múltiples DBs** | 768m | 2g | 20 | 680 | | **Carga moderada** | 1g | 2g | 10 | 900 | --- ## ⚡ Configuración para Máximo Rendimiento ### Desarrollo Local - Máximo Rendimiento ```bash docker run -d \ --name mssql-performance \ --memory=1g \ --memory-swap=2g \ --memory-swappiness=10 \ --cpus=2 \ -e MSSQL_SA_PASSWORD=MiPassword123! \ -e MSSQL_PID=Developer \ -e MSSQL_MEMORY_LIMIT_MB=900 \ -e TZ=America/Bogota \ -p 1433:1433 \ -v mssql_data:/var/opt/mssql/data \ -v mssql_log:/var/opt/mssql/log \ andresgarcia0313/mssql-express-lowram ``` ### Máxima Estabilidad (Producción-like) ```bash docker run -d \ --name mssql-stable \ --memory=768m \ --memory-swap=2g \ --memory-reservation=512m \ --memory-swappiness=20 \ --restart=unless-stopped \ --cpus=2 \ -e MSSQL_SA_PASSWORD=MiPassword123! \ -e MSSQL_PID=Express \ -e MSSQL_MEMORY_LIMIT_MB=680 \ -p 1433:1433 \ -v /path/to/data:/var/opt/mssql/data \ -v /path/to/log:/var/opt/mssql/log \ -v /path/to/backup:/var/opt/mssql/backup \ andresgarcia0313/mssql-express-lowram ``` ### Recursos Mínimos Absolutos ```bash docker run -d \ --name mssql-minimal \ --memory=384m \ --memory-swap=6g \ --memory-swappiness=80 \ -e MSSQL_SA_PASSWORD=MiPassword123! \ -e MSSQL_PID=Express \ -e MSSQL_MEMORY_LIMIT_MB=300 \ -p 1433:1433 \ andresgarcia0313/mssql-express-lowram ``` > ⚠️ Con recursos mínimos, el rendimiento dependerá mucho del swap (requiere SSD). --- ## 🔧 Optimizaciones Incluidas en la Imagen ### Configuración de SQL Server (Automática) | Setting | Valor | Propósito | |---------|-------|-----------| | `max server memory` | 320 MB | Límite del buffer pool | | `min server memory` | 128 MB | Permite liberar RAM bajo presión | | `max degree of parallelism` | 2 | Reduce consumo en queries paralelas | | `cost threshold for parallelism` | 50 | Solo queries costosas usan paralelismo | | `optimize for ad hoc workloads` | ON | Reduce caché de planes únicos | | `recovery interval` | 1 min | Recuperación rápida tras crash | ### Trace Flags Activos (Automáticos) | Flag | Propósito | |------|-----------| | **TF 1117** | Crecimiento uniforme de archivos de datos | | **TF 1118** | Reduce contención en tempdb (extents uniformes) | | **TF 3226** | Suprime logs de backup exitoso (menos I/O) | --- ## 📦 Docker Compose ### Configuración Básica ```yaml version: '3.8' services: sqlserver: image: andresgarcia0313/mssql-express-lowram container_name: mssql mem_limit: 512m memswap_limit: 2g mem_reservation: 384m restart: unless-stopped environment: - MSSQL_SA_PASSWORD=MiPassword123! - MSSQL_PID=Express - MSSQL_MEMORY_LIMIT_MB=450 - TZ=America/Bogota ports: - "1433:1433" volumes: - mssql_data:/var/opt/mssql/data - mssql_log:/var/opt/mssql/log healthcheck: test: /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "$$MSSQL_SA_PASSWORD" -Q "SELECT 1" interval: 30s timeout: 10s retries: 3 volumes: mssql_data: mssql_log: ``` ### Configuración Avanzada (SSD + Rendimiento) ```yaml version: '3.8' services: sqlserver: image: andresgarcia0313/mssql-express-lowram container_name: mssql mem_limit: 768m memswap_limit: 4g mem_reservation: 512m cpus: 2 restart: unless-stopped environment: MSSQL_SA_PASSWORD: ${MSSQL_PASSWORD:-MiPassword123!} MSSQL_PID: Express MSSQL_MEMORY_LIMIT_MB: 680 MSSQL_COLLATION: Modern_Spanish_CI_AS TZ: America/Bogota ports: - "1433:1433" volumes: - mssql_data:/var/opt/mssql/data - mssql_log:/var/opt/mssql/log - mssql_backup:/var/opt/mssql/backup healthcheck: test: /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "$$MSSQL_SA_PASSWORD" -Q "SELECT 1" interval: 30s timeout: 10s start_period: 30s retries: 3 logging: driver: "json-file" options: max-size: "10m" max-file: "3" volumes: mssql_data: driver: local mssql_log: driver: local mssql_backup: driver: local ``` --- ## 🔌 Conexión ### Desde línea de comandos ```bash # Usando sqlcmd dentro del contenedor docker exec -it mssql /opt/mssql-tools/bin/sqlcmd \ -S localhost -U sa -P 'MiPassword123!' # Usando sqlcmd local sqlcmd -S localhost,1433 -U sa -P 'MiPassword123!' ``` ### Connection Strings **.NET / C#** ```csharp Server=localhost,1433;Database=MiDB;User Id=sa;Password=MiPassword123!;TrustServerCertificate=True; ``` **Node.js (mssql)** ```javascript const config = { server: 'localhost', port: 1433, user: 'sa', password: 'MiPassword123!', database: 'MiDB', options: { trustServerCertificate: true } }; ``` **Python (pyodbc)** ```python conn_str = ( "DRIVER={ODBC Driver 17 for SQL Server};" "SERVER=localhost,1433;" "DATABASE=MiDB;" "UID=sa;" "PWD=MiPassword123!;" "TrustServerCertificate=yes;" ) ``` **Java (JDBC)** ```java String url = "jdbc:sqlserver://localhost:1433;database=MiDB;user=sa;password=MiPassword123!;trustServerCertificate=true;"; ``` --- ## 🏗️ Ejemplos de Uso ### CI/CD (GitHub Actions) ```yaml services: sqlserver: image: andresgarcia0313/mssql-express-lowram env: MSSQL_SA_PASSWORD: TestPassword123! MSSQL_PID: Express MSSQL_MEMORY_LIMIT_MB: 450 ports: - 1433:1433 options: >- --memory=512m --memory-swap=2g --health-cmd="/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P TestPassword123! -Q 'SELECT 1'" --health-interval=10s --health-timeout=5s --health-retries=5 ``` ### Kubernetes ```yaml apiVersion: v1 kind: Pod metadata: name: mssql-lowram spec: containers: - name: mssql image: andresgarcia0313/mssql-express-lowram resources: limits: memory: "768Mi" requests: memory: "512Mi" env: - name: MSSQL_SA_PASSWORD valueFrom: secretKeyRef: name: mssql-secret key: sa-password - name: MSSQL_PID value: "Express" - name: MSSQL_MEMORY_LIMIT_MB value: "680" ports: - containerPort: 1433 livenessProbe: exec: command: - /opt/mssql-tools/bin/sqlcmd - -S - localhost - -U - sa - -P - $(MSSQL_SA_PASSWORD) - -Q - SELECT 1 initialDelaySeconds: 30 periodSeconds: 30 ``` --- ## ⚠️ Advertencias - **No recomendado para producción pesada** - La RAM es insuficiente para cargas grandes - **Swap en HDD** - Experimentará lentitud significativa, usar SSD cuando sea posible - **Realizar backups frecuentes** en entornos con recursos limitados - Los **trace flags** se aplican en cada inicio (no persisten en la imagen) - `MSSQL_MEMORY_LIMIT_MB` debe ser **menor** que `--memory` (dejar ~60MB para el OS) --- ## 🔍 Troubleshooting ### Ver logs de optimización ```bash docker logs mssql 2>&1 | grep LOWRAM ``` ### Verificar configuración aplicada ```bash docker exec mssql /opt/mssql-tools/bin/sqlcmd \ -S localhost -U sa -P 'MiPassword123!' \ -Q "SELECT name, value_in_use FROM sys.configurations WHERE name LIKE '%memory%' OR name LIKE '%parallel%'" ``` ### Ver uso de memoria real ```bash docker stats mssql --no-stream ``` ### El contenedor no inicia 1. Verificar que el password cumple los requisitos 2. Verificar que hay suficiente RAM: `docker stats` 3. Revisar logs: `docker logs mssql` 4. Verificar swap disponible: `free -h` ### Rendimiento lento 1. Verificar tipo de disco (SSD vs HDD) 2. Aumentar `--memory` si es posible 3. Reducir `--memory-swappiness` en HDD 4. Verificar que no hay otros contenedores compitiendo por recursos --- ## 🔬 Proceso de Optimización (Trazabilidad) Esta imagen fue creada mediante un proceso de investigación y optimización documentado. A continuación se detalla el proceso completo para reproducibilidad y trazabilidad. ### Problema Original Microsoft SQL Server 2017 tiene un **requisito mínimo oficial de 2GB de RAM**, lo cual es excesivo para: - Desarrollo local en equipos con recursos limitados - Pipelines de CI/CD - Contenedores en entornos de pruebas - Microservicios que solo necesitan una DB pequeña ### Investigación Realizada 1. **Documentación oficial consultada:** - [Configure SQL Server Docker Containers](https://learn.microsoft.com/en-us/sql/linux/sql-server-linux-docker-container-configure) - [SQL Server Linux Performance Best Practices](https://learn.microsoft.com/en-us/sql/linux/sql-server-linux-performance-best-practices) - [KB4347055 - Fix OOM in Docker containers](https://support.microsoft.com/en-us/topic/kb4347055) - [mssql-conf Configuration Tool](https://learn.microsoft.com/en-us/sql/linux/sql-server-linux-configure-mssql-conf) 2. **Hallazgos clave:** - `MSSQL_MEMORY_LIMIT_MB` existe pero requiere versiones recientes - SQL Server 2017 CU10+ incluye fix para respetar límites de contenedor - El 80% de RAM por defecto es configurable vía `sp_configure` - Trace flags pueden mejorar estabilidad en entornos con poca RAM ### Optimizaciones Aplicadas #### 1. Configuración de SQL Server (`sp_configure`) ```sql -- Ejecutado automáticamente al iniciar el contenedor -- Limitar buffer pool (principal consumidor de RAM) EXEC sp_configure 'max server memory', 320; -- Permitir liberar memoria bajo presión del sistema EXEC sp_configure 'min server memory', 128; -- Reducir caché de planes para queries ad-hoc (ahorra RAM) EXEC sp_configure 'optimize for ad hoc workloads', 1; -- Limitar paralelismo (operaciones paralelas consumen más RAM) EXEC sp_configure 'max degree of parallelism', 2; -- Solo queries costosas usan paralelismo EXEC sp_configure 'cost threshold for parallelism', 50; -- Checkpoints frecuentes para recuperación rápida EXEC sp_configure 'recovery interval (min)', 1; ``` #### 2. Trace Flags para Estabilidad ```sql -- Ejecutados automáticamente al iniciar -- TF 1117: Crecimiento uniforme de archivos -- Evita que un archivo crezca más que otros, reduciendo fragmentación DBCC TRACEON(1117, -1); -- TF 1118: Extents uniformes en tempdb -- Reduce contención de páginas mixtas, mejora rendimiento DBCC TRACEON(1118, -1); -- TF 3226: Suprime logs de backup exitoso -- Reduce I/O en el log de errores DBCC TRACEON(3226, -1); ``` #### 3. Entrypoint Personalizado ```bash # El entrypoint realiza: # 1. Valida que MSSQL_SA_PASSWORD esté definido # 2. Inicia SQL Server en foreground # 3. En background, espera que SQL Server esté listo # 4. Aplica todas las optimizaciones automáticamente # 5. Muestra logs informativos del proceso ``` #### 4. Health Check Integrado ```dockerfile HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \ CMD /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "$MSSQL_SA_PASSWORD" -Q "SELECT 1" ``` ### Pruebas de Validación La imagen fue probada durante **6+ minutos** de monitoreo continuo: | Minuto | Estado | RAM | Operación | |--------|--------|-----|-----------| | 0 | ✅ OK | 380.9 MB | Query básica | | 2 | ✅ OK | 381.9 MB | Count de databases | | 4 | ✅ OK | 381.8 MB | CREATE TABLE + 1000 INSERTs | | 6 | ✅ OK | 381.6 MB | Listado de databases | **Resultado:** Sin errores, sin OOM, sin crashes, memoria estable. ### Archivos de la Imagen ``` deploy/docker-mssql/ ├── Dockerfile # Imagen base + labels + health check ├── entrypoint.sh # Validación + inicio + optimización automática ├── optimize.sql # Queries de sp_configure y trace flags ├── build-push.sh # Script para build y push a Docker Hub └── README.md # Esta documentación ``` ### Limitaciones Conocidas | Limitación | Causa | Mitigación | |------------|-------|------------| | RAM mínima ~380MB | Componentes fuera del buffer pool | Usar swap en SSD | | No persisten trace flags | Se aplican en runtime, no en imagen | Se re-aplican en cada inicio | | Rendimiento reducido | Menos RAM = menos caché | Usar SSD, aumentar swap | ### Diferencias vs Imagen Oficial | Aspecto | Imagen Oficial | Esta Imagen | |---------|----------------|-------------| | RAM mínima | 2 GB | 384 MB | | Optimizaciones | Ninguna | Automáticas | | Trace flags | Ninguno | 3 preconfigurados | | Health check | No | Sí | | Validación password | No | Sí (con mensaje de error claro) | | Documentación | Básica | Completa | ### Reproducir las Optimizaciones Manualmente Si prefieres aplicar las optimizaciones a la imagen oficial: ```bash # 1. Iniciar contenedor oficial docker run -d --name mssql --memory=512m \ -e ACCEPT_EULA=Y \ -e MSSQL_SA_PASSWORD=TuPassword123! \ -p 1433:1433 \ mcr.microsoft.com/mssql/server:2017-latest # 2. Esperar que inicie sleep 30 # 3. Aplicar optimizaciones docker exec mssql /opt/mssql-tools/bin/sqlcmd \ -S localhost -U sa -P 'TuPassword123!' -Q " EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'max server memory', 384; RECONFIGURE; EXEC sp_configure 'min server memory', 128; RECONFIGURE; EXEC sp_configure 'optimize for ad hoc workloads', 1; RECONFIGURE; EXEC sp_configure 'max degree of parallelism', 2; RECONFIGURE; EXEC sp_configure 'cost threshold for parallelism', 50; RECONFIGURE; EXEC sp_configure 'recovery interval (min)', 1; RECONFIGURE; DBCC TRACEON(1117, -1); DBCC TRACEON(1118, -1); DBCC TRACEON(3226, -1); " ``` --- ## 📊 Basado en - **Microsoft SQL Server 2017 Express** (CU31 - versión 14.0.3515.1) - Imagen base: `mcr.microsoft.com/mssql/server:2017-latest` - Documentación oficial de Microsoft para SQL Server en Linux ## 📄 Licencia - **SQL Server Express**: Gratuito para desarrollo y producción (con límites) - **Scripts de optimización**: MIT License ## 👤 Autor **andresgarcia0313** - GitHub: [@andresgarcia0313](https://github.com/andresgarcia0313) - Docker Hub: [andresgarcia0313](https://hub.docker.com/u/andresgarcia0313) --- ⭐ Si esta imagen te fue útil, considera dejar una estrella en el repositorio.