Los perfiles de Docker Compose permiten mantener servicios opcionales en un mismo compose.yaml y activarlos solo cuando hacen falta. Son útiles para herramientas de depuración, pruebas, migraciones, paneles administrativos u observabilidad.

Activacion de perfiles

Sin embargo, hay una distinción importante: un perfil selecciona servicios, pero no crea por sí mismo un entorno aislado. Para ejecutar desarrollo, staging y producción sin colisiones también se necesitan nombres de proyecto, configuraciones, redes, volúmenes y secretos independientes.

Qué vas a implementar

La configuración de ejemplo tendrá:

  • app y db como servicios principales, siempre disponibles.
  • adminer dentro del perfil debug.
  • smoke-test dentro del perfil test.
  • Nombres de proyecto diferentes para cada entorno.
  • Archivos de variables y overrides específicos.
  • Comandos para validar la configuración antes de iniciarla.

Requisitos previos

Necesitas:

  • Docker Engine instalado y activo.
  • Docker Compose v2, invocado como docker compose.
  • Permisos para administrar contenedores.
  • Una imagen de la aplicación que escuche en el puerto interno 8080.
  • Un endpoint de comprobación, como /health.
  • Secretos y datos de producción almacenados fuera del repositorio.

Comprueba las versiones instaladas:

docker version
docker compose version
docker info

El borrador utilizaba docker compose info, pero ese no es el comando apropiado: la información del motor se obtiene con docker info.

Cómo funcionan los profiles

Los servicios que no tienen el atributo profiles están siempre habilitados. Los servicios perfilados solo se incorporan cuando se activa alguno de sus perfiles.

services:
  app:
    image: ejemplo/app

  debugger:
    image: ejemplo/debugger
    profiles: ["debug"]

En este caso:

docker compose up

inicia únicamente app. En cambio:

docker compose --profile debug up

incluye también debugger.

Docker recomienda dejar los servicios principales sin perfiles. Además, si se selecciona directamente un servicio perfilado, Compose lo ejecuta junto con sus dependencias, pero no inicia automáticamente los demás servicios que compartan ese perfil. Documentación oficial sobre profiles.

Paso 1: preparar la estructura

Trabaja primero en un entorno de prueba:

mkdir -p ~/compose-profiles/{secrets,config}
cd ~/compose-profiles
umask 077

Estructura propuesta:

compose-profiles/
├── compose.yaml
├── compose.dev.yaml
├── compose.prod.yaml
├── .env.dev
├── .env.prod
└── secrets/
    └── db_password.txt

No guardes contraseñas, tokens ni claves reales en Git. Para producción, utiliza el mecanismo de secretos disponible en tu plataforma. Los secretos de Compose basados en archivos son montajes controlados, no un gestor centralizado de secretos.

Paso 2: definir los servicios y perfiles

Crea compose.yaml:

services:
  app:
    image: ${APP_IMAGE:?Debes definir APP_IMAGE}
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "127.0.0.1:${APP_PORT:-8080}:8080"
    networks:
      - backend

  db:
    image: postgres:17-alpine
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: app
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password
    volumes:
      - db_data:/var/lib/postgresql/data
    networks:
      - backend
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 5

  adminer:
    image: adminer:standalone
    profiles: ["debug"]
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "127.0.0.1:8081:8080"
    networks:
      - backend

  smoke-test:
    image: curlimages/curl:8.12.1
    profiles: ["test"]
    depends_on:
      app:
        condition: service_started
    command:
      - "--fail"
      - "--silent"
      - "--show-error"
      - "--retry"
      - "10"
      - "--retry-connrefused"
      - "http://app:8080/health"
    networks:
      - backend

networks:
  backend:

volumes:
  db_data:

secrets:
  db_password:
    file: ./secrets/db_password.txt

Antes de ejecutarlo:

  • Sustituye APP_IMAGE por una imagen aprobada.
  • Confirma que la aplicación escucha en 8080.
  • Ajusta /health si utiliza otra ruta.
  • Fija las imágenes por digest en producción.
  • No expongas Adminer públicamente; el binding a 127.0.0.1 limita el acceso al propio servidor.

Paso 3: separar la configuración de cada entorno

Ejemplo de .env.dev:

APP_IMAGE=registro.ejemplo.com/miapp:dev
APP_PORT=8080

Ejemplo de .env.prod:

APP_IMAGE=registro.ejemplo.com/miapp@sha256:DIGEST_VERIFICADO
APP_PORT=8080

El archivo indicado mediante --env-file se utiliza para interpolar valores del modelo Compose. No introduce automáticamente todas esas variables dentro de los contenedores y no debe tratarse como almacén de secretos. Variables e interpolación en Compose.

Cuando un entorno necesite cambios estructurales, utiliza un archivo adicional. Por ejemplo, compose.prod.yaml:

services:
  app:
    restart: unless-stopped

  db:
    restart: unless-stopped

Compose combina los archivos en el orden especificado; los posteriores agregan o sobrescriben valores. Conviene revisar siempre el resultado final con docker compose config. Reglas oficiales de combinación.

Paso 4: validar antes de aplicar

Primero valida la configuración base:

docker compose \
  -p miapp-dev \
  --env-file .env.dev \
  -f compose.yaml \
  config --quiet

Muestra los perfiles declarados:

docker compose \
  --env-file .env.dev \
  -f compose.yaml \
  config --profiles

Comprueba los servicios del perfil debug:

docker compose \
  --profile debug \
  --env-file .env.dev \
  -f compose.yaml \
  config --services

Para inspeccionar el modelo efectivo de producción:

docker compose \
  -p miapp-prod \
  --env-file .env.prod \
  -f compose.yaml \
  -f compose.prod.yaml \
  config

docker compose config resuelve variables, combina archivos y representa el modelo que Compose aplicará. La opción --quiet valida sin imprimirlo. Referencia del comando.

El comando docker build --check del borrador no valida un archivo Compose. Solo es pertinente cuando existe un Dockerfile que realmente se va a construir.

Paso 5: iniciar los servicios

Inicia únicamente los servicios principales:

docker compose \
  -p miapp-dev \
  --env-file .env.dev \
  -f compose.yaml \
  up -d

Activa también el perfil de depuración:

docker compose \
  -p miapp-dev \
  --profile debug \
  --env-file .env.dev \
  -f compose.yaml \
  up -d

Activa varios perfiles:

docker compose \
  -p miapp-dev \
  --profile debug \
  --profile test \
  --env-file .env.dev \
  -f compose.yaml \
  up -d

También pueden declararse mediante una variable:

COMPOSE_PROFILES=debug,test docker compose up -d

Para habilitar todos los perfiles:

docker compose --profile "*" up -d

Esta última opción es útil para pruebas, pero debe usarse con precaución en hosts compartidos o productivos.

Ejecutar directamente un servicio perfilado

La prueba puede ejecutarse sin activar manualmente test:

docker compose \
  -p miapp-dev \
  --env-file .env.dev \
  -f compose.yaml \
  run --rm smoke-test

Compose ejecutará smoke-test porque fue seleccionado explícitamente y levantará sus dependencias declaradas. No iniciará adminer ni otros servicios perfilados que no sean necesarios.

Esta característica es especialmente útil para migraciones, tareas administrativas y verificaciones puntuales.

Paso 6: comprobar el resultado

Revisa todos los contenedores, incluidos los detenidos:

docker compose -p miapp-dev ps --all

Comprueba la aplicación:

curl -fsS http://127.0.0.1:8080/health

Consulta los registros relevantes:

docker compose -p miapp-dev logs --tail=100 app db

Comprueba el consumo puntual:

docker stats --no-stream

Para acceder a Adminer desde otro equipo, utiliza un túnel SSH en lugar de publicar el puerto en Internet:

ssh -L 8081:127.0.0.1:8081 usuario@TU_IP

Luego abre http://127.0.0.1:8081 en el equipo local.

Profiles frente a separación real de entornos

No ejecutes desarrollo y producción con el mismo nombre de proyecto. Compose utiliza ese nombre para construir los nombres de redes, contenedores y volúmenes.

docker compose -p miapp-dev up -d
docker compose -p miapp-stg up -d
docker compose -p miapp-prod up -d

El nombre puede establecerse con -p, COMPOSE_PROJECT_NAME o el atributo superior name. La opción -p tiene mayor precedencia. Nombres de proyecto en Compose.

Una separación consistente requiere:

  • Nombre de proyecto distinto.
  • Archivos de configuración y variables independientes.
  • Redes y volúmenes no compartidos.
  • Secretos y credenciales diferentes.
  • Puertos de host sin colisiones.
  • Permisos y acceso al Docker daemon controlados.

Los perfiles no son control de acceso. Un usuario con permisos sobre Docker puede activar cualquier perfil definido.

Detener un servicio opcional

Para detener y retirar únicamente Adminer:

docker compose -p miapp-dev stop adminer
docker compose -p miapp-dev rm -f adminer

No uses docker compose down -v como rollback habitual: la opción -v elimina los volúmenes declarados y puede destruir datos.

Si una modificación del archivo falla, recupera la versión anterior desde el control de versiones, valida nuevamente con config --quiet y vuelve a ejecutar up -d.

Problemas frecuentes

El servicio perfilado no aparece

Comprueba los perfiles y servicios reconocidos:

docker compose config --profiles
docker compose --profile debug config --services

Revisa también la indentación YAML y que el nombre del perfil coincida exactamente.

Se inició un servicio aunque su perfil no estaba activo

Puede haber sido seleccionado explícitamente:

docker compose run servicio
docker compose up servicio

La selección directa habilita ese servicio y sus dependencias.

Compose informa una dependencia inválida

Una dependencia perfilada debe estar disponible en el conjunto activo. Mantén los servicios principales sin perfiles y evita que un servicio base dependa de una herramienta opcional.

Desarrollo y producción comparten recursos

Comprueba el nombre del proyecto:

docker compose ls
docker compose -p miapp-dev ps
docker compose -p miapp-prod ps

Revisa además los nombres de volúmenes y redes. No marques como external un recurso que no deba compartirse.

Una variable no llega al contenedor

--env-file puede estar utilizándose solo para interpolar el archivo Compose. Si la aplicación necesita la variable dentro del contenedor, declárala explícitamente mediante environment, env_file o un secreto, según su sensibilidad.

Buenas prácticas

  • Deja los servicios principales sin profiles.
  • Usa perfiles para componentes opcionales y tareas puntuales.
  • Valida cada combinación relevante con docker compose config.
  • Conserva una matriz documentada de perfiles permitidos por entorno.
  • Fija imágenes por digest y revisa sus actualizaciones.
  • Restringe paneles de administración a localhost o a una red privada.
  • Mantén separados datos, redes, credenciales y nombres de proyecto.
  • Prueba restauración y rollback sin utilizar datos productivos.

Cloud Serversby Donweb

Todo el poder de la nube a tus proyectos y aplicaciones.
Alojamiento ultra rápido, escalable y con alta disponibilidad.

  • Performance que te sorprenderá
  • Rápida escalabilidad y sin limitaciones
  • Arquitectura de alta disponibilidad
  • Soporte experto y ejecutivos de cuenta
  • Pagos en tu moneda y facturación local

Descubre la mejor solución de Cloud Hosting