10. Red, Kubernetes e interfaz gráfica
Secciones
Ajustes de lectura
Ninguna voz para este idioma en este navegador.
Más voces
Código y términos técnicos en inglés
Desactivado: la voz de la página lo lee todo, sin pausa entre dos voces.
Ninguna voz para este idioma en este navegador.
Más voces
Más voces: Microsoft Edge ofrece voces naturales en línea, y Windows (Configuración › Hora e idioma › Voz), macOS y Android instalan otras.
Docker Desktop es más que un motor. Tiene un panel, una casilla de Kubernetes, un mercado de extensiones y una configuración de red en la que la mayoría de los desarrolladores nunca tienen que pensar: publicas un puerto, abres localhost y listo. Esta última lección compara esas partes una a una con wslc 2.9.11, desde la más útil en el día a día, la red, hasta lo que simplemente no existe.
Las salidas vienen del diario, salvo la comprobación de las capacidades del contenedor de la CLI, que se volvió a ejecutar para esta lección.
Dónde escucha un puerto publicado
Sección titulada «Dónde escucha un puerto publicado»Por defecto, wslc publica solo en 127.0.0.1, como has visto en cada columna PORTS desde la lección 3:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES1796028d1f6a nginx "/docker-entrypoint.…" 3 seconds ago Up 2 seconds 127.0.0.1:8080->80/tcp webDocker Desktop, en cambio, publica en todas las direcciones, IPv4 e IPv6, salvo que indiques una. En Windows, el listener del contenedor de wslc pertenece a un proceso dllhost:
TCP 0.0.0.0:8080 LISTENING com.docker.backendTCP [::]:8080 LISTENING com.docker.backendTCP 127.0.0.1:8080 LISTENING dllhost ← wslcTCP [::1]:8080 LISTENING wslrelayEsa tabla viene de la prueba de conflicto de puertos de la lección 5, con Docker Desktop y wslc en el mismo puerto. Dos opciones de settings.yaml cambian este comportamiento (lección 6):
defaultBindingAddress,127.0.0.1por defecto, es la dirección que usa-pcuando no indicas ninguna;hostLoopbackse refiere a la otra dirección del tráfico: el nombrehost.wslc.internal, para un contenedor que necesita llegar a un servicio que se ejecuta en Windows. Por verificar: el nombre se leyó en el archivo de configuración, no se probó desde un contenedor.
Se acepta una dirección explícita en -p: wslc run -d -p 0.0.0.0:8082:80 nginx arrancó sin ningún error, y 127.0.0.1:8082 llegó a él. Por verificar: si ese puerto es entonces accesible desde otra máquina de la red, lo que también depende del firewall de Windows.
Es un valor por defecto seguro para una máquina de desarrollo: una base de datos o un broker de mensajes en un contenedor no tiene ninguna razón para ser accesible desde la red local.
Las redes de una sesión
Sección titulada «Las redes de una sesión»Cada sesión ejecuta su propio motor, así que cada una tiene sus propias redes. El mismo wslc network list, desde la sesión de administrador:
> wslc network listd9c6879f7df3 bridge bridge local0dd65e6d15ec host host local34ad73ecd806 none null localLas tres redes por defecto son las de Docker: bridge, a la que wslc run conecta un contenedor por defecto; host, la pila de red de la propia VM; y none, sin ninguna red. En la sesión sin elevación, las mismas tres redes tienen ID distintos. Una red creada con wslc network create en una sesión no existe en la otra.
wslc network --help lista create, remove, inspect, list, prune, connect y disconnect. La lección 8 mostró la propiedad más importante de una red creada: los nombres de los contenedores y los valores de --network-alias se resuelven como nombres DNS en ella, mientras que en la red bridge por defecto no.
Los contenedores de la API arrancan sin red
Sección titulada «Los contenedores de la API arrancan sin red»La CLI y la API no tienen el mismo valor por defecto. container.Inspect() muestra "NetworkMode":"none" cuando ContainerSettings.NetworkingMode no está definido. El mismo contenedor Alpine, creado dos veces desde C#, muestra ip -4 addr y luego intenta un wget hacia internet:
--- NetworkingMode=defaultNetworkMode in inspect: none inet 127.0.0.1/8 scope host lono internet--- NetworkingMode=BridgedNetworkMode in inspect: bridge inet 127.0.0.1/8 scope host lo inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0internet okSin la opción, el contenedor solo tiene la interfaz de loopback. Con Bridged, obtiene una dirección eth0 en la red bridge, 172.17.0.2, y llega a internet.
La descarga de la imagen funciona en los dos casos, porque es la sesión la que descarga las imágenes, no el contenedor. Así, un programa puede descargar una imagen, arrancar un contenedor y obtener su salida, y solo descubrir que falta la red cuando el servicio de dentro intenta llamar al exterior, o cuando un puerto publicado no responde.
new ContainerSettings("alpine:latest"){ NetworkingMode = ContainerNetworkingMode.Bridged, // ...}El diagrama resume los tres casos de esta lección.
flowchart LR subgraph session["VM de la sesión"] subgraph bridge["red bridge"] cli["contenedor de wslc run"] apiB["contenedor de la API, NetworkingMode Bridged"] end apiN["contenedor de la API, por defecto: NetworkMode none"] end internet["internet y registros"] win["Windows 127.0.0.1"] cli --> internet apiB --> internet win -->|"puerto publicado"| cli apiN --x|"ninguna interfaz salvo lo"| internetKubernetes: no, ni siquiera k3s
Sección titulada «Kubernetes: no, ni siquiera k3s»wslc no tiene ningún comando de Kubernetes, y la aplicación WSL Settings no tiene página de Kubernetes. Con Docker, un rodeo habitual es ejecutar una distribución pequeña como k3s dentro de un contenedor privilegiado. Necesita --privileged, porque Kubernetes tiene que gestionar los grupos de control y los montajes, justo lo que normalmente se le niega a un contenedor.
Desde la CLI
Sección titulada «Desde la CLI»wslc run --help no tiene opción --privileged ni --cap-add. Sin ellas, k3s se detiene de inmediato:
wslc run -d --name k3s-cli --tmpfs /run --tmpfs /var/run rancher/k3s:v1.36.4-k3s1 servertime="2026-09-14T02:17:38Z" level=fatal msg="Error: failed to evacuate root cgroup: mkdir /sys/fs/cgroup/init: read-only file system"El sistema de archivos de los grupos de control está montado en solo lectura en el contenedor, así que k3s no puede crear su propio grupo. Puedes ver los límites de un contenedor de la CLI con tres comandos, ejecutados de nuevo para esta lección:
wslc run --rm alpine sh -c 'grep cgroup /proc/mounts; grep CapEff /proc/self/status; ls /dev | wc -l'cgroup /sys/fs/cgroup cgroup2 ro,nosuid,nodev,noexec,relatime 0 0CapEff: 00000000a80425fb15- El
rode las opciones de montaje es el sistema de archivos de grupos de control en solo lectura que detuvo a k3s. CapEffes la máscara de bits de las capacidades efectivas del contenedor, los fragmentos del poder de root que Linux reparte uno a uno.a80425fbes el conjunto por defecto de Docker, sinCAP_SYS_ADMIN, la capacidad que necesitamount, entre otras cosas./devtiene 15 entradas: solo los dispositivos básicos, no los del host.
Desde la API: Privileged no tiene efecto
Sección titulada «Desde la API: Privileged no tiene efecto»La API tiene lo que le falta a la CLI: ContainerSettings.Privileged. Dos contenedores Alpine en la misma sesión, uno con cada valor, muestran los mismos tres datos:
--- Privileged=Falsecgroup /sys/fs/cgroup cgroup2 ro,nosuid,nodev,noexec,relatime 0 0CapEff: 00000000a80425fb15--- Privileged=Truecgroup /sys/fs/cgroup cgroup2 ro,nosuid,nodev,noexec,relatime 0 0CapEff: 00000000a80425fb15No cambia nada: mismas capacidades, mismos grupos de control en solo lectura, las mismas 15 entradas en /dev. Y k3s falla con el mismo error. El sospechoso evidente es la sesión: quizá los privilegios requieren una sesión elevada. La misma prueba como administrador, en una sesión limitada a 1 CPU y 1 GB, con una comprobación más, mount -t tmpfs none /mnt:
elevated: True--- Privileged=False HostConfig={"Memory":0,"NanoCpus":0,"NetworkMode":"none","Ulimits":[]}cgroup /sys/fs/cgroup cgroup2 ro,nosuid,nodev,noexec,relatime 0 0CapEff: 00000000a80425fbdev=15mount: permission denied (are you root?)mount denied--- Privileged=True HostConfig={"Memory":0,"NanoCpus":0,"NetworkMode":"none","Ulimits":[]}cgroup /sys/fs/cgroup cgroup2 ro,nosuid,nodev,noexec,relatime 0 0CapEff: 00000000a80425fbdev=15mount: permission denied (are you root?)mount deniedTampoco hay diferencia, y el HostConfig que devuelve Inspect() ni siquiera tiene un campo Privileged. Sin embargo, el flag existe en la cabecera C del SDK, como WSLC_CONTAINER_FLAG_PRIVILEGED = 0x00000004 en wslcsdk.h: declarado, pero no aplicado en la 2.9.11. No se volvió a intentar k3s.
Extensiones e interfaz gráfica: ninguna
Sección titulada «Extensiones e interfaz gráfica: ninguna»wslc --helplistacontainer,image,network,registry,settings,system,volumey los atajos al estilo Docker. No hay ningún mecanismo de extensiones ni de plugins.wslc settingssolo abresettings.yamlen el editor por defecto.- La aplicación WSL Settings, la única aplicación de WSL en el menú Inicio además del propio
WSL, no tiene página de contenedores. Sus páginas sonAbout,Developer,DistroManagement,DockerDesktopIntegration,FileSystem,General,GPUAcceleration,GUIApps,MemAndProc,Networking,NetworkingIntegration,OptionalFeatures,VSCodeIntegration,VSIntegrationyWorkingAcrossFileSystems.
Así que las vistas diarias del panel de Docker Desktop solo tienen equivalentes en la línea de comandos: wslc container list --all para los contenedores, wslc logs para su salida, wslc stats para los recursos, y wslc image list y wslc volume list para el almacenamiento.
Lo que ha encontrado el curso
Sección titulada «Lo que ha encontrado el curso»wslc 2.9.11 es un motor de ejecución, no una plataforma. Ejecuta, construye, publica y limita contenedores Linux sin ningún producto de terceros, y su API permite que una aplicación Windows tenga sus propios contenedores, con una imagen construida por dotnet build y cargada sin registro. Alrededor de ese núcleo, no hay Compose, ni Kubernetes, ni contenedores privilegiados, ni extensiones, ni interfaz gráfica. Para un único servicio, una herramienta o una aplicación que integra contenedores, es suficiente. Para un proyecto con Compose, un clúster local o un equipo que comparte una configuración de Docker, Docker Desktop o Podman siguen siendo la herramienta, y los dos pueden convivir en una misma máquina si mantienes sus puertos separados (lección 5).
Puntos clave
Sección titulada «Puntos clave»wslcpublica en127.0.0.1por defecto, segúndefaultBindingAddress; Docker Desktop publica en todas las direcciones.- Cada sesión tiene sus propias redes
bridge,hostynone, con ID distintos, y sus propias redes definidas por el usuario. - Los contenedores creados por la API tienen
NetworkMode: nonea menos queNetworkingModeseaBridged, aunque la descarga de la imagen funcione. - La CLI no tiene
--privilegedni--cap-add, y k3s se detiene ante un sistema de archivos de grupos de control en solo lectura. ContainerSettings.Privilegedestá declarado pero no tiene efecto en la 2.9.11, ni en una sesión normal ni en una elevada.- No hay extensiones ni página de contenedores en WSL Settings:
wslces un motor de ejecución, y la CLI es su única interfaz.
Ejercicios
Sección titulada «Ejercicios»- Un programa C# arranca un contenedor nginx con un mapeo de puertos, pero
curl.exe http://127.0.0.1:8080/no obtiene respuesta, mientras quewslc run -d -p 8080:80 nginxfunciona. ¿Qué compruebas primero?
Solución
El modo de red. Un contenedor de la API sin NetworkingMode tiene NetworkMode: none, solo la interfaz de loopback, así que un mapeo de puertos no tiene adónde reenviar el tráfico. Compruébalo con container.Inspect() o con wslc --session <name> container inspect <container>, y luego define NetworkingMode = ContainerNetworkingMode.Bridged. Por verificar: el comportamiento exacto de PortMappings en un contenedor sin red, que el diario no probó.
- Lee
CapEff: 00000000a80425fbcon la herramienta que prefieras, y di si el contenedor tieneCAP_NET_ADMIN, el bit 12, yCAP_SYS_ADMIN, el bit 21.
Solución
capsh --decode=00000000a80425fb, de las herramientas libcap de una distribución Linux, lista las capacidades por su nombre. A mano, en PowerShell:
$caps = 0xa80425fb(($caps -shr 12) -band 1), (($caps -shr 21) -band 1)Las dos líneas muestran 0. La máscara tiene activados los bits 0, 1, 3 a 8, 10, 13, 18, 27, 29 y 31. El bit 12 no está activado, así que no hay CAP_NET_ADMIN: el contenedor no puede cambiar su propia configuración de red. El bit 21 tampoco está activado, así que no hay CAP_SYS_ADMIN, lo que explica mount: permission denied como root.
- Quieres saber si una versión posterior de WSL aplica
Privileged. Escribe la comprobación más pequeña que te lo diría, sin instalar k3s.
Solución
Crea dos contenedores desde la API, uno con Privileged = false y otro con true, que ejecuten el mismo comando que en esta lección:
grep cgroup /proc/mounts; grep CapEff /proc/self/status; ls /dev | wc -lUn contenedor privilegiado debería mostrar un CapEff distinto, con todas las capacidades, más entradas en /dev, y un mount -t tmpfs none /mnt que funcione. Si las tres líneas son idénticas, el flag se sigue ignorando.
- Desde la terminal sin elevación, creaste una red
demoy ejecutaste un contenedor en ella. En una terminal de administrador,wslc network listno muestrademo, y el ID debridgees distinto. ¿Hay algo roto?
Solución
No. La terminal de administrador usa otra sesión, wslc-cli-admin-<user>, con su propia VM y su propio motor, así que sus redes por defecto tienen sus propios ID y no ve las redes de la otra sesión. Usa el mismo tipo de terminal para todo, o indica la sesión con --session.
- Elabora, a partir de las diez lecciones, la lista de lo que te haría elegir Docker Desktop en lugar de
wslcpara un proyecto nuevo, y la lista de lo que te haría elegirwslc.
Solución
Docker Desktop, o Podman: un compose.yaml que ejecutar, depends_on con condiciones de salud, un clúster de Kubernetes local, contenedores privilegiados, herramientas que necesitan la Docker Engine API, como Testcontainers, un equipo ya configurado con Docker, un panel gráfico.
wslc: nada que instalar aparte de WSL, servicios sencillos arrancados por un script, límites y discos por sesión fáciles de medir y de eliminar, y sobre todo una aplicación Windows que ejecuta sus propios contenedores Linux mediante Microsoft.WSL.Containers, con una imagen construida por dotnet build. Las dos listas valen para la 2.9.11, una versión preliminar: vuelve a comprobarlas en cada versión.
Fuentes
Sección titulada «Fuentes»- WSL container — Microsoft Learn
- Referencia de la API de WSL container
- Networking overview y Runtime privilege and Linux capabilities — documentación de Docker
- capabilities(7) — página del manual de Linux
- k3s y kind
- Notas de versión de WSL — GitHub