Docker: - docker-compose.yml: optimize resource allocation - start.sh: improve startup sequence - docker-mssql/: add standalone SQL Server config for local dev Kubernetes (K3s): - hpa.yaml: adjust autoscaling thresholds - kustomization.yaml: add new resource references - secrets.yaml: update secret structure Utility scripts: - start.backend.sh: fix environment variables - start.db.sh: database initialization script - start.db.simple.sh: simplified DB startup - generate-docs.sh: PlantUML diagram generation Misc: - index.html: landing page redirect Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| Dockerfile | ||
| README.md | ||
| build-push.sh | ||
| entrypoint.sh | ||
| optimize.sql | ||
| update-dockerhub-readme.sh | ||
README.md
SQL Server 2017 Express - Low RAM Edition 🐳
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
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:
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:
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
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)
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
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
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)
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
# 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#
Server=localhost,1433;Database=MiDB;User Id=sa;Password=MiPassword123!;TrustServerCertificate=True;
Node.js (mssql)
const config = {
server: 'localhost',
port: 1433,
user: 'sa',
password: 'MiPassword123!',
database: 'MiDB',
options: { trustServerCertificate: true }
};
Python (pyodbc)
conn_str = (
"DRIVER={ODBC Driver 17 for SQL Server};"
"SERVER=localhost,1433;"
"DATABASE=MiDB;"
"UID=sa;"
"PWD=MiPassword123!;"
"TrustServerCertificate=yes;"
)
Java (JDBC)
String url = "jdbc:sqlserver://localhost:1433;database=MiDB;user=sa;password=MiPassword123!;trustServerCertificate=true;";
🏗️ Ejemplos de Uso
CI/CD (GitHub Actions)
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
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_MBdebe ser menor que--memory(dejar ~60MB para el OS)
🔍 Troubleshooting
Ver logs de optimización
docker logs mssql 2>&1 | grep LOWRAM
Verificar configuración aplicada
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
docker stats mssql --no-stream
El contenedor no inicia
- Verificar que el password cumple los requisitos
- Verificar que hay suficiente RAM:
docker stats - Revisar logs:
docker logs mssql - Verificar swap disponible:
free -h
Rendimiento lento
- Verificar tipo de disco (SSD vs HDD)
- Aumentar
--memorysi es posible - Reducir
--memory-swappinessen HDD - 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
-
Documentación oficial consultada:
-
Hallazgos clave:
MSSQL_MEMORY_LIMIT_MBexiste 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)
-- 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
-- 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
# 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
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:
# 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
- Docker Hub: andresgarcia0313
⭐ Si esta imagen te fue útil, considera dejar una estrella en el repositorio.