Variables de entorno con caracteres especiales en Docker Compose: el problema del dollar y cómo recrear contenedores

Etiquetas:

El 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:

  1. Defino todo en .env con comillas simples:
    bash
    MYSQL_ROOT_PASSWORD='R00t!$pecial#Pass'
    MYSQL_USER='admin'
    MYSQL_PASSWORD='Pass$word@123'

  2. Referencia en docker-compose.yml:
    yaml
    environment:
    MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
    MYSQL_PASSWORD: ${MYSQL_PASSWORD}

  3. Después de modificar .env, siempre uso:
    bash
    docker-compose up -d --force-recreate

  4. 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
  • restart solo reinicia, no recarga configuración
  • --force-recreate es 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

Enlaces de afiliado. Sin coste extra para ti.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *