Laboratorios: contenedores a partir de un archivo compose
Algunas lecciones necesitan más de un archivo: una base de datos que consultar, una API delante de ella, una caché al lado. Un laboratorio es ese conjunto de servicios, descrito en un archivo compose escrito en la página del laboratorio o guardado en tu propio repositorio de GitHub.
Configura uno, comprueba lo que le dará a cada alumno, publícalo y prueba tu propia copia; después asígnalo como cualquier tarea. Cada alumno inicia su propia copia desde la página del laboratorio; la copia se conserva de una sesión a otra y, al final, el alumno la entrega para que la califiques.
Para probar uno tú mismo antes, sin módulo, abre «Crear» en la barra y elige «Ejecutar un contenedor». También está disponible para los visitantes: sin cuenta, cualquiera puede iniciar el laboratorio de Git o el de SQL, y todos los demás ejemplos necesitan una cuenta gratuita. Una tarjeta «Laboratorios de ejemplo» ofrece seis, una base de datos con una API web, MySQL con los datos de una tienda y phpMyAdmin delante, Git con Gitea y los laboratorios de seguridad Juice Shop, DVWA y WebGoat, cada uno con su propia página en este manual y con un «Iniciar» que lo arranca con un clic, o «Editar el archivo primero» para cambiarlo antes de iniciarlo. En esa página «Iniciar» ejecuta lo que hay en pantalla y conserva los volúmenes, abrirla no escribe nada, el archivo se guarda un segundo después de que dejes de escribir en una cuenta y solo se comprueba para un visitante, y «Deshacer» retira un ejemplo que hayas cargado.
Un laboratorio también puede ser una máquina virtual Ubuntu: elige «Máquina virtual Ubuntu» como tipo de laboratorio y cada alumno tendrá su propia máquina, preparada con un script que escribes tú. Consulta «Configurar un laboratorio de máquina virtual» más abajo.
Configurarlo
En Laboratorio, añade una tarea con la tarjeta «Laboratorio de contenedores». Un laboratorio nuevo empieza en «Escrito aquí», con un ejemplo ya incluido: una base de datos y una API web delante de ella, a las que se accede desde el terminal con psql y curl. Publícalo tal cual para ver un laboratorio en marcha, o modifícalo antes. El archivo se guarda un segundo después de que dejes de escribir y se comprueba al guardarse. Un archivo escrito aquí solo puede usar imágenes, ya que no hay ningún repositorio a partir del cual compilar una imagen ni del que leer un env_file.
Para algo más grande, elige «En un repositorio de GitHub», que guarda el historial del laboratorio y funciona igual con docker compose en tu propio ordenador. «Usar el ejemplo» apunta el laboratorio a mitsurutech/lab-sample, cuyo README es una lección para acompañarlo; haz un fork para adaptarlo. Otro, mitsurutech/lab-mysql-phpmyadmin, es MySQL con una base de datos de práctica y phpMyAdmin, con ejercicios de SQL en su README; indica su dirección para usarlo. Un tercero, mitsurutech/lab-git-gitea, es un servidor Git, Gitea, con un repositorio que clonar, en el que hacer commit y push desde el terminal, que tiene git. Si no, indica la dirección del repositorio, la rama y dónde está el archivo compose a partir de la raíz del repositorio. Para un repositorio privado, marca «Repositorio privado» y pega un fine-grained personal access token con acceso de solo lectura a ese único repositorio. Se almacena cifrado y no se vuelve a mostrar nunca.
El formulario se guarda solo. Cada vez que se guarda, lee el archivo en el commit más reciente de la rama y muestra lo que recibiría cada alumno: cada servicio, la imagen de la que procede, su memoria, sus puertos y qué volúmenes se conservan.

Lo que puede pedir un archivo compose
Un laboratorio se ejecuta en máquinas que comparte toda la clase, así que un archivo solo puede pedir lo que es seguro dar a treinta alumnos a la vez. Las imágenes proceden de Docker Hub o del registro de GitHub (ghcr.io), o se compilan a partir de una carpeta de un repositorio público: al publicar, primero se compilan en GitHub, y la imagen resultante es pública, así que guarda las contraseñas en un env_file y no en el Dockerfile. Un laboratorio puede tener hasta 6 servicios y 2048 MB de memoria para la copia de un alumno; un servicio sin límite propio cuenta como 512 MB.
Se rechaza todo lo que daría acceso a la propia máquina: contenedores privilegiados, carpetas de la máquina montadas en el contenedor, el socket de Docker, la red del host, puertos publicados en la máquina y valores tomados de su entorno con ${...}. Un archivo que pida algo de esto se rechaza línea por línea, con todos los problemas a la vez y cada uno con su línea, para que puedas corregirlos en un solo push. Un signo de dólar que el contenedor deba ver se escribe $$, como en docker compose, así que un comando puede seguir usando $$HOME o "$$@".
Probar tu propia copia
Una vez publicado un commit, pulsa «Iniciar» en la página del laboratorio. Tus servicios se inician en el orden que indica el depends_on del archivo, cada uno accesible desde los demás por su nombre de servicio, con un terminal al lado: «Abrir el terminal» cuando esté en marcha. «Detener y guardar» conserva todos los volúmenes con nombre y la carpeta personal del terminal, y «Volver a iniciar» los recupera.
El terminal tiene docker para los propios servicios del laboratorio, por sus nombres en el archivo: docker ps para verlos y saber si están en buen estado, docker logs api para leer lo que ha escrito uno de ellos, docker exec -it db sh para abrir un shell dentro de uno, docker restart, stop y start, docker inspect, top, stats y cp. No se puede crear, descargar, compilar ni eliminar nada, y solo se puede llegar a los servicios de esta copia. En una imagen sin shell no se puede entrar, igual que en un servidor real.
Un servicio se puede abrir en el navegador añadiéndole una etiqueta en el archivo, lab.open: "8080", para un puerto que declare en ports o expose. Mientras la copia está en marcha, su tarjeta muestra un enlace a cada puerto abierto, en una dirección propia. Solo pueden abrirlo el alumno al que pertenece la copia y el personal del módulo. Para llamar a una API desde Postman, curl o un programa, envía el token de la copia, que aparece en la tarjeta, en la cabecera X-Lab-Token; «Nuevo token» lo sustituye si se ha filtrado. Los puertos solo transportan tráfico web: un cliente de base de datos instalado en tu ordenador no puede conectarse, así que usa el terminal del laboratorio para eso. Si abres un puerto que suele ser de una base de datos o de otro servicio que no es web (5432, 3306, 6379, 27017, etc.), la página lo indica y dice dónde conectarse en su lugar: es un aviso y nunca un rechazo.
En conjunto pueden ocupar 200 MB. La página te avisa cuando una copia se acerca a ese límite, y una copia que lo supera al detenerse conserva en su lugar lo guardado la vez anterior.
Asignarlo
Marca el laboratorio en la pestaña «Tareas» del módulo y pulsa «Asignar a», como con cualquier tarea: los alumnos reciben el aviso y el correo habituales. Su enlace abre la propia página del laboratorio, con tus instrucciones, un botón «Iniciar» para su propia copia y el archivo compose que ejecuta.
Los alumnos se quedan con el commit con el que empezaron. Cuando publicas una corrección, la página del laboratorio indica cuántas copias están atrasadas, y «Actualizar a todos» las pasa a esa versión la próxima vez que cada uno inicie la suya, conservando lo que hayan guardado.
Una lección trabajada en un laboratorio
Una lección puede apoyarse en un laboratorio, de contenedores o de máquina virtual Ubuntu, para que la clase lea y escriba en el mismo sitio. En el editor de la lección, elija el laboratorio en «Laboratorio», arriba; solo se ofrecen los laboratorios del propio módulo. Varias lecciones pueden compartir uno, por ejemplo Git parte 1 y Git parte 2, y cada persona tiene entonces una sola copia y un solo terminal para todas.
Añada un bloque Comando para cada paso: un comando de shell de hasta 20 líneas. En la lección, cada lector ve arriba la barra del laboratorio: Iniciar y Detener, un enlace a cada puerto abierto y «Abrir el terminal», que abre el terminal completo en una pestaña nueva. «Ejecutar» en un bloque Comando escribe ese comando en su propio terminal, así que lo que se ejecutó desde la lección queda en su historial, y lo que mostró aparece debajo del bloque. Un comando que sigue en marcha tras unos segundos, esperando una contraseña por ejemplo, continúa en el terminal. Solo se puede pulsar con el laboratorio en marcha, y nunca lo inicia por sí mismo. El terminal de un laboratorio de máquina virtual es la máquina Ubuntu, así que «Ejecutar» escribe en la máquina cuando ya ha arrancado y su script de preparación ha terminado; antes dice que la máquina aún está arrancando y no escribe nada.
El personal también tiene su propia copia, así que un comando ejecutado en el proyector se ejecuta en la suya. Un alumno cuyo trabajo de laboratorio está entregado o calificado tampoco puede iniciarlo desde la lección. Un bloque Comando en una lección sin laboratorio aparece en la lista de lo que no está listo, en el editor.
Observar y tomar el control
La página del laboratorio muestra la lista de la clase: quién ha iniciado una copia, quién tiene el terminal abierto en este momento y dos botones por alumno. «Observar» abre su terminal en modo de solo lectura, así que ves lo que escribe a medida que lo escribe. «Tomar el control» te permite escribir en él: la página del alumno dice «Tu profesor está escribiendo», su registro de accesos lo anota, y con «Devolver el control» terminas. La primera vez que abres cualquiera de los dos, se te envía un código por correo, como para cualquier terminal.
Para un alumno que no está, «Abrir copia guardada» inicia lo último que guardó, en una sesión tuya con su propio terminal. Nada de lo que cambies ahí se guarda en su copia. Se rechaza mientras la copia de ese alumno se está ejecutando: obsérvala en su lugar.
Entrega y calificación
El alumno detiene su laboratorio y pulsa «Entregar». Lo que su copia ha guardado se conserva tal como estaba en ese momento, y la copia se cierra: no puede volver a iniciarla hasta que se la devuelvas. Un laboratorio que sigue en marcha no se puede entregar, así que lo que calificas es exactamente lo que se guardó.
La lista de la clase de la página del laboratorio muestra quién ha entregado y a quién se ha calificado, con «Calificar» junto a cada alumno. Abre el laboratorio tal como lo tiene ese alumno: cuándo lo entregó, qué cambió en una máquina virtual, la conversación con él, y la nota y los comentarios. «Abrir copia guardada», desde la lista de la clase, inicia lo que entregó, sin cambios, en una sesión tuya.
Calificar avisa al alumno y mantiene el laboratorio cerrado. «Devolver» lo vuelve a abrir, con un motivo si lo indicas, que el alumno lee en el aviso y en la conversación. Lo que entregó antes se mantiene hasta que vuelva a entregar.
Publicar
«Publicar» fija el commit que acabas de comprobar. Las copias de los alumnos se inician a partir de ese commit, y hacer push a la rama no les cambia nada hasta que vuelvas a publicar.
Solo se conservan, para cada alumno y de una sesión a otra, los volúmenes con nombre, junto con la carpeta personal de su terminal. Cualquier otra cosa que cambie dentro de un contenedor desaparece cuando se detiene el laboratorio, como ocurre con los contenedores en producción. Una imagen nueva no cambia los datos que ya contiene un volumen: los datos iniciales y los scripts de arranque solo se ejecutan en un volumen vacío.
Cada servicio se ejecuta con el usuario propio de su imagen, igual que lo ejecuta docker compose en tu ordenador, salvo que el archivo indique otro usuario. Una copia cuyos contenedores escriban más de 2 GB fuera de los volúmenes se detiene, con sus volúmenes guardados, para que un registro desbocado no pueda llenar el disco que comparte la clase.
Configurar un laboratorio de máquina virtual
En Laboratorio, añade una tarea con la tarjeta «Laboratorio de VM Ubuntu». La página contiene una breve descripción de la máquina en lugar de un archivo compose: cpus, memory en MB, disk en GB, open para los puertos que se abren en el navegador, y setup, un script que se ejecuta como root la primera vez que se inicia la máquina virtual de cada alumno. Parte de un ejemplo que instala un servidor web, así que al publicar y pulsar «Iniciar» ves uno funcionando enseguida.
La máquina virtual de cada alumno se conserva de una sesión a otra, con todo lo que hay en su disco, y puedes observar el terminal de un alumno o tomar el control como en cualquier laboratorio. El script setup se ejecuta una vez por alumno, y su salida está en /var/log/mitsurutech-setup.log en su máquina virtual. La máquina virtual llega a los paquetes de Ubuntu, a PyPI, a npm y a GitHub, y a nada más.
Para calificar una VM entregada sin leerla tú, añade check, un script con la misma forma que setup. Ejecutar la comprobación en la fila de un alumno de la lista de la clase inicia una copia de su máquina guardada, sin guardar nada de vuelta, ejecuta tu script como root y muestra si se superó (sale con 0), qué imprimió y cuándo. Al alumno no se le comunica el resultado, y nada de lo que haga el script cambia su máquina.
Un alumno de un centro recibe el tamaño que escribas, hasta 4 CPU, 4096 MB de memoria y 20 GB de disco. Lo que omitas toma el valor por defecto del centro, 2 CPU, 2 GB y 10 GB. Quien no esté en un centro y abra el laboratorio queda limitado al tamaño de su propia categoría.
Cuando un alumno detiene su máquina virtual, la lista de la clase muestra lo que ha cambiado: los paquetes que ha instalado, los archivos que ha escrito fuera de las carpetas del sistema y el historial de /etc. Puedes consultarlo para calificar el trabajo sin iniciar su máquina virtual.
Laboratorios de redes en una sola VM
Un router necesita su propia máquina y un estudiante tiene una sola VM, así que los laboratorios de redes de ejemplo construyen toda la topología dentro de ella: cada router y cada equipo es un espacio de nombres de red, cada enlace un par de cables virtuales, y cada router ejecuta su propio FRRouting, con la consola vtysh que los estudiantes encontrarán en equipos reales. La página de un laboratorio VM ofrece tres para empezar: enrutamiento estático, OSPF y BGP entre dos sistemas autónomos. Usar uno reemplaza el texto, y Deshacer recupera el suyo.
Todo lo instala el propio script setup del laboratorio, desde el archivo de paquetes de Ubuntu, la primera vez que arranca la VM, en unos diez segundos. Con él se instala un comando netlab: netlab status lista las máquinas, netlab shell r1 abre la consola de un router y netlab shell h1 la de un equipo, y netlab reset empieza el laboratorio de nuevo. Los comandos reales también funcionan, y esa es la idea: sudo ip netns exec h1 ping 10.0.3.2, sudo ip netns exec r1 tcpdump -ni to-r2, sudo vtysh -N r1. Cada laboratorio deja en la carpeta personal del estudiante un README que dice qué hacer y no da ninguna respuesta.
Cada ejemplo tiene una comprobación. Se ejecuta sobre una copia de la máquina guardada tras un arranque limpio, así que solo ve lo que el estudiante guardó con write memory (salir de netlab shell también guarda), y solo se aprueba si el estado real se cumple: las rutas están en las tablas de enrutamiento, los vecinos OSPF están en Full o la sesión BGP en Established, h1 llega a h2 pasando por los routers y la red privada sigue sin ser alcanzable. Mover una dirección, una regla de cortafuegos o una ruta escrita con ip route y nunca guardada no la aprueba, y la primera línea de lo que imprimió dice por qué.
Para crear su propia topología, copie un ejemplo y cambie la topología en su setup: una línea por router, equipo y enlace, y daemons ospfd o daemons bgpd para arrancar ese protocolo en cada router. La herramienta, una topología y un README caben de sobra en los 16 KB de setup.
Preguntas frecuentes
- ¿Es mejor escribir un laboratorio aquí o guardarlo en GitHub?
- «Escrito aquí» es lo más rápido para probar algo, y basta para un laboratorio hecho de imágenes ya preparadas. Guárdalo en GitHub para compilar imágenes a partir de un Dockerfile, conservar su historial, probarlo en tu ordenador con docker compose y compartirlo con tus compañeros. Cambiar de una opción a otra conserva lo que configuraste en la otra.
- ¿Puedo usar una imagen que he creado yo?
- Sí. Súbela a ghcr.io como imagen pública e indica su nombre en el archivo, o deja que el archivo la compile a partir de una carpeta del repositorio.
- ¿Pueden los alumnos ver el archivo compose?
- Sí, en modo de solo lectura, en la página del laboratorio, junto a su propia copia. Así aprenden de qué está hecho. El token, en cambio, no se le muestra nunca a nadie.