academia/deploy/docker-mssql/README.md

672 lines
18 KiB
Markdown
Raw Permalink Normal View History

# 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.