Variables de entorno con caracteres especiales en Docker Compose: el problema del dollar y cómo recrear contenedores
Etiquetas: docker,docker-compose,variables-entorno,troubleshootingEl problema real
Llevo meses ejecutando servicios en mi servidor doméstico con Docker Compose. Hace poco intenté configurar una contraseña con caracteres especiales en mi archivo .env. La contraseña era algo como Pass$word123!@. Al iniciar los contenedores, la variable llegaba vacía o malformada. Después de investigar, descubrí que Docker Compose interpretaba el $ como referencia a otra variable.
Por qué sucede: interpolación de variables
Docker Compose interpreta el archivo .env de forma especial. Cuando encuentra un $ seguido de un nombre válido de variable, intenta sustituirlo por su valor. Si esa variable no existe, la deja vacía o genera un error silencioso.
Ejemplo del problema:
# .env
DB_PASSWORD=Pass$word123
API_KEY=sk_test_$random_key
SECRET=$UNDEFINED_VAR
En estos casos, Docker Compose buscará variables llamadas word123, random_key y UNDEFINED_VAR. Obviamente no las encontrará, y tus valores quedarán corruptos.
La solución: comillas simples
La solución más confiable es envolver los valores en comillas simples. Las comillas simples previenen la interpolación de variables en Docker Compose, exactamente como funcionan en bash.
# .env - FORMA CORRECTA
DB_PASSWORD='Pass$word123'
API_KEY='sk_test_$random_key'
SECRET='$UNDEFINED_VAR'
COMPLEX='!@#$%^&*()'
Con comillas simples, Docker Compose trata todo el contenido como texto literal. No intenta resolver referencias a variables.
Usando las variables en docker-compose.yml
Una vez definidas correctamente en .env, usarlas en tu docker-compose.yml es normal:
version: '3.8'
services:
database:
image: postgres:15
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USER}
api:
image: mi-api:latest
environment:
API_KEY: ${API_KEY}
DB_SECRET: ${SECRET}
Docker Compose cargará los valores desde .env e inyectará las variables correctamente en los contenedores.
El segundo problema: restart no recarga variables
Aquí viene lo frustrante. Después de modificar tu archivo .env, ejecutas:
docker-compose restart
Y descubres que los contenedores siguen usando los valores antiguos. Esto sucede porque restart solo reinicia los contenedores existentes sin recrearlos. No vuelve a leer el archivo .env.
La solución: –force-recreate
Para que Docker Compose lea nuevamente el archivo .env y aplique las nuevas variables, debes recrear los contenedores. El comando correcto es:
docker-compose up -d --force-recreate
O si prefieres una secuencia más explícita:
docker-compose down
docker-compose up -d
La opción --force-recreate fuerza la recreación incluso si la imagen no ha cambiado. Sin ella, Docker Compose podría reutilizar contenedores existentes.
Mi flujo de trabajo actual
Después de experimentar con esto, así es como manejo las variables en mi servidor:
-
Defino todo en
.envcon comillas simples:
bash
MYSQL_ROOT_PASSWORD='R00t!$pecial#Pass'
MYSQL_USER='admin'
MYSQL_PASSWORD='Pass$word@123' -
Referencia en
docker-compose.yml:
yaml
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_PASSWORD: ${MYSQL_PASSWORD} -
Después de modificar
.env, siempre uso:
bash
docker-compose up -d --force-recreate -
Verifico que los cambios se aplicaron:
bash
docker-compose exec servicio env | grep MI_VAR
Lecciones aprendidas
- Los caracteres especiales
$,!,@,#en valores requieren comillas simples restartsolo reinicia, no recarga configuración--force-recreatees imprescindible tras modificar.env- Siempre verifica que las variables se hayan cargado correctamente dentro del contenedor
Estos detalles ahorraron muchas horas de debugging en mi setup doméstico. Espero que te ahorren también las tuyas.
Equipamiento recomendado
- Raspberry Pi 3 B+ — Servidor ligero de bajo consumo para empezar tu homelab
- Raspberry Pi 4 (4GB) — La base perfecta para homelab, Docker y monitorización
Enlaces de afiliado. Sin coste extra para ti.