Saltar a contenido

3.5.-Virtualización, nube y contenedores

3.5. Virtualización, nube y contenedores

Idea principal

La virtualización permite preparar un entorno aislado para ejecutar una aplicación web. Una máquina virtual, una instancia cloud y un contenedor ofrecen niveles de aislamiento y responsabilidades diferentes; elegir uno no consiste en usar la tecnología más compleja, sino la que se pueda instalar, configurar y mantener con garantías.

Después de identificar los requisitos de la aplicación, hay que decidir dónde se ejecutarán sus componentes. En este tema se comparan las máquinas virtuales, los servicios de nube y los contenedores, y se prepara un entorno pequeño para la aplicación de ejemplo. La comparación se centra en la instalación y la configuración básica; la publicación de Nginx y Tomcat se aborda en los puntos posteriores.

Este contenido desarrolla exclusivamente el criterio siguiente de la normativa del módulo:

Código Descripción
RA1 Implanta arquitecturas web analizando y aplicando criterios de funcionalidad.
CE e Se ha realizado la instalación y configuración básica de tecnologías de virtualización de servidores en la nube y en contenedores.

Qué deberías saber al terminar

Al acabar este tema deberías poder:

  • distinguir una máquina virtual, una instancia cloud y un contenedor;
  • preparar una plataforma de contenedores con red, puertos y almacenamiento básicos;
  • justificar la opción elegida y registrar sus límites, costes y riesgos.

Mapa del tema

Seguiremos esta secuencia:

  1. virtualización y niveles de aislamiento;
  2. nube como infraestructura bajo demanda;
  3. imágenes y ciclo de vida de los contenedores;
  4. redes, persistencia y configuración declarativa;
  5. preparación de un entorno reproducible para una aplicación web.

1. Virtualizar un servidor

En un servidor físico se pueden ejecutar varios entornos aislados mediante un hipervisor. Un hipervisor es el programa que crea y administra máquinas virtuales: reparte entre ellas CPU, memoria, almacenamiento y dispositivos de red. Cada máquina virtual incluye su propio sistema operativo, por lo que el aislamiento es amplio, aunque también aumenta el consumo de recursos y el tiempo de arranque.

Hay dos formas habituales de encontrar un hipervisor:

  • Tipo 1 o nativo: se ejecuta directamente sobre el hardware. Es habitual en centros de datos y proveedores cloud.
  • Tipo 2 o alojado: se ejecuta como una aplicación sobre un sistema operativo, como ocurre en muchos laboratorios con VirtualBox o VMware Workstation.

La diferencia es útil para interpretar la responsabilidad de cada entorno: en una máquina virtual local administras el hipervisor y el sistema invitado; en una instancia cloud el proveedor suele administrar la capa física y el hipervisor, mientras tú administras lo que el servicio contratado te entrega.

Un contenedor utiliza el núcleo del sistema anfitrión, es decir, del sistema operativo de la máquina que lo ejecuta. Aísla procesos, sistema de archivos, red y límites de recursos. Arranca normalmente más rápido y ocupa menos que una máquina virtual, pero no es un sistema operativo completo y no debe tratarse como una frontera de seguridad absoluta.

Virtualización

Es la creación de una representación aislada de recursos informáticos para ejecutar sistemas o procesos independientes sobre una infraestructura física compartida.

Tecnología Qué aísla principalmente Ventaja Coste o límite
Máquina virtual Un sistema operativo completo Aislamiento amplio y flexibilidad Más consumo y administración
Contenedor Procesos y sus dependencias Arranque rápido y empaquetado reproducible Comparte el núcleo del anfitrión
Servidor físico La máquina completa Rendimiento y control directos Menor aprovechamiento y elasticidad

La elección también depende del riesgo. Un contenedor es apropiado para empaquetar una aplicación y sus dependencias, pero la organización debe aplicar actualizaciones, límites, separación de redes y un usuario no privilegiado. No es correcto afirmar que un contenedor sea una máquina virtual pequeña: comparte el núcleo del anfitrión y una vulnerabilidad del motor o una configuración privilegiada puede afectar al aislamiento.

flowchart TB
  P["Servidor físico o instancia cloud"] --> H["Hipervisor opcional"]
  H --> VM["Máquina virtual<br/>sistema operativo propio"]
  P --> OS["Sistema operativo anfitrión"]
  OS --> E["Motor de contenedores"]
  E --> C["Contenedor<br/>proceso aislado"]

El esquema representa dos recorridos posibles, no una obligación de utilizar todos los niveles. En un laboratorio puede existir una máquina virtual sobre el ordenador; en Docker Desktop el motor puede ejecutarse dentro de una máquina virtual gestionada por la herramienta sin que la administres directamente.

Cómo elegir

Utiliza una máquina virtual cuando necesites otro núcleo o sistema operativo, un aislamiento más amplio o una aplicación heredada difícil de adaptar. Utiliza contenedores cuando quieras empaquetar servicios reproducibles que compartan el núcleo del anfitrión y necesites arrancarlos y recrearlos con rapidez.

2. Nube e infraestructura bajo demanda

Una plataforma cloud o nube permite solicitar recursos de un proveedor sin comprar ni mantener físicamente todo el hardware. En un modelo IaaS (Infrastructure as a Service, infraestructura como servicio) se recibe una máquina virtual o instancia con CPU, memoria, disco y red configurables. El equipo sigue siendo responsable del sistema operativo, los servicios instalados, las cuentas, los datos y buena parte de la seguridad.

La nube es un modelo de provisión y administración de recursos, no una tecnología concreta. Puede apoyarse en máquinas virtuales, contenedores o servicios gestionados. Por eso conviene separar estas ideas:

Modelo Qué entrega el proveedor Qué suele administrar el equipo
IaaS Infraestructura virtual, red y almacenamiento Sistema operativo, runtime, servicios, datos y configuración
PaaS Plataforma preparada para ejecutar la aplicación Código, configuración, datos y permisos de la aplicación
CaaS Plataforma gestionada para ejecutar contenedores Imágenes, servicios, redes lógicas y datos, según el proveedor

Los límites exactos dependen del contrato. Un servicio gestionado reduce tareas de administración, pero no elimina la necesidad de proteger credenciales, revisar permisos, controlar datos y comprobar copias de seguridad.

Antes de crear una instancia hay que fijar al menos:

  • región o ubicación de los recursos;
  • imagen y arquitectura del sistema operativo;
  • tamaño de CPU, memoria y disco;
  • claves o mecanismo de acceso administrativo;
  • reglas de firewall y puertos publicados;
  • presupuesto, cuotas y política de apagado;
  • copias de seguridad y procedimiento de eliminación.

Una cuenta educativa también puede generar costes

Una instancia, una dirección IP pública, un disco o una transferencia pueden tener un coste aunque la aplicación sea pequeña. Utiliza cuentas de aula y límites definidos, no publiques credenciales y elimina los recursos cuando termine la actividad.

Antes de crear recursos en la nube, comprueba también:

  • la región y la arquitectura disponibles, especialmente si las imágenes solo soportan amd64 o arm64;
  • las cuotas de CPU, memoria, disco, IP y transferencia;
  • quién puede acceder a la instancia y con qué mecanismo de autenticación;
  • el procedimiento para apagar, eliminar y recuperar los datos;
  • qué controles de seguridad aplica el proveedor y cuáles debe aplicar el equipo.

Una instancia cloud puede alojar Docker y, dentro de él, los servicios de la aplicación. En ese caso hay dos niveles que documentar: la instancia y los contenedores. Un fallo o una regla de firewall del primer nivel puede impedir que funcionen los servicios del segundo.

3. Imágenes, contenedores y ciclo de vida

En Docker, una imagen es una plantilla formada por capas. Decimos que es inmutable porque no se modifica mientras un contenedor está funcionando; si necesitamos cambiarla, construimos una nueva versión. Un contenedor es una ejecución de esa imagen con su propia configuración. La imagen no debería guardar los datos de trabajo: los datos que deben sobrevivir a la recreación del contenedor se colocan en un volumen o en un servicio externo.

El Docker Engine sigue un modelo cliente-servidor. La orden docker es el cliente; el demonio dockerd recibe la petición a través de la API y gestiona imágenes, contenedores, redes y volúmenes. Un registro, como Docker Hub, sirve para distribuir imágenes, pero no ejecuta por sí mismo los contenedores.

Recurso Función Ejemplo en una aplicación web
Imagen Empaquetar sistema, runtime y aplicación nginx:1.27-alpine
Contenedor Ejecutar una imagen con límites y variables Servidor web en ejecución
Red Permitir la comunicación entre servicios Red interna entre Nginx y Tomcat
Puerto publicado Conectar el host con un puerto del contenedor 8080:80 para una prueba local
Volumen Conservar datos fuera del ciclo del contenedor Datos de MariaDB

Una etiqueta identifica una variante, por ejemplo nginx:1.27-alpine, pero no garantiza por sí sola que el contenido sea inmutable: una etiqueta puede actualizarse en el registro. Para una entrega reproducible conviene registrar la etiqueta probada y el digest (sha256:...) que devolvió el registro.

Componentes del motor Docker
El cliente Docker solicita operaciones al motor, que administra imágenes, contenedores, redes y volúmenes.

Un recorrido mínimo para comprobar la plataforma puede ser:

docker version
docker info --format '{{.Architecture}}'
docker pull nginx:1.27-alpine
docker run --name web-prueba --detach --publish 127.0.0.1:8080:80 nginx:1.27-alpine
docker ps
curl --fail http://127.0.0.1:8080
docker logs --tail 20 web-prueba
docker inspect web-prueba
docker stop web-prueba
docker rm web-prueba

--publish 127.0.0.1:8080:80 publica el puerto 80 del contenedor en el 8080 del host, pero solo para conexiones desde el propio equipo. Omitir la dirección (8080:80) suele hacer que Docker escuche en todas las interfaces del host. Ninguna de las dos formas convierte automáticamente un puerto interno en un servicio seguro para Internet: el firewall y la configuración del proveedor siguen siendo relevantes.

docker info permite comprobar la arquitectura del motor. Si el host es arm64 y la imagen solo ofrece amd64, Docker puede necesitar emulación y el resultado puede ser más lento o incompatible. Esta comprobación evita atribuir al código un fallo causado por la plataforma.

El grupo docker no es un usuario sin privilegios

Añadir una cuenta al grupo docker evita escribir sudo, pero normalmente permite controlar el motor con privilegios equivalentes a root. En equipos compartidos valora Docker rootless, limita el acceso al socket y aplica la política de cuentas del centro o de la empresa.

4. Redes y persistencia: dos decisiones distintas

La red decide quién puede comunicarse con cada servicio; el almacenamiento decide qué datos sobreviven cuando se recrea un contenedor. No son intercambiables.

Mecanismo Uso habitual Riesgo o límite principal
Volumen nombrado Datos de bases de datos y ficheros de la aplicación Sigue ligado al host si no se copia o replica
Bind mount Código y configuración durante el desarrollo Depende de rutas y permisos del host
tmpfs Datos temporales que no deben persistir en disco Se pierde al detener el contenedor

También hay que distinguir tres conceptos de red:

  • Puerto interno: donde escucha el proceso dentro de su contenedor.
  • Puerto publicado (ports): conecta el host con el contenedor y puede hacerlo accesible desde fuera.
  • Puerto declarado (expose): documenta o facilita el acceso interno, pero no sustituye a un firewall ni publica por sí solo el servicio.

En una red definida por la persona administradora o por Compose, los servicios se localizan por nombre DNS. Por ejemplo, la aplicación debe conectarse a db:3306, no a una IP que pueda cambiar al recrear el contenedor. Una base de datos solo debe tener ports si existe un motivo concreto para acceder a ella desde el host; para la comunicación interna basta con compartir la red.

5. Preparar un entorno con Docker Compose

Cuando hay varios servicios, un archivo Compose permite describir la red, las imágenes, los puertos y los volúmenes en un documento versionable. Este ejemplo prepara un servidor web y una base de datos sin publicar el puerto interno de MariaDB:

services:
  web:
    image: nginx:1.27-alpine
    ports:
      - "127.0.0.1:8080:80"
    networks:
      - aplicacion
  db:
    image: mariadb:11.4
    env_file:
      - .env
    volumes:
      - datos-db:/var/lib/mysql
    networks:
      - aplicacion
    healthcheck:
      test: ["CMD-SHELL", "healthcheck.sh --connect --innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 5

networks:
  aplicacion:

volumes:
  datos-db:

El archivo .env puede partir de una plantilla sin secretos:

MARIADB_DATABASE=catalogo
MARIADB_USER=catalogo_app
MARIADB_PASSWORD=rellenar-en-el-entorno
MARIADB_ROOT_PASSWORD=rellenar-en-el-entorno

El .env real no debe subirse al repositorio. En producción se preferirá un gestor de secretos o el mecanismo equivalente del proveedor. La configuración del ejemplo es para un entorno de aprendizaje: no convierte automáticamente una instalación local en un despliegue preparado para Internet.

docker compose config --quiet
docker compose up --detach
docker compose ps
docker compose logs --tail 50 db
docker compose down

docker compose config permite revisar el resultado que Compose ha interpretado antes de crear recursos. down elimina los contenedores y la red del proyecto, pero no elimina los volúmenes salvo que se indique expresamente. healthcheck indica si MariaDB está preparada para aceptar conexiones; depends_on, por sí solo, solo ordena el arranque y no garantiza esa disponibilidad.

6. Aplicación al entorno de la unidad

Para la aplicación de ejemplo se puede utilizar una instancia cloud pequeña o un equipo local con Docker. En ambos casos se documentan las mismas evidencias:

  1. Preparar el anfitrión: anota sistema operativo, arquitectura, versión de Docker o hipervisor y recursos asignados.

  2. Aislar la red: crea una red para los servicios y publica solo el puerto que utilizará el cliente durante la práctica.

  3. Separar datos: asigna un volumen a la base de datos y define quién puede leer o escribir en él.

  4. Comprobar el ciclo de vida: crea, detén, recrea y elimina un contenedor de prueba para comprobar qué recursos son efímeros y cuáles persisten.

  5. Registrar la decisión: indica por qué el entorno elegido satisface los requisitos y qué cambiaría para pasar a producción.

flowchart LR
  F["Servidor físico o proveedor cloud"] --> V["Hipervisor o sistema anfitrión"]
  V --> VM["Máquina virtual opcional"]
  VM --> D["Motor de contenedores"]
  D --> N["Red interna"]
  N --> W["Servidor web"]
  N --> A["Servidor de aplicaciones"]
  A --> DB["Base de datos"]
  DB --> Vol["Volumen persistente"]

Este esquema no afirma que siempre sean necesarios todos los niveles. En local puede no existir una máquina virtual; en un proveedor cloud la instancia puede ser la capa visible; y en una plataforma gestionada el equipo puede no administrar el hipervisor. Lo importante es identificar qué nivel se configura y quién es responsable de él.

7. Buenas prácticas

  • Fijar versiones: utiliza etiquetas y versiones compatibles, y registra la imagen exacta que se ha probado.
  • Publicar poco: deja las bases de datos en redes internas y expón solo los puertos necesarios para el acceso de las personas usuarias.
  • Separar código y datos: recrea los contenedores sin perder la información que deba conservarse.
  • No guardar secretos en Git: utiliza variables protegidas, secretos del proveedor o un gestor específico; .env.example solo debe contener nombres y valores ficticios.
  • Comprobar la disponibilidad real: añade healthchecks y reintentos de la aplicación; que un contenedor esté en estado Up no demuestra que el servicio acepte peticiones.
  • Probar la recuperación: la persistencia de un volumen no es una copia de seguridad. Realiza una copia y una restauración de prueba.
  • Aplicar mínimo privilegio: evita --privileged, usa usuarios sin privilegios y monta configuraciones en modo solo lectura cuando sea posible.
  • Aplicar límites: asigna CPU y memoria razonables para evitar que un servicio monopolice el anfitrión.
  • Controlar el coste cloud: usa cuotas, alertas y una política de apagado o eliminación al terminar la actividad.

8. Errores frecuentes

Error frecuente Por qué ocurre Cómo evitarlo
Confundir contenedor con máquina virtual Se supone que ambos incluyen un sistema operativo completo Explica qué comparte cada uno con el anfitrión
Publicar todos los puertos Se utiliza -p por comodidad Publica solo la entrada necesaria y revisa el firewall
Guardar datos dentro del contenedor Se olvida que el contenedor se puede recrear Usa volúmenes o almacenamiento externo
Usar latest sin registrar la versión La etiqueta puede cambiar con el tiempo Fija una versión probada y documenta la actualización
Dejar una instancia cloud encendida Se olvida el ciclo de vida del recurso Configura alertas y elimina los recursos de la práctica
Confundir Up con servicio disponible El proceso existe, pero aún no acepta conexiones Usa un healthcheck, logs y una prueba funcional
Ejecutar down --volumes sin comprobarlo Se confunde eliminar contenedores con eliminar datos Haz copia y utiliza down sin --volumes durante las pruebas normales
Depender de la IP de un contenedor La IP puede cambiar al recrearlo Usa el nombre del servicio en la red interna
Tratar la pertenencia al grupo docker como inocua Se confunde comodidad con menor privilegio Protege el socket y valora rootless o una cuenta controlada
Considerar el volumen como una copia Persistencia y backup se mezclan Programa y prueba una restauración independiente

9. Resumen

En este tema has aprendido que:

  • una máquina virtual y un contenedor ofrecen niveles de aislamiento y costes diferentes;
  • una instancia cloud añade responsabilidades de red, acceso, coste y seguridad que también deben documentarse;
  • imágenes, contenedores, redes, puertos y volúmenes cumplen funciones distintas;
  • Docker Compose permite describir un entorno de varios servicios de forma reproducible.

Idea clave

Preparar la infraestructura no es solo instalar Docker o crear una máquina: es definir el aislamiento, los recursos, las redes, la persistencia y las responsabilidades que permiten ejecutar la aplicación con seguridad.

10. Para seguir practicando

Bibliografía y fuentes

Presentación