La mayoría de las guías “WSL2 + Docker” parecen escritas como si nadie hubiese entregado software con presión de tiempo. Saltan las partes donde tus contenedores van a paso de tortuga porque clonaste un repositorio en el directorio equivocado, o Docker Desktop decide que tus imágenes “desaparecieron” porque “limpiaste” WSL. Y luego llega el lunes.
Esta es la forma orientada a producción para configurar WSL2 de modo que Docker se mantenga rápido, predecible y recuperable. Es opinada porque la realidad lo es.
La forma correcta: qué estás realmente construyendo
No estás “instalando Linux en Windows”. Estás montando una pequeña pila de virtualización gestionada:
- Windows aloja la infraestructura adyacente al kernel (componentes Hyper-V) que usa WSL2.
- WSL2 ejecuta una o más distribuciones Linux dentro de una VM ligera. Cada distro tiene su propio disco virtual (un VHDX).
- Docker se ejecuta de dos formas:
- Docker Desktop, que ejecuta su propia VM Linux y puede integrarse con las distros WSL2, o
- Docker Engine dentro de una distro WSL2 (sin Docker Desktop), con systemd y comportamiento nativo de Linux.
La configuración que “no rompe” se reduce a tres temas:
- Pon los archivos correctos en el sistema de archivos correcto. Linux sobre Linux para builds, node_modules y capas de imagen. Rutas de Windows solo cuando realmente necesites herramientas de Windows.
- Controla los recursos deliberadamente. WSL2 consumirá RAM y disco hasta que tu portátil se convierta en un calentador con teclado.
- Elige un modelo de propiedad de Docker. O Docker Desktop administra Docker, o lo hace tu distro Linux. Mezclarlos sin intención es la forma de llegar al “ayer funcionaba”.
Una cita para tener sobre el monitor: La esperanza no es una estrategia.
— General Gordon R. Sullivan
Hechos y contexto interesantes (para que dejes de cometer errores de 2019)
- WSL1 no era una VM. Traducía llamadas de sistema de Linux a llamadas del kernel de Windows. Un truco excelente, pero no era “Linux real”, y Docker en WSL1 era un proyecto experimental.
- WSL2 cambió a un kernel Linux real. Por eso Docker se volvió práctico. También por eso ahora tienes un disco virtual real que puede llenarse y fragmentarse.
- Las primeras versiones de WSL2 tuvieron dolores notorios de E/S en /mnt/c. Por eso “clonar en el home de Linux” se volvió el consejo por defecto—y sigue siendo correcto para la mayoría de cargas de desarrollo.
- Docker Desktop movió su backend varias veces. Backend Hyper-V, luego backend WSL2, además de comportamientos de integración cambiantes entre versiones. Los posts antiguos mienten por accidente.
- La red de WSL2 usa NAT. Por eso la VM WSL2 tiene su propia IP y por qué algunas configuraciones de VPN/DNS se comportan como si estuvieran embrujadas.
- La “reducción” del VHDX no es automática. Borrar archivos en Linux no devuelve necesariamente espacio a Windows. Necesitas pasos explícitos de compactación.
- El soporte de systemd en WSL es reciente. Durante años fue “no systemd”, lo que cambió la forma en que servicios y Docker se comportaban. Ahora puedes activarlo, pero muchas guías aún asumen que no se puede.
- Las diferencias en sensibilidad por mayúsculas son reales. Los sistemas de archivos de Windows suelen ser insensibles a mayúsculas; Linux es sensible. Esto aparece como diffs raros en Git, builds rotos o archivos duplicados.
WSL2 + Docker: arquitectura y bordes afilados
Dos modelos soportados (elige uno)
Modelo A: Docker Desktop + integración WSL2. Docker Desktop gobierna el daemon. Tu distro WSL tiene acceso al cliente Docker y puede ejecutar contenedores, pero el “estado real” de Docker vive en el entorno gestionado por Docker Desktop.
Modelo B: Docker Engine dentro de una distro WSL2. Tu distro posee el daemon y el almacenamiento. Se siente más como un servidor Linux. Es ideal si quieres comportamiento nativo de Linux y menos sorpresas de una app GUI.
La realidad del almacenamiento: donde vive o muere el rendimiento
El sistema de archivos Linux en WSL2 (el ext4 de tu distro dentro del VHDX) es rápido para herramientas Linux. Los archivos montados desde Windows bajo /mnt/c son más lentos y tienen sobrecarga de traducción de metadatos. Los bind mounts de Docker y los contextos de build amplifican esa sobrecarga.
Si ejecutas builds en rutas de Windows y las montas en contenedores Linux, te estás pidiendo problemas de rendimiento. También puedes estar pidiendo comportamientos extraños de los watch (especialmente con Node, Python o cualquier herramienta que use inotify).
Red: “localhost funciona” hasta que deja de hacerlo
WSL2 tiene su propia interfaz de red virtual. Windows y WSL2 cooperan para que “localhost” funcione a menudo en ambos sentidos, pero el camino no es simétrico y no está garantizado con VPNs, firewalls o DNS personalizados.
Docker añade sus propios espacios de nombres de red y redes puente dentro del entorno Linux. Las capas de traducción se apilan, y cada capa es un nuevo lugar donde la latencia, problemas de MTU o la resolución de nombres pueden fallar.
Broma #1: NAT es como la gerencia intermedia—útil en teoría, pero a veces tus paquetes salen de la reunión más confundidos que cuando entraron.
Reglas no negociables que mantienen Docker sin fallos
Regla 1: Mantén el código fuente en el sistema de archivos Linux a menos que haya una razón fuerte
Por defecto: clona en ~/src dentro de WSL. Construye ahí. Ejecuta Docker desde ahí. Tu vida mejora.
Hay excepciones (flujos de trabajo con IDEs solo para Windows, restricciones de seguridad corporativa), pero deberías tratar las excepciones como solicitudes de cambio en producción: documentadas, justificadas y reversibles.
Regla 2: No dejes que los datos de Docker atraviesen fronteras de propiedad
Si usas Docker Desktop, déjalo poseer el engine y su almacenamiento. No ejecutes además un dockerd separado dentro de tu distro a menos que intencionalmente quieras dos daemons (la mayoría no lo hace).
Regla 3: Controla los recursos de WSL con un .wslconfig
WSL sin límites puede dejar a Windows sin recursos. Eso puede parecer “Docker está lento”, “VS Code va con retraso” o “mi ventilador es ahora mi dispositivo de entrada principal”. Pon límites y luego afina.
Regla 4: Trata las distros WSL como ganado, pero exporta antes de cirugía
WSL facilita eliminar y recrear una distro. Eso es una característica. Pero imágenes Docker, volúmenes y bases de datos dentro de WSL son estado. Exporta o haz snapshot antes de “reinstalar Ubuntu rápido”.
Regla 5: Nunca depures rendimiento sin medir el límite del sistema de archivos
Cuando Docker se siente lento, necesitas responder: ¿estamos en I/O lento en /mnt/c, o es CPU/memoria/red? Adivinar es la forma de quemar tardes.
Tareas prácticas (comandos, salidas, decisiones)
Estos son los comandos del día a día que mantienen WSL2 + Docker aburridos. Cada tarea incluye: comando, qué significa la salida y qué decisión tomar después.
Task 1: Confirmar versiones de WSL y la distro por defecto
cr0x@server:~$ wsl -l -v
NAME STATE VERSION
* Ubuntu-22.04 Running 2
docker-desktop Running 2
docker-desktop-data Running 2
Significado: Tienes Ubuntu en WSL2, más las distros internas de Docker Desktop. Eso es normal para el Modelo A.
Decisión: Si no quieres Docker Desktop, no deberías ver las distros docker-desktop. Si las ves, estás en el Modelo A te des cuenta o no.
Task 2: Comprobar la versión del kernel WSL (sanidad + contexto de bugs)
cr0x@server:~$ wsl --status
Default Distribution: Ubuntu-22.04
Default Version: 2
WSL version: 2.1.5.0
Kernel version: 5.15.133.1-1
WSLg version: 1.0.59
MSRDC version: 1.2.4677
Direct3D version: 1.611.1-81528511
DXCore version: 10.0.26091.1-240325-1447.ge-release
Windows version: 10.0.22631.3085
Significado: WSL moderno con un kernel basado en 5.15. Muchos problemas antiguos de red y systemd dependen de la versión del kernel/WSL.
Decisión: Si estás en una versión mucho más antigua de WSL, actualiza antes de perseguir fantasmas. Depurar builds antiguas de WSL es pagar intereses sobre deuda técnica.
Task 3: Verificar la propiedad de Docker (Desktop vs in-distro)
cr0x@server:~$ docker context ls
NAME DESCRIPTION DOCKER ENDPOINT ERROR
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock
desktop-linux Docker Desktop unix:///var/run/docker.sock
Significado: Existen contextos; en WSL, ambos pueden apuntar a un socket Unix dependiendo de la integración.
Decisión: Elige un contexto y apégate a él por flujo de trabajo. Si los contextos cambian sin avisar, eso es un problema de configuración, no de “Docker es inestable”.
Task 4: Comprobar si systemd está habilitado en la distro WSL (prerrequisito del Modelo B)
cr0x@server:~$ cat /etc/wsl.conf
[boot]
systemd=true
Significado: systemd está habilitado. Puedes ejecutar docker.service correctamente dentro de WSL (Modelo B).
Decisión: Si quieres el Modelo B y esto falta, añádelo y reinicia WSL. Si quieres el Modelo A (Docker Desktop), normalmente no necesitas dockerd dentro de la distro.
Task 5: Reiniciar WSL limpiamente después de cambios de configuración
cr0x@server:~$ wsl --shutdown
The operation completed successfully.
Significado: Todas las VMs WSL han parado. El siguiente inicio volverá a leer la configuración.
Decisión: Haz esto después de cambiar .wslconfig o /etc/wsl.conf. Si no lo haces, estarás depurando una configuración que en realidad no aplicaste.
Task 6: Medir dónde vive tu repo (filesystem Linux vs montaje Windows)
cr0x@server:~$ pwd
/home/cr0x/src/myapp
Significado: El repo está en el sistema de archivos Linux. Bueno para contextos de build y bind mounts de Docker.
Decisión: Si estás bajo /mnt/c/..., espera I/O más lento. Mueve el repo a menos que tengas un requisito innegociable para mantenerlo en Windows.
Task 7: Demostrar rápidamente el límite de rendimiento (fio)
cr0x@server:~$ fio --name=randread --filename=/home/cr0x/fio.test --size=256M --bs=4k --rw=randread --iodepth=32 --numjobs=1 --runtime=10 --time_based --direct=1
randread: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=32
fio-3.33
Starting 1 process
randread: Laying out IO file (1 file / 256MiB)
randread: (groupid=0, jobs=1): err= 0: pid=221: Fri Feb 2 10:01:16 2026
read: IOPS=21.4k, BW=83.5MiB/s (87.6MB/s)(835MiB/10000msec)
Significado: Estás obteniendo IOPS de lectura aleatoria saludables en el sistema de archivos Linux.
Decisión: Ejecuta la misma prueba en /mnt/c. Si las IOPS caen en picado, deja de culpar a Docker y deja de construir en montajes de Windows.
Task 8: Comprobar driver de almacenamiento de Docker y root dir (dónde viven realmente tus capas)
cr0x@server:~$ docker info --format 'RootDir={{.DockerRootDir}} Driver={{.Driver}} Cgroup={{.CgroupDriver}}'
RootDir=/var/lib/docker Driver=overlay2 Cgroup=systemd
Significado: Docker usa overlay2 y guarda datos en /var/lib/docker dentro del entorno Linux que posee el daemon.
Decisión: Si ves un RootDir inesperado o un driver que no planificaste, no estás ejecutando el daemon que crees que ejecutas.
Task 9: Encontrar dónde vive el VHDX en Windows (planificación de capacidad)
cr0x@server:~$ powershell.exe -NoProfile -Command "Get-ChildItem -Recurse $env:LOCALAPPDATA\Packages\*Ubuntu*\LocalState\ext4.vhdx | Select-Object FullName,Length"
FullName Length
-------- ------
C:\Users\cr0x\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu22.04LTS_79rhkp1fndgsc\LocalState\ext4.vhdx 64424509440
Significado: El disco virtual de tu distro Ubuntu tiene 60 GiB en C:. Ahí vive tu sistema de archivos Linux.
Decisión: Si C: es pequeño o está protegido por políticas corporativas, planifica un movimiento controlado usando export/import (tareas posteriores). Mover carpetas al azar es la forma de crear estados WSL irrecuperables.
Task 10: Comprobar uso de disco de WSL desde Linux (antes de “limpiar”)
cr0x@server:~$ df -hT /
Filesystem Type Size Used Avail Use% Mounted on
/dev/sdb ext4 251G 96G 143G 41% /
Significado: El sistema de archivos raíz de Linux tiene espacio. Esto está dentro del VHDX.
Decisión: Si Use% es alto, limpia desde Linux primero (docker prune, limpieza de logs). No asumas que Windows verá el espacio liberado después.
Task 11: Identificar los mayores consumidores de espacio de Docker (imágenes/volúmenes)
cr0x@server:~$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 24 6 18.3GB 12.7GB (69%)
Containers 11 2 1.4GB 1.1GB (78%)
Local Volumes 13 5 22.9GB 9.6GB (41%)
Build Cache 0 0 0B 0B
Significado: Los volúmenes son los que más pesan. Las imágenes también son recuperables.
Decisión: Si necesitas liberar disco, primero prunea imágenes/contenedores y luego audita volúmenes cuidadosamente. Prunear volúmenes a ciegas es la forma de “borrar accidentalmente” la base de datos local de alguien.
Task 12: Limpieza relativamente segura (prune con intención)
cr0x@server:~$ docker image prune -a
WARNING! This will remove all images without at least one container associated to them.
Are you sure you want to continue? [y/N] y
Deleted Images:
deleted: sha256:3f1e2a0f7c8d...
Total reclaimed space: 9.8GB
Significado: Imágenes sin usar eliminadas, ~10 GB recuperados dentro del almacenamiento de Docker.
Decisión: Si tus builds son lentos, prunear no ayudará. Si tu disco está lleno, prunear ayuda. Problemas distintos, palancas distintas.
Task 13: Verificar riesgo de rendimiento de bind mounts (¿estás montando rutas de Windows?)
cr0x@server:~$ docker run --rm -v /mnt/c/Users/cr0x/src:/src alpine ls -la /src | head
total 64
drwxrwxrwx 1 root root 4096 Feb 2 10:22 .
drwxr-xr-x 1 root root 4096 Feb 2 10:22 ..
-rwxrwxrwx 1 root root 1962 Feb 1 19:04 README.md
-rwxrwxrwx 1 root root 372 Feb 1 19:04 docker-compose.yml
Significado: Estás haciendo un bind-mount de una ruta de Windows. Funciona, pero es una trampa de rendimiento para cargas con I/O intensivo.
Decisión: Si tu stack hace muchas lecturas de archivos (Node, PHP, webpack, Python), mueve el repositorio al sistema de archivos Linux y monta desde /home en su lugar.
Task 14: Confirmar accesibilidad de puertos desde Windows a contenedores WSL
cr0x@server:~$ docker run --rm -d -p 8080:80 nginx:alpine
c7c51d1c65b98a0c2a5c2b9d9a3a9b10f1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
cr0x@server:~$ powershell.exe -NoProfile -Command "Test-NetConnection -ComputerName 127.0.0.1 -Port 8080 | Select-Object TcpTestSucceeded"
TcpTestSucceeded
----------------
True
Significado: El publish de puertos funciona y Windows puede alcanzarlo en localhost.
Decisión: Si esto falla bajo VPN, normalmente el problema es resolución de nombres, reglas de firewall o comportamiento NAT de WSL, no “nginx está roto”.
Task 15: Diagnosticar DNS dentro de WSL (el asesino silencioso de productividad)
cr0x@server:~$ cat /etc/resolv.conf
nameserver 172.22.48.1
search corp.example
cr0x@server:~$ getent hosts registry-1.docker.io | head -n 1
2600:1f18:2148:bc02:7fd3:1c63:6f57:fc3a registry-1.docker.io
Significado: WSL está usando un resolver provisto por la NAT; las búsquedas DNS funcionan.
Decisión: Si las búsquedas cuelgan o devuelven resultados erróneos bajo VPN, puede que necesites deshabilitar resolv.conf autogenerado y configurar DNS explícitamente (con cuidado—ver errores comunes).
Task 16: Exportar una distro antes de cambios riesgosos (tu botón de deshacer)
cr0x@server:~$ wsl --export Ubuntu-22.04 D:\wsl-backups\Ubuntu-22.04.tar
The operation completed successfully.
Significado: Ahora tienes una copia de seguridad offline que puedes importar en otro lugar.
Decisión: Haz esto antes de mover discos, reinstalar o “limpiar WSL”. Si no lo haces, estás apostando tu trabajo a la suerte.
Task 17: Mover una distro a otro disco (la forma correcta)
cr0x@server:~$ wsl --unregister Ubuntu-22.04
The operation completed successfully.
cr0x@server:~$ wsl --import Ubuntu-22.04 D:\wsl\Ubuntu-22.04 D:\wsl-backups\Ubuntu-22.04.tar --version 2
The operation completed successfully.
Significado: La distro ahora está almacenada bajo D:\wsl\Ubuntu-22.04 (incluido su nuevo VHDX). Así es como se reubica el almacenamiento WSL sin corrupción.
Decisión: Haz esto si C: está limitado o si políticas corporativas de cifrado hacen que I/O de WSL en el disco del sistema sea miserable.
Task 18: Verificar que Docker sigue apuntando a donde crees después de mover
cr0x@server:~$ wsl -d Ubuntu-22.04 -- bash -lc "docker ps"
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c7c51d1c65b9 nginx:alpine "/docker-entrypoint.…" 2 min ago Up 2 min 0.0.0.0:8080->80/tcp nostalgic_borg
Significado: El cliente Docker aún puede hablar con un daemon y el estado de tus contenedores existe.
Decisión: Si contenedores/imágenes “desaparecen”, cambiaste de daemon o de contexto. Diagnostica primero la deriva del modelo de propiedad, no “Docker se comió mi trabajo”.
Guion de diagnóstico rápido
Este es el orden que encuentra el cuello de botella rápido, sin perseguir folklore.
1) Identifica el modelo de propiedad en 30 segundos
- Comprobar:
wsl -l -vpara distrosdocker-desktop;docker infopara root dir y driver. - Por qué: Si no estás seguro con qué daemon hablas, toda otra observación es sospechosa.
- Decisión: Comprométete con Modelo A o Modelo B para esta máquina y equipo. “Ambos” es un impuesto de depuración.
2) Mide el límite del sistema de archivos (Linux vs /mnt/c)
- Comprobar: Dónde vive el repo (
pwd), hacia dónde apuntan los bind mounts, y hacer una prueba fio rápida en ambos lugares. - Por qué: La mayoría de los reportes “Docker en WSL es lento” son en realidad “hago builds en una ruta montada desde Windows”.
- Decisión: Si /mnt/c es el foco del problema, mueve el código al sistema de archivos Linux y ajusta el flujo de trabajo del editor.
3) Confirma límites de recursos (RAM/swap) y señales de presión
- Comprobar: Uso de memoria WSL, comportamiento de swap, y si Windows está haciendo mucho paging.
- Por qué: Bajo presión de memoria, todo parece lentitud de I/O.
- Decisión: Establece límites en
.wslconfig; aumenta memoria para cargas de builds intensivas; mantén el swap razonable.
4) Valida DNS y comportamiento de proxy (especialmente con VPN)
- Comprobar:
getent hosts, pulls desde registries, y si/etc/resolv.confse genera automáticamente. - Por qué: Los pasos de build suelen obtener dependencias; DNS roto parece “Docker build se cuelga”.
- Decisión: Arregla la generación de DNS o establece DNS estático con una política controlada.
5) Solo entonces: rendimiento específico de Docker (buildkit, cache, overlay2)
- Comprobar: Logs de build, misses de cache, patrones de invalidación de capas, y si los bind mounts están provocando tormentas de rebuild.
- Por qué: Afinar Docker es inútil si el sistema de archivos subyacente es incorrecto.
- Decisión: Optimiza el orden del Dockerfile, usa BuildKit y reduce la volatilidad de los bind mounts.
Errores comunes: síntoma → causa raíz → solución
1) “Docker está dolorosamente lento”
Síntoma: npm install, composer install, pip install o builds con webpack tardan 5–20× más de lo esperado.
Causa raíz: El repo vive bajo /mnt/c y lo estás bind-mountando en contenedores; las operaciones de metadatos son caras a través del límite Windows↔Linux.
Solución: Mueve el repo al sistema de archivos Linux (/home/.../src). Si necesitas acceso desde un editor en Windows, usa VS Code Remote / WSL o accede vía \\wsl$\\ desde Windows.
2) “Mis imágenes/contenedores desaparecieron después de un reinicio”
Síntoma: Las imágenes de ayer no están; docker ps está vacío; los volúmenes no aparecen.
Causa raíz: Estás hablando con un daemon/contexto diferente (Desktop vs in-distro), o Docker Desktop reinició su distro de datos.
Solución: Ejecuta docker context ls, luego docker info para confirmar RootDir. Decide Modelo A o B y elimina el otro daemon para evitar deriva.
3) “Docker build se queda en ‘Downloading…’”
Síntoma: Los builds se atascan en la descarga de imágenes base o dependencias; reintentar a veces funciona.
Causa raíz: Problemas de resolución DNS bajo VPN, o variables de proxy no aplicadas dentro de WSL/Docker.
Solución: Prueba resolución de nombres con getent hosts. Si es necesario, desactiva resolv.conf autogenerado y configura resolvers conocidos; alinea variables de proxy para WSL y Docker.
4) “Los puertos publicados dejan de funcionar aleatoriamente”
Síntoma: -p 8080:80 funcionó antes; ahora Windows no puede alcanzarlo en localhost.
Causa raíz: NAT de WSL y cambios de firewall después de suspensión/Toggles de VPN; a veces el switch virtual de WSL queda en mal estado.
Solución: Reinicia WSL (wsl --shutdown). Si usas Docker Desktop, reinícialo también. Vuelve a probar con Test-NetConnection.
5) “El disco está lleno pero borré un montón de cosas”
Síntoma: El espacio en el drive de Windows no aumenta tras borrar imágenes Docker o archivos Linux.
Causa raíz: El VHDX no se encoge automáticamente; el espacio queda asignado dentro del disco virtual.
Solución: Limpia dentro de Linux y luego compacta el VHDX usando herramientas soportadas. Si no puedes compactar fácilmente, export/import a un nuevo VHDX como reinicio práctico.
6) “El file watching no funciona (hot reload roto)”
Síntoma: La app no se recarga en cambios de archivos; los watchers pierden eventos o disparan CPU alta.
Causa raíz: Vigilar un sistema de archivos montado desde Windows desde contenedores Linux puede degradar la semántica inotify; o demasiados archivos saturan los watchers.
Solución: Mantén el código en el sistema de archivos Linux; para monorepos grandes, configura polling con intervalos razonables como plan B, pero trátalo como último recurso.
7) “Git muestra renombres raros solo por mayúsculas o duplicados”
Síntoma: CI pasa en Linux pero localmente se comporta raro; archivos difieren solo por mayúsculas.
Causa raíz: Desajuste de sensibilidad a mayúsculas cuando trabajas en el sistema de archivos de Windows.
Solución: Trabaja en el sistema de archivos Linux para repos que asumen semántica Linux; aplica nombres consistentes por mayúsculas en el repo.
Tres micro-historias corporativas desde el campo
Incidente: la suposición equivocada (“WSL es básicamente solo una carpeta”)
Un equipo de producto desplegó WSL2 para estandarizar entornos de desarrollo. El mandato era razonable: Docker, herramientas Linux, builds consistentes. La implementación no lo fue. Alguien asumió que las distros WSL eran solo directorios que se podían mover como cualquier caché.
Así que un ingeniero “ahorró espacio” copiando el directorio LocalState de la distro WSL a D: y borrando el original en C:. Funcionó un día, mayormente. Luego Docker Desktop se actualizó, el estado registrado por WSL ya no coincidía con el contenido del disco, y la distro se negó a arrancar. El síntoma inmediato fue “Docker no arranca”, pero la falla real fue “el disco de la VM ya no está donde WSL cree que está”.
La recuperación fue fea. Tuvieron que unregister e importar desde la copia que quedaba. Algunas personas perdieron bases de datos locales guardadas en volúmenes porque nadie tenía una política de exportar el estado WSL antes de cirugía.
La lección no fue “no uses WSL”. Fue: trata las distros WSL como activos de VM gestionados. Si las quieres en otro disco, usa export/import. Si quieres reducir espacio, prunea y compacta; no juegues a la ruleta con el sistema de archivos.
Optimización que salió mal: “Pongamos todo en /mnt/c para que las herramientas Windows lo vean”
Otra organización quería una experiencia suave para desarrolladores orientados a Windows. Su idea: mantener repos en C:\ para que las herramientas de seguridad y los IDEs de Windows “vean todo”, luego ejecutar builds en WSL2 y contenedores montando esas mismas rutas de Windows.
En proyectos pequeños parecía bien. En el monorepo principal fue un incidente en cámara lenta. Los builds incrementales dejaron de ser incrementales. Los pasos de escaneo de archivos (linters, descubrimiento de tests, compilación TypeScript) se volvieron el nuevo cuello de botella. La gente compensó desactivando checks localmente—porque los deadlines no miran tu diagrama de arquitectura.
Luego vino el verdadero contragolpe: los builds Docker empezaron a tardar en scripts tipo CI locales. No porque la CPU fuera débil, sino porque el tar del contexto de build y las operaciones overlay pasaban su tiempo en la capa de traducción Windows↔Linux. Los desarrolladores lo llamaron “overhead de Docker”. No lo era. Era la colocación del almacenamiento.
Eventualmente cambiaron a ubicaciones nativas Linux para los repos y usaron integraciones de editor para mantener la UX en Windows. La mejora fue inmediata y aburrida, que es el tipo de éxito que quieres en operaciones.
Práctica aburrida pero correcta que salvó el día: “Exportar antes de cambios”
Un equipo de plataforma mantenía una imagen WSL2 estándar para desarrolladores que trabajaban en múltiples servicios contenedorizados. Tenían una regla: cualquier cambio que pudiera tocar el almacenamiento de la distro WSL requiere un export primero. Sin excepciones, sin “todo estará bien”, sin heroicidades.
Un trimestre, una actualización de Windows más una actualización de un agente de seguridad causaron paradas de I/O en C:. Los desarrolladores reportaron builds Docker eternos, más timeouts ocasionales de WSL. La solución fue reubicar las distros a otro disco donde la política del agente era menos agresiva. Es la clase de oración que hace suspirar, pero pasa.
Como tenían un export reciente, el movimiento fue procedimental: shutdown WSL, exportar, unregister, importar a la nueva ubicación, verificar. No tuvieron que depurar VHDX corruptos a las 2 a.m. Tampoco tuvieron que pedir a cientos de ingenieros que reconstruyeran entornos desde cero.
No fue glamoroso. Fue disciplinado. Y convirtió una migración potencialmente caótica en una tarea de mantenimiento controlada.
Listas de verificación / plan paso a paso
Paso 0: Decide tu modelo de Docker (no improvises después)
- Elige Modelo A si quieres la experiencia de escritorio más sencilla, gestión por GUI y no necesitas control nativo del daemon Linux.
- Elige Modelo B si quieres comportamiento tipo servidor Linux, control explícito de
/var/lib/dockery menos sorpresas de Docker Desktop.
Paso 1: Instala WSL2 limpiamente y verifica
- Instala WSL y una distro.
- Ejecuta
wsl -l -vy confirma VERSION=2. - Ejecuta
wsl --statusy confirma que tienes una versión moderna de WSL.
Paso 2: Configura recursos de WSL (los guardarraíles aburridos)
Crea o edita %UserProfile%\.wslconfig en Windows. Política de ejemplo (ajusta a tu máquina):
- Memory: límite razonable (por ejemplo, 8–16 GB en portátiles de desarrollo).
- Swap: no lo pongas en 0 a menos que te gusten los OOM durante builds.
- Processors: limita si quieres que los ventiladores dejen de pedir salario por riesgo.
Luego wsl --shutdown para aplicar.
Paso 3: Pon el código en el lugar correcto
- Crea
~/srcdentro de WSL. - Clona repos allí.
- Ejecuta builds Docker desde allí.
Paso 4: Configuración de Docker por modelo
Modelo A: Docker Desktop + integración WSL2
- Habilita backend WSL2 en la configuración de Docker Desktop.
- Habilita la integración para tu distro elegida.
- Confirma que
docker psfunciona dentro de la distro. - No instales ni ejecutes un
dockerdseparado dentro de WSL a menos que quieras intencionalmente dos daemons.
Modelo B: Docker Engine dentro de WSL2
- Habilita systemd en
/etc/wsl.conf. - Reinicia WSL.
- Instala los paquetes de Docker Engine dentro de la distro.
- Inicia y habilita docker vía systemd; confirma que
docker infomuestra overlay2 y un root dir sensato.
Paso 5: Haz el desastre recovery aburrido
- Antes de cambios mayores, exporta la distro:
wsl --export. - Para reubicación de disco: exportar → unregister → importar.
- Mantén una política sobre qué puede vivir en volúmenes Docker localmente (bases de datos, caches) y cómo respaldarlo si importa.
Broma #2: Si tu único plan de respaldo es “me acordaré de lo que hice”, felicidades—has inventado el punto único de fallo memoria.
Preguntas frecuentes
1) ¿Debo usar Docker Desktop o Docker Engine dentro de WSL?
Si quieres la menor fricción en Windows, usa Docker Desktop (Modelo A). Si quieres control nativo Linux y comportamiento predecible del daemon, ejecuta Docker Engine dentro de WSL (Modelo B). Elige uno por máquina.
2) ¿Por qué construir desde /mnt/c es tan más lento?
Porque estás cruzando un límite de sistema de archivos con traducción de metadatos. Los builds hacen muchas operaciones de archivos pequeños. Las operaciones pequeñas son donde se notan los costes del límite.
3) ¿Dónde se almacenan realmente mis imágenes Docker?
Ejecuta docker info y mira DockerRootDir. En Docker Desktop, el almacenamiento de respaldo está en su entorno gestionado; en Docker in-distro, suele ser /var/lib/docker dentro del VHDX de esa distro.
4) ¿Puedo mover WSL a otro disco de forma segura?
Sí: exporta la distro a un tar, unregister y luego importala a un directorio en el disco destino. No copies manualmente LocalState VHDX esperando que funcione.
5) ¿Por qué Windows no recupera espacio después de borrar archivos en WSL?
Porque el archivo VHDX no se encoge automáticamente. Liberaste espacio dentro de ext4, pero Windows sigue viendo la asignación del VHDX. Usa workflows de compactación o export/import para recrear un VHDX más pequeño.
6) ¿Cómo sé si “Docker está lento” es en realidad DNS?
Si pulls/pasos de build se cuelgan en fetch de red, prueba con getent hosts y un pull simple de imagen. Si la resolución de nombres es lenta o incorrecta, arregla DNS antes de tocar Dockerfiles.
7) ¿Es seguro ejecutar dos daemons Docker (Desktop + in-distro)?
Se puede hacer, pero suele ser una auto-impuesta interrupción. Confundirás contextos, puertos y ubicaciones de imágenes. Si debes hacerlo, documenta contextos y píndalos por proyecto.
8) ¿Por qué a veces los puertos funcionan solo desde Windows o solo desde WSL?
Porque las reglas NAT y de reenvío difieren por dirección. Además, cambios de VPN/firewall pueden romper el pegamento implícito. Reinicia WSL y Docker Desktop, y vuelve a probar con un contenedor conocido y Test-NetConnection.
9) ¿Cuál es la forma más segura de manejar bases de datos en volúmenes Docker locales?
Asume que los volúmenes son desechables a menos que los respaldes. Para algo importante, automatiza exports (por ejemplo, pg_dump) a una ubicación conocida dentro del sistema de archivos Linux y/o una ruta de respaldo en Windows.
10) ¿Importa habilitar systemd en WSL para Docker?
Para el Modelo B, sí: systemd hace que Docker se comporte como en un Linux real, incluyendo ciclo de vida de servicios y alineación del driver de cgroups. Para el Modelo A es opcional.
Próximos pasos (haz esto, no vibes)
- Decide tu modelo de Docker y elimina ambigüedad: integración Desktop o daemon in-distro.
- Mueve repos activos al sistema de archivos Linux y deja de bind-mountear rutas Windows para builds pesados.
- Añade límites de recursos WSL para que Windows siga siendo usable bajo carga.
- Exporta tu distro antes de cambios como movimientos de disco, reinstalaciones o “limpieza”.
- Usa el guion de diagnóstico rápido la próxima vez que el rendimiento caiga: propiedad → límite de sistema de archivos → recursos → DNS → afinado de Docker.
Cuando WSL2 y Docker están configurados correctamente, no se sienten como una “pila”. Se siente como que tu máquina finalmente coopera. Ese es el objetivo: aburrido, rápido y recuperable.