Qué es Docker: Análisis detallado

Públicado el

20 de noviembre de 2024

a las

22:44

Docker es una plataforma de código abierto que proporciona herramientas para crear, gestionar, desplegar y compartir contenedores.

Este conjunto de herramientas, como Docker ComposeDocker HubDocker CLI y Docker Engine, proporcionan una capa de abstracción que facilita la gestión de contenedores en comparación a otras soluciones como LXC. Esta capa de abstracción es uno de los principales valores añadidos que Docker ofrece en el mundo de los contenedores.

Actualizado el

21 de noviembre de 2024

a las

13:41
Qué es Docker

Docker es una plataforma de código abierto que proporciona herramientas para crear, gestionar, desplegar y compartir contenedores.

Este conjunto de herramientas, como Docker ComposeDocker HubDocker CLI y Docker Engine, proporcionan una capa de abstracción que facilita la gestión de contenedores en comparación a otras soluciones como LXC. Esta capa de abstracción es uno de los principales valores añadidos que Docker ofrece en el mundo de los contenedores.

Sin embargo, para tener una comprensión más profunda sobre qué es Docker y de algunas de sus características, también es necesario saber qué es un contenedor.

Qué es un contenedor

En el desarrollo de software, un contenedor se refiere a software empaquetado junto a todas las dependencias necesarias para ejecutarse, lo que los convierte una herramienta de gran utilidad en diversos escenarios.

Entre las características más interesantes de los contenedores se encuentra el hecho que, se ejecutan de forma aislada del resto de procesos, de otros contenedores y en cualquier entorno, en un servidor, máquina local, sistemas *nix, Windows o Mac.

Y aunque en el desarrollo de software la contenedorización no es un concepto nuevo, el conjunto de herramientas que conforman Docker fueron disruptivas desde sus inicios, dado que, fueron desarrolladas para solventar un problema que viene de lejos.

Y es que antes de la aparición de Docker, contenedorizar aplicaciones resultaba más complejo y requería de una serie de conocimientos sobre la configuración y funcionamiento de herramientas como LXC, que es utilizada para crear y gestionar contenedores, pero a diferencia de Docker, a un nivel más bajo.

Esta forma de trabajar con contenedores rápidamente posicionó a Docker como el estándar de facto, para la creación y gestión de contenedores de hoy en día, haciendo de esta tecnología una opción más atractiva frente a las máquinas virtuales.  

Diferencias entre contenedores y máquinas virtuales

A diferencia de las máquinas virtuales, los contenedores son más ligeros gracias a que comparten el Kernel del sistema anfitrión y solo incluyen las dependencias necesarias, lo que reduce significativamente el espacio que ocupan en disco y optimiza mejor el uso de los recursos del sistema.

Por otro lado, las máquinas virtuales necesitan un sistema operativo completo y contar con sus propios recursos asignados, esto hace que una máquina virtual, además de ser más pesada que su contraparte, sea menos portable y consuma más recursos.

Sin embargo cada herramienta tiene sus pros y contras, como también distintos casos de uso. En el caso de los contenedores que tienden a ser más ligeros, compartir el kernel del sistema anfitrión los hace más propensos a comprometerlo si un atacante detecta una vulnerabilidad. Mientras que con las máquinas virtuales resulta más difícil por que están completamente aisladas del sistema principal.

Las características de los contenedores los hacen la opción preferida para trabajar con aplicaciones autocontenidas, no solo por requerir menos espacio y hacer un mejor manejo de los recursos del sistema, si no también por su portabilidad y experiencia de desarrollo.

Docker ofrece una experiencia completa y fluida para gestionar contenedores

Crear un contenedor con Docker es relativamente sencillo. Para ello es necesario crear un archivo de configuración que puede llamarse docker-compose o simplemente compose, y utilizar una de las extensiones .yaml o .yml.

Independientemente del nombre o la extensión, este archivo permite configurar todas las directivas necesarias de un contenedor. Además, es posible definir múltiples contenedores en el mismo archivo de configuración.

El siguiente ejemplo de un archivo de configuración incluye tres contenedores: el primero corresponde a una imagen de Nginx, que podría servir como proxy inverso para los otros servicios, como MySQL o PhpMyAdmin.

docker
version: '3.8'

services:
  nginx:
    image: nginx:1.23.3 
    container_name: ${NGINX_CONTAINER_NAME}
    restart: 'unless-stopped'
    volumes:
      - ./nginx/logs:/var/log/nginx
      - ./nginx/sites-available:/etc/nginx/sites-available
      - ./nginx/sites-enabled:/etc/nginx/sites-enabled
    ports:
      - "${NGINX_PORT}:80"
    networks:
      - my_network

  mysql:
    image: mysql:5.7
    container_name: ${MYSQL_CONTAINER_NAME}
    restart: 'unless-stopped'
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
      - mysql_data:/var/lib/mysql 
    networks:
      - my_network

  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    container_name: ${PHPMYADMIN_CONTAINER_NAME}
    restart: 'unless-stopped'
    environment:
      PMA_HOST: mysql
      PMA_USER: ${MYSQL_USER}
      PMA_PASSWORD: ${MYSQL_PASSWORD}
    ports:
      - "${PHPMYADMIN_PORT}:80"
    networks:
      - my_network

volumes:
  mysql_data: 

networks:
  my_network:
    driver: bridge

En el primer bloque se define el servicio de Nginx, un servidor web, proxy inverso y balanceador de carga. En dicho bloque se comienza por definir el nombre del servicio y, dentro de él, el resto de configuraciones necesarias:

  • image: Define la imagen que se utilizará para crear el contenedor, si no existe en cache, Docker intentará descargarla automáticamente de Docker Hub.
  • container_name: Asigna un nombre personalizado al contenedor; en caso de no configurar uno, Docker lo generará en formato hexadecimal. 
  • restart: Define la política de reinicio del contenedor. Si el contenedor se detiene a causa de un reinicio, un error en alguno de los servicios de los que depende, o incluso por un error interno del contenedor, intentará reiniciarse hasta que se detenga manualmente o se elimine.
  • environment: Sirve para declarar las variables de entorno del servicio. Los nombres pueden variar según la imagen, por lo que, para conocer las variables disponibles, es necesario consultar la documentación de la imagen en Docker Hub.
  • volumesEl atributo volumes especifica dónde se deben almacenar los datos persistentes del contenedor, como logs, sites-availables y sites-enabled. Según las necesidades de cada proyecto, los datos pueden variar. 
  • ports: El atributo ports es crucial para la comunicación entre el sistema anfitrión y el contenedor. Por ejemplo, el puerto interno puede configurarse para escuchar en el puerto 3000, y si en el sistema anfitrión ya existe un proceso escuchando en el mismo puerto, el atributo ports puede redirigir el puerto interno al puerto 3001.
  • networks: Es útil para conectar los distintos servicios y contenedores entre sí, ya que cada contenedor está aislado del resto. Para acceder a ellos, es necesario configurar una red compartida. En el ejemplo, 'my_network' es compartida por los tres contenedores.

Aunque en el archivo de configuración se han definido tres contenedores distintos, están conectados a través del  atributo networks, lo que resalta varios puntos importantes, siendo los más destacados el potencial de escalabilidad y portabilidad. 

Un proyecto contenedorizado incrementa su portabilidad

En cuanto a portabilidad, uno de los principales cuellos de botella es la diversidad de entornos de producción o desarrollo. Y cuando se trata de servidores la opción preferida son casi siempre sistemas basados en GNU/Linux, y aunque el ecosistema es similar en gran medida, e incluso, en algunos casos comparte la misma versión del Kernel o paquetes preinstalados, Fedora no es igual a Ubuntu, ni openSUSE que Debian.

Cada distribución configura y compila el kernel de manera única e incluye herramientas adicionales que las distinguen. Por ello, lo que funciona en Debian puede no hacerlo en openSUSE, salvo que se trate de la misma distribución en desarrollo y producción, o de versiones derivadas.

No obstante, aún en este escenario contenedorizar una aplicación sigue teniendo un valor intrínseco, ya que reduce significativamente los riesgos de errores por dependencias o problemas de compatibilidad entre entornos. Esto junto a la estadarización de herramientas internas de Docker que estimulan el desarrollo de otras alternativas cómo Podman que mitigan la falta de soporte oficial por parte de Docker.

Docker es un estándar en el mundo de los contenedores

La estandarización de herramientas internas y participación activa de Docker en el mundo del software libre, estimulan el desarrollo de otras alternativas o implementaciones para distribuciones o sistemas sin soporte oficial.

Un ejemplo de distribuciones que no cuentan con soporte oficial por parte de Docker es openSUSE. Sin embargo, a pesar de no contar con soporte oficial, es posible utilizar Docker en esta distribución de la mano de The Moby Project, un framework de Docker.

Aunque este framework no está precisamente pensado para equipos de desarrollo que necesitan una solución completa o lista para utilizar, la comunidad de openSUSE se ha encargado de ensamblar los componentes necesarios para contar con su propia versión de Docker. Esto no sin que existan algunas diferencias entre la versión oficial y la de openSUSE.

The Moby Project según su propia definición, es comparable a un "set de legos" de componentes estándar para ensamblar plataformas personalizadas, o bien para hacer parches en un build personalizado de Docker, como ha hecho openSUSE.

¿Entonces cuál es la diferencia entre el build de openSUSE y el oficial de Docker

La diferencia entre el build de openSUSE y el oficial de Docker, es que este último da soporte a distribuciones específicas y está optimizado para funcionar de manera consistente con el resto de herramientas que componen la plataforma.

En cambio el build de openSUSE tiene parches orientados mas bien a funcionar con el ecosistema de dicha distribución tales como; Yast que además incluye Zypper para gestionar paquetes desde la terminal, lo que lo convierte en algo más complejo de implementar que el resto de distribuciones.

La arquitectura interna de Docker

Docker se compone de múltiples herramientas que trabajan juntas para garantizar la mejor experiencia posible a los desarrolladores y a su vez, estimular el desarrollo de nuevas tecnologías en el mundo de los contenedores.

Inicialmente se basaba en la tecnología de contenedorización de GNU/LinuxLXC, pero más adelante desarrolló la suya propia llamada libcontainer, y si bien es cierto que ambas interactúan directamente con el Kernel, la separación de LXC y posterior migración a libcontainer fue una forma de deshacerse de una dependencia de los tiempos de desarrollo de esta tecnología y a la vez de una limitación.

Esta migración permitió a Docker ganar más control sobre la optimización de procesos y otorgo mayor flexibilidad al equipo detrás de esta tecnología, ya que dejaron de depender de LXC y comenzarón a trabajar con contenedores en base a su propia filosofía.

Docker Engine, el core de la plataforma

Docker Engine es el núcleo de la plataforma, solo se encuentra disponible para algunas distribuciones de GNU/Linux, y a través de Docker Desktop para otros sistemas operativos.

No obstante, siempre que la arquitectura este soportada oficialmente, los pasos para instalar Docker también aplican para las derivativas de cada distribución. El único inconveniente puede ser que, Docker no verifica ni prueba los procesos de instalación o builds de distribuciones sin soporte oficial.

Las distribuciones con soporte oficial son; DebianUbuntuFedoraRHELCentOS y SLES, esta última es la versión para servidores de openSUSE y aunque SLES soporta otras arquitecturas como; x84_86 (Intel 64 y AMD 64), ppc64le, s390x, Arm64, Docker solo da soporte oficial a la arquitectura s390x.

Qué es Docker Engine

Docker Engine es una plataforma compuesta de tres componentes esenciales que actúan como una aplicación cliente-servidor, Docker CLI, Docker Daemon y una API REST.

Esta arquitectura está organizada de forma que, el cliente de Docker (CLI) se comunica con el daemon a través de la API REST lo que permite crear, ejecutar y distribuir contenedores.

La comunicación entre el daemon y el cliente de Docker se realiza a través de sockets UNIX o interfaces de red.  Cuando el daemon se encuentra en la misma máquina que el CLI, se utilizan sockets UNIX para la comunicación y en caso que los contenedores se encuentren en un servidor remoto se utilizan las interfaces de red.

Qué es Docker Desktop

Docker Desktop es la forma más sencilla de instalar Docker Engine y comenzar a trabajar con contenedores. Se trata de una aplicación de escritorio que incluye todo lo necesario para interactuar con Docker a través de una interfaz gráfica intuitiva y elimina la necesidad de utilizar la línea de comandos.

Es además la forma de instalar Docker en sistemas como MacOS o Windows

En sistemas basados en GNU/Linux los contenedores desplegados antes de la instalación de Docker Desktop no estarán disponibles. Por que a diferencia de Docker Engine, Docker Desktop se ejecuta en una máquina virtual que crea y utiliza su propio contexto.

Gracias a la creciente popularidad de Arch Linux Docker Desktop también se encuentra disponible para está distribución.

Cuando se instala Docker Engine a través de Docker Desktop es importante tener en cuenta que en los siguientes escenarios se requiere pagar una subscripción.

  • Sí el número de empleados excede los 250.
  • Sí los beneficios anuales exceden los 10 millones de dolares estadounidenses.
Docker Compose

Docker Compose es una herramienta diseñada para trabajar con aplicaciones multi-contenedor de manera eficiente y simplificada en cualquier entorno, desarrollo, stage o producción.

Al igual que en la arquitectura interna de Docker Engine, la comunicación con Docker Compose se realiza a través de Docker CLI. Esta herramienta permite orquestar varios contenedores a través de un archivo de configuración .yml, siguiendo las especificaciones de compose espec, también establecidas por Docker.

El archivo de configuración de Docker Compose se basa exclusivamente en directivas y configuraciones, cosa que lo hace ligero y fácil de compartir entre equipos.

Reflexiones finales

Aunque en el artículo se han tratado una variedad aspectos sobre Docker, no se han tocado temas como DockerfileDocker Hub o cómo funciona internamente un contenedor y cuya lectura es recomendada.

En conclusión, Docker se ha consolidado como una herramienta fundamental en el desarrollo de software moderno, a tal punto que se ha convertido en el estándar de facto para trabajar con contenedores.

Su presencia en distintos sistemas operativos y gran aporte a la comunidad open source hacen que sea una opción acertada para cualquier proyecto.

Fuentes