Casi todos los textos sobre este problema culpan al volumen, y por eso mismo la solución tarda tanto. Tenías un bind mount que funcionaba, la VPN corporativa se conectó y docker compose up ahora falla con una ruta de origen que falta, un directorio vacío o un montaje que el motor se niega a crear. En los entornos que he limpiado, el archivo Compose no había cambiado y la ruta era correcta. Lo que cambió fue qué demonio recibió la petición, y el error de montaje fue solo el primer lugar donde esa diferencia se hizo visible.

El volumen nunca se movió; la petición sí

El -v /srv/app:/app no es una copia de directorio que haga tu shell. El cliente lo convierte en una petición de API, y el demonio que responde resuelve /srv/app contra su propio sistema de archivos. Cuando ambos lados se ejecutan en el mismo núcleo, esa ruta es la que ves en tu gestor de archivos. Cuando el endpoint cambia, la misma cadena se busca en una máquina que nunca ha oído hablar del directorio de tu proyecto, y el demonio o bien informa que falta el origen o crea en silencio un directorio vacío en su lugar.

También es por eso que un volumen con nombre sigue funcionando mientras que un bind mount no. -v appdata:/app nombra almacenamiento que el demonio posee, así que ninguna ruta del host tiene que existir en ningún lugar concreto. Si cambiar un servicio de un bind mount a un volumen con nombre hace desaparecer el error, no has arreglado el problema. Has confirmado que el cliente y el demonio no están de acuerdo sobre a qué sistema de archivos pertenece la ruta, y ese desacuerdo vuelve en el momento en que necesitas otra vez un directorio real del host.

Imprime el endpoint antes de tocar el montaje

Varias opciones pueden apuntar el cliente a un endpoint, y no siempre coinciden: la opción --context , DOCKER_CONTEXT, DOCKER_HOST en la shell actual y el contexto guardado en la configuración del cliente. En lugar de razonar sobre la precedencia, imprímelos todos y compara las respuestas.

docker context show
docker context ls
docker version
docker info --format "{{.Name}} {{.OperatingSystem}} {{.ServerVersion}}"

La configuración del cliente está en ~/.docker/config.json en Linux y macOS y en %USERPROFILE%\.docker\config.json en Windows, y un valor exportado en la terminal actual sustituye al guardado solo para esa sesión. Si el endpoint es un nombre de host en lugar de un socket local, la resolución de nombres y las rutas deciden dónde aterriza, y son precisamente lo que reescribe un cliente VPN. Un túnel que añade una ruta o cambia el resolutor puede enviar un nombre que antes significaba este portátil a una dirección dentro de la red corporativa.

Compara estado en lugar de configuración. Ejecuta docker ps -a y docker images con el túnel desconectado, y luego otra vez conectado. Una lista de contenedores distinta es una prueba más sólida que cualquier archivo de configuración, porque muestra que otro demonio respondió a tu petición.

Pregunta al demonio si la ruta existe allí

Cuando sepas a qué demonio llegaste, haz que mire el directorio. La forma --mount falla con un mensaje más claro que la opción corta, porque valida el origen antes de iniciar el contenedor:

docker run --rm --mount type=bind,source=/srv/app,target=/app alpine ls -la /app

Si informa que falta el origen, créalo en la máquina que respondió, o apunta el servicio a un volumen con nombre y copia los datos allí. Lo que no deberías hacer es recrear volúmenes y reinstalar el motor antes de esta comprobación. Esas acciones cambian el entorno lo suficiente como para ocultar la discrepancia mientras la dejan en su sitio.

Hay otra ruta que se ejecuta en un lugar completamente distinto: descargar una imagen es trabajo del demonio, no del cliente. Una descarga correcta solo demuestra que el demonio puede llegar a un registry, y un bind mount que funciona solo demuestra que una ruta se resolvió. Prueba cada ruta donde se ejecuta de verdad, o pasarás una tarde con la equivocada.

Los nombres de intranet fallan por otro motivo

La segunda mitad del mismo informe suele ser que el contenedor no puede llegar a intranet.corp.example. Ese es un mecanismo aparte, no un segundo problema de volumen. Un contenedor obtiene su /etc/resolv.conf al arrancar, generado a partir de la configuración del resolutor del demonio, así que un servidor DNS que la VPN añadió después de crear el contenedor no aparecerá ahí hasta que el contenedor se recree.

El resolutor integrado de Docker en una red definida por el usuario reenvía las consultas externas a los servidores configurados del host, lo que ayuda cuando la VPN reescribe el resolutor del host y perjudica cuando el DNS dividido envía una zona interna a un servidor que el demonio ya no ve. Un mapeo estrecho y explícito evita la discusión para nombres que nunca cambian:

services:
  web:
    extra_hosts:
      - "intranet.corp.example:10.20.30.40"

Esto escribe una entrada en el archivo hosts del contenedor, así que el contenedor no aprende nada del túnel, y además congela la dirección. Cuando el host interno se mueve, la entrada sigue mal hasta que alguien edita el archivo Compose. Úsalo para un dispositivo fijo o una base de datos fijada, y deja que el DNS gestione los nombres que se mueven.

Qué cambia realmente una reinstalación

Reinstalar Docker Desktop recrea la VM, el socket y la lista de contextos, y el montaje vuelve a funcionar. Ese resultado es real y no enseña nada, y por eso el mismo fallo vuelve tras la siguiente actualización de la VPN. La reinstalación sustituyó el endpoint que usaba el cliente; no reconcilió la ruta que nombra tu proyecto con el sistema de archivos que el demonio lee de verdad.

Mi orden de trabajo es corto. Confirma qué endpoint usará el cliente. Confirma qué demonio respondió comparando listas de contenedores. Pide a ese demonio que liste la ruta de origen. Solo entonces edita el montaje, añade una entrada hosts o cambia un tipo de volumen. Si mantienes el archivo Compose para un equipo que trabaja por VPN, prefiere volúmenes con nombre para los datos que el demonio debe poseer, para que una ruta del host nunca forme parte del contrato.

Artículos relacionados