Czytaj książkę: «Aprender Docker, un enfoque práctico»

Czcionka:



Aprender Docker, un enfoque práctico

Primera edición, 2022

© 2022 José Juan Sánchez Hernández

© MARCOMBO, S.L. 2022

www.marcombo.com

Diseño de la cubierta: ENEDENÚ DISEÑO GRÁFICO

Corrección: Mónica Muñoz

Maquetación: Reverté-Aguilar

Directora de producción: M.a Rosa Castillo

Docker y el logotipo de Docker son marcas comerciales o marcas comerciales registradas de Docker, Inc. en los Estados Unidos y/o en otros países. Docker, Inc. y otras partes también pueden tener derechos de marca registrada en otros términos utilizados en este libro.

Cualquier forma de reproducción, distribución, comunicación pública o transformación de esta obra solo puede ser realizada con la autorización de sus titulares, salvo excepción prevista por la ley. Diríjase a Cedro (Centro Español de Derechos Reprográficos, www.cedro.org) si necesita fotocopiar o escanear algún fragmento de esta obra.

ISBN: 978-84-267-3448-8

Producción del ePub: booqlab

A mis padres, José y María; a mi mujer, Noelia y a mi hija, María

Índice general

Lista de siglas y acrónimos

Acerca de este libro

CAPÍTULO 1 Conceptos básicos

1.1. ¿Qué es Docker?

1.1.1. Docker como tecnología de contenedores

1.1.2. Docker, Inc.

1.2. ¿Qué ventajas nos aporta el uso de Docker?

1.3. Breve historia de las tecnologías de aislamiento

1.4. ¿Qué es una máquina virtual?

1.5. ¿Qué es un contenedor?

1.6. Analogía con los contenedores de transporte marítimo

1.7. Diferencias entre contenedores y máquinas virtuales

1.8. Arquitectura de Docker

1.9. Cliente de Docker

1.9.1. Docker CLI

1.9.2. Docker Compose

1.10. Docker Engine

1.10.1. Docker Engine API

1.10.2. Docker daemon

1.11. Container runtime

1.11.1. containerd

1.11.2. runc

1.12. Docker Registry

1.12.1. Docker Hub

1.12.2. Otros registros

1.13. Objetos de Docker

1.13.1. Imágenes

1.13.2. Contenedores

1.13.3. Volúmenes

1.13.4. Redes

1.14. Orquestación de contenedores

1.15. Organizaciones y estándares

1.15.1. Open Container Initiative (OCI)

1.15.2. Cloud Native Computing Foundation (CNCF)

1.16. Alternativas a Docker

CAPÍTULO 2 Instalación de Docker

2.1. Docker Engine Community

2.2. Instalación de Docker Engine en Linux

2.2.1. Métodos de instalación en Ubuntu

2.2.2. Instalación en Ubuntu utilizando el script oficial

2.2.3. Instalación en Ubuntu desde los repositorios oficiales de Docker

Configuración del repositorio oficial de Docker

Instalación de Docker Engine

Comprobación de la instalación

2.2.4. Pasos posteriores a la instalación en Linux

Configuración del usuario

Configuración de Docker Engine para que se inicie automáticamente

2.3. Instalación de Docker Desktop en Windows 10

2.3.1. Instalación de Docker Desktop utilizando WSL 2 como backend

2.4. Instalación de Docker Engine en Windows Server

Comprobación de la instalación

2.5. Instalación de Docker Desktop en macOS

2.6. Play with Docker

CAPÍTULO 3 Imágenes Docker

3.1. ¿Qué es una imagen Docker?

3.2. ¿Qué es un repositorio de imágenes?

3.3. ¿Qué es un tag?

3.4. ¿Qué es el digest de una imagen?

3.5. ¿Qué es el namespace de un repositorio?

3.6. ¿Qué es un registry?

3.7. Docker Hub

3.7.1. Repositorios de imágenes oficiales

3.7.2. Repositorios de imágenes de organizaciones verificadas

3.7.3. Repositorios de imágenes de la comunidad

3.8. El archivo Dockerfile

3.9. Creación de una imagen a partir de un archivo Dockerfile

3.10. Cómo publicar una imagen en Docker Hub

3.11. Capas de una imagen

3.12. Soporte para múltiples arquitecturas

3.13. Formato de las imágenes Docker

3.14. Buscar imágenes en Docker Hub ‒ docker search

3.14.1. Buscar imágenes por nombre

3.14.2. Buscar imágenes utilizando filtros

3.15. Administración de imágenes – docker image

3.16. Descargar imágenes – docker pull

3.16.1. Descargar imágenes desde Docker Hub

3.16.2. Descargar imágenes desde un registry diferente a Docker Hub

3.17. Mostrar imágenes – docker images

3.17.1. Mostrar las imágenes que tenemos descargadas

3.17.2. Mostrar las imágenes intermedias

3.17.3. Mostrar el identificador de las imágenes

3.17.4. Mostrar el digest de las imágenes

3.18. Eliminar imágenes – docker rmi

3.18.1. Eliminar una imagen por su tag

3.18.2. Eliminar una imagen por su identificador

3.18.3. Eliminar todas las imágenes, excepto las dangling images

3.18.4. Eliminar las dangling images

3.18.5. Eliminar las imágenes que no están siendo utilizadas

3.19. Consultar el historial de una imagen – docker history

3.20. Mostrar información detallada – docker inspect

CAPÍTULO 4 Contenedores Docker

4.1. Ciclo de vida de un contenedor

4.2. Administración de contenedores – docker container

4.3. Creación y ejecución de contenedores – docker run

4.4. Hello World!

4.5. Obtener el listado de contenedores – docker ps

4.5.1. Obtener el listado de los contenedores que están en ejecución

4.5.2. Obtener el listado de todos los contenedores

4.5.3. Obtener el identificador de los contenedores que están en ejecución

4.5.4. Obtener el identificador de todos los contenedores

4.6. Ejecutar un comando dentro de un contenedor

4.7. Ejecutar un contenedor en modo interactivo

4.8. Eliminar contenedores – docker rm

4.8.1. Eliminar un contenedor que está detenido

4.8.2. Eliminar un contenedor que está en ejecución

4.8.3. Eliminar un contenedor y sus volúmenes anónimos asociados

4.8.4. Eliminar los contenedores que están detenidos

4.8.5. Eliminar los contenedores que están en ejecución y detenidos

4.9. Mostrar la salida estándar de un contenedor – docker logs

4.10. Creación de un contenedor en segundo plano

4.11. Publicar los puertos de un contenedor

4.11.1. Opción -p, --publish

4.11.2. Opción -P, --publish-all

4.12. Cómo conectarnos a un contenedor en ejecución

4.12.1. docker attach

4.12.2. docker exec

4.13. Copiar archivos y directorios – docker cp

4.14. Cómo detener un contenedor – docker stop

4.15. Cómo iniciar un contenedor – docker start

4.16. Políticas de reinicio

CAPÍTULO 5 Almacenamiento en Docker

5.1. Almacenamiento en Docker

5.2. Bind mounts

5.3. Formas de crear un bind mount en un contenedor

5.4. Crear un bind mount de solo lectura

5.5. Cómo crear las rutas de los directorios en un bind mount

5.6. Ejemplo para compartir el código fuente de una aplicación

5.7. Ejemplo para compartir un archivo de configuración

5.8. Volúmenes

5.9. Administración de volúmenes – docker volume

5.10. Creación de un volumen

5.10.1. Creación de un volumen con el comando docker volume create

5.10.2. Creación de un volumen al crear un contenedor con docker run

5.11. Inspeccionar un volumen

5.12. Obtener el listado de volúmenes

5.13. Eliminar volúmenes que no están en uso

5.14. Eliminar volúmenes

5.15. Ejemplo de creación de un contenedor con MySQL

5.15.1. Creación de un contenedor MySQL con un volumen anónimo

5.15.2. Creación de un contenedor MySQL con un volumen con nombre

5.15.3. Inicializar un contenedor de MySQL con una base de datos

CAPÍTULO 6 Redes en Docker

6.1. Redes en Docker

6.1.1. Container Network Model (CNM)

6.1.2. libnetwork

6.1.3. Drivers de red

6.2. Redes de tipo bridge

6.3. Administración de redes – docker network

6.4. Obtener el listado de redes

6.5. Creación de una red

6.6. Conectar un contenedor a una red

6.6.1. Con el comando docker network connect

6.6.2. Con la opción --network cuando se crea un contenedor

6.7. Desconectar un contenedor de una red

6.8. Inspeccionar una red

6.9. Eliminar las redes que no están en uso

6.10. Eliminar redes

6.11. Cómo conectar un contenedor Adminer con MySQL

6.11.1. Utilizando enlaces entre contenedores con la opción --link

6.11.2. Utilizando una red bridge definida por el usuario

6.12. Cómo conectar WordPress, MySQL y phpMyAdmin

CAPÍTULO 7 Docker Compose

7.1. ¿Qué es Docker Compose?

7.1.1. La especificación Compose

7.1.2. La implementación Docker Compose

7.2. Instalación de Docker Compose v2

7.3. El archivo de configuración de Docker Compose

7.3.1. version

7.3.2. services

7.3.3. volumes

7.3.4. networks

7.3.5. configs

7.3.6. secrets

7.4. Comandos de Docker Compose

7.5. Ejemplo de un servicio Apache HTTP Server

7.6. Ejemplo de un servicio MySQL

7.7. Cómo utilizar archivos con variables de entorno

7.8. Ejemplo de una aplicación con dos servicios

7.9. Despliegue de una aplicación WordPress

7.10. Creación de un entorno de desarrollo LAMP

7.11. Creación de un entorno de desarrollo LEMP

7.12. Repositorio con proyectos de ejemplo

ANEXO A docker system

Lista de siglas y acrónimos


ACI Azure Container Instances
API Application Programming Interface
CI/CD Continuous Integration/Continuous Delivery
CLI Command Line Interface
CMS Content Management System
CNCF Cloud Native Computing Foundation
CNM Container Network Model
CRI Container Runtime Interface
DCE Docker Community Edition
DEE Docker Enterprise Edition
ECS Elastic Container Service
HTTP Hypertext Transfer Protocol
HTTPS Hypertext Transfer Protocol Secure
IPAM Internet Protocol Address Management
ISO International Organization for Standardization
JSON JavaScript Object Notation
MAC Media Access Control
MCR Mirantis Container Runtime
OCI Open Container Initiative
PaaS Platform as a Service
RC Release Candidate
REST Representational State Transfer
SDK Software Development Kit
SDN Software Defined Networking
SLAT Second Level Address Translation
UUID Universally Unique Identifier
VM Virtual Machine
VMM Virtual Machine Monitor
WSL Windows Subsystem for Linux

Acerca de este libro

Este libro está dirigido a estudiantes, profesores, profesionales y a todas aquellas personas que quieran conocer qué es la tecnología de contenedores Docker y todavía no sepan cómo empezar a utilizarla en su entorno de trabajo.

El libro está dividido en siete capítulos, que lo ayudarán a tener una visión global de todos los componentes que forman el ecosistema Docker y a conocer con detalle cómo utilizar cada uno de los principales objetos de Docker: imágenes, contenedores, volúmenes y redes.

En el primer capítulo, encontrará los conceptos básicos que debe conocer antes de entrar en materia. La lectura de este capítulo es fundamental para entender con mayor claridad el resto del libro. El capítulo 2 lo ayudará a conocer los detalles del proceso de instalación de Docker Engine para Linux y Docker Desktop para Windows y macOS.

El capítulo 3 está dedicado al estudio de las imágenes Docker. Aquí aprenderemos lo que es un repositorio, un tag o un digest de una imagen. Veremos cómo podemos crear una imagen, cómo publicarla en Docker Hub y todos los comandos básicos para poder gestionar las imágenes en un host de Docker.

En el capítulo 4, estudiaremos los comandos necesarios para gestionar el ciclo de vida básico de un contenedor. En el capítulo 5, se analizan todas las posibilidades que nos ofrece Docker para implementar persistencia de datos entre un contenedor y el host de Docker. Aprenderemos las diferencias entre un bind mount y un volumen, además de los comandos necesarios para gestionarlos.

En el capítulo 6, estudiaremos los diferentes tipos de redes que existen en Docker y los comandos básicos para poder gestionarlas. El último capítulo está dedicado a la herramienta Docker Compose, donde se explica cómo gestionar y ejecutar aplicaciones con múltiples contenedores Docker de una forma muy sencilla.

CAPÍTULO 1
Conceptos básicos
1.1. ¿Qué es Docker?

Cuando hablamos de Docker, podemos referirnos a la tecnología que permite desarrollar, desplegar y ejecutar aplicaciones en entornos aislados denominados «contenedores». O también podemos referirnos a la empresa Docker, Inc., que es la que desarrolla esta tecnología.

1.1.1. Docker como tecnología de contenedores

Docker permite empaquetar las aplicaciones en contenedores que incluyen todo lo necesario para que se puedan ejecutar en un entorno de manera aislada. Cada contenedor almacena el código fuente de la aplicación, los archivos de configuración y todas las dependencias software que necesita. Esta estrategia permite que las aplicaciones se puedan ejecutar de la misma manera sobre cualquier infraestructura que tenga soporte para Docker, tanto de forma local como en la nube.

Con la tecnología de contenedores para aplicaciones, ya no es necesario preocuparse por el software que está instalado en la máquina donde se ejecuta el contenedor, porque todo lo que necesita la aplicación está incluido dentro del propio contenedor. Esta forma de trabajar resuelve el problema de «it works on my machine», donde una aplicación puede funcionar correctamente en el entorno de desarrollo, pero tiene errores en el entorno de producción, porque los dos entornos no son idénticos y contienen versiones de software diferentes.

Cada vez hay más equipos de desarrollo y operaciones que están utilizando la tecnología de contenedores Docker en sus flujos de trabajo. Esto ha permitido acelerar el proceso de desarrollo de las aplicaciones, ha facilitado la forma de distribuirlas y ha acelerado la automatización del despliegue en producción.

1.1.2. Docker, Inc.

Docker, Inc. es una empresa tecnológica estadounidense que fue fundada por Solomon Hykes en 2008 como dotCloud. En sus orígenes, ofrecía servicios de PaaS (Platform as a Service) y, en marzo de 2013, liberó como un proyecto open source un componente de su plataforma al que llamó Docker. Este proyecto tuvo una gran aceptación y supuso un cambio significativo en la forma de desarrollar, distribuir y desplegar software.

En octubre de 2013, dotCloud pasó a llamarse Docker, Inc. y, a partir de ese momento, fue cuando la empresa decidió centrarse en el desarrollo de su tecnología de contenedores.

1.2. ¿Qué ventajas nos aporta el uso de Docker?

Las principales ventajas que nos aporta el uso de Docker son las siguientes:

Soluciona el problema «it works on my machine».

Permite tener un entorno de desarrollo limpio, seguro y portátil.

Facilita la automatización de pruebas, integración y empaquetado.

Posibilita empaquetar una aplicación con todas las dependencias que necesita (código fuente, librerías, configuración, etc.) para ser ejecutada en cualquier plataforma.

Se eliminan inconsistencias entre los entornos de desarrollo, pruebas y producción.

El proceso de despliegue es rápido y repetible.

1.3. Breve historia de las tecnologías de aislamiento

Antes de Docker, ya existían implementaciones de aislamiento de recursos, como chroot (1982), FreeBSD jail (2000), Solaris Zones (2004), cgroups (2006) o Linux Containers (LXC), en el año 2008.

En primer lugar, apareció la llamada del sistema chroot, que fue desarrollada para la versión 7 de UNIX (1979) y, posteriormente, se incorporó a la versión 4 de BSD (1980). Esta operación permite cambiar el directorio raíz del sistema de archivos de un proceso y de sus procesos hijos aislando, de esta manera, su ejecución e impidiendo que puedan acceder a los archivos que están por encima del nuevo directorio raíz.

Años más tarde, FreeBSD se basó en la idea de chroot para desarrollar FreeBSD jail (2000), una implementación que permitía dividir un sistema en varios subsistemas llamados «jaulas» o jails. Todas las jaulas comparten el mismo kernel del sistema operativo anfitrión. Cada jaula puede tener un directorio raíz aislado del resto de sistema de archivos, su propio grupo de usuarios, su propio nombre de host y su propia dirección IP.

En 2004, se liberó el proyecto Solaris Zones, que permitía aislar la ejecución de los procesos del resto del sistema metiéndolos en zonas o sandboxes. Cada zona se comporta como un servidor virtual completamente aislado.

En 2006, los ingenieros de Google empezaron a trabajar en lo que más tarde se llamaría cgroups o «grupos de control». Los grupos de control son un mecanismo que permiten controlar la asignación de recursos a los procesos. Permiten definir jerarquías en las que se agrupan los procesos y establecer cuáles serán los límites de uso de los recursos del sistema (CPU, memoria, red, etc.). Esta funcionalidad se integró en el kernel de Linux en la versión 2.6.24 aunque, años más tarde, fue rediseñada y la versión que se encuentra actualmente en el kernel es conocida como cgroup v2.

Linux Containers, o LXC (2008), es un método de virtualización a nivel de sistema operativo que permite ejecutar aplicaciones en entornos aislados que comparten el kernel de Linux del sistema operativo anfitrión. Utiliza las características del kernel de cgroups para controlar la asignación de recursos a los procesos y namespaces para supervisar a qué recursos pueden acceder los procesos.

Las primeras versiones de Docker utilizaban LXC para ejecutar contenedores, pero fue reemplazado por una herramienta interna a la que llamaron libcontainer. Actualmente, libcontainer forma parte de runc, un runtime de contenedores que cumple con las especificaciones OCI (Open Container Initiative) del que hablaremos más adelante.

1.4. ¿Qué es una máquina virtual?

Una «máquina virtual» o virtual machine (VM) es un entorno que emula la misma funcionalidad de una máquina física. Una máquina virtual hace uso de los recursos que se le hayan asignado; cuenta con su propia CPU, memoria, interfaz de red, almacenamiento y su propio sistema operativo.

Las máquinas virtuales se crean y ejecutan sobre un software llamado «hipervisor» o virtual machine monitor (VMM). El hipervisor se ejecuta sobre una máquina física y actúa como una capa intermedia entre el hardware de la máquina anfitriona o host y la máquina virtual. El hipervisor se encarga de gestionar y distribuir los recursos de la máquina física (CPU, memoria, almacenamiento, etc.) entre las máquinas virtuales.

Es posible crear varias máquinas virtuales sobre una misma máquina física. Cada una de las máquinas virtuales estará aislada del resto, tendrá sus propios recursos y contará con su propio sistema operativo, que no tiene por qué ser el mismo que el de la máquina anfitriona.

1.5. ¿Qué es un contenedor?

Un «contenedor» se puede definir como una unidad estándar de software que permite empaquetar el código fuente de una aplicación y todas sus dependencias, para que se pueda distribuir y ejecutar de forma rápida y fiable en diferentes entornos.

También se puede definir como un proceso que ha sido aislado de todos los demás procesos de la máquina anfitriona donde se está ejecutando. Aunque es posible tener más de un proceso en un contenedor, las buenas prácticas nos recomiendan ejecutar solo un proceso por contenedor.

1.6. Analogía con los contenedores de transporte marítimo

El término docker, en inglés, significa «estibador», que es la persona encargada de realizar la carga y descarga de un buque u otros medios de transporte. Para entender mejor qué es un «contenedor», podemos establecer una analogía entre los contenedores que se utilizan en el transporte marítimo y los contenedores software.

Los contenedores de transporte marítimo:

Cumplen una normativa ISO (International Organization for Standardization), donde se establecen las medidas, tamaño y forma de los contenedores.

Se rigen por un estándar para distribuir mercancías.

Pueden ser transportados en cualquier embarcación que cumpla el estándar ISO.

Los contenedores software:

Cumplen con los estándares abiertos de la industria de los contenedores software desarrollados por la OCI (Open Container Initiative).

Se rigen por un estándar para distribuir software.

Pueden ser ejecutados en cualquier runtime que cumpla el estándar OCI.

1.7. Diferencias entre contenedores y máquinas virtuales

A continuación, se enumeran las principales diferencias que existen entre contenedores y máquinas virtuales:

Una máquina virtual necesita un sistema operativo completo para poder funcionar, mientras que un contenedor no, ya que comparte el kernel del sistema operativo de la máquina donde se está ejecutando.

Los contenedores necesitan menos recursos que las máquinas virtuales. Con el mismo hardware, es posible tener un mayor número de contenedores que de máquinas virtuales.

El tiempo necesario para iniciar un contenedor es mucho menor que el de una máquina virtual. Un contenedor se puede iniciar en cuestión de milisegundos, mientras que una máquina virtual puede llegar a necesitar algunos minutos.

Por lo general, los contenedores son más ligeros que las máquinas virtuales. El tamaño de los contenedores se suele medir en megabytes, mientras que el de las máquinas virtuales se suele medir en gigabytes.

Un contenedor se puede ejecutar en una máquina virtual pero no al revés.

Los contenedores no han venido para sustituir a las máquinas virtuales, ya que cada tecnología es adecuada para casos de uso diferentes. Podemos decir que ambas tecnologías se complementan entre sí.


Figura 1.1. Diferencias entre contenedores y máquinas virtuales.

1.8. Arquitectura de Docker

Al inicio, Docker fue diseñado con una arquitectura monolítica, pero, más tarde, fue rediseñado a una arquitectura modular, formada por diferentes componentes que pueden ser reemplazados o incluso utilizarse en otros proyectos.

Cada uno de los componentes de Docker se desarrolla por separado y muchos de ellos forman parte del proyecto Moby. El proyecto Moby es un proyecto open source creado por Docker, Inc. en 2017, donde se desarrollan componentes y herramientas que pueden ser utilizados para crear productos basados en la tecnología de contenedores. Podemos decir que Moby es el proyecto donde se desarrollan los componentes y Docker es un producto que utiliza esos componentes:


Los principales componentes de Docker que debemos conocer son los siguientes:

Cliente de Docker.

Docker CLI.

Docker Compose.

Docker Engine.

Docker Engine API.

Docker daemon.

Container Runtime.

Containerd.

Runc.

Docker Registry.

En la figura 1.2, se trata de dar una visión global de cómo se relacionan los componentes que forman la arquitectura de Docker. En la figura se muestran tres bloques que representan al cliente, el host de Docker y el Registry. El host de Docker será una máquina que tiene instalado el componente Docker Engine y puede estar dentro o fuera de nuestra red local. En una instalación habitual, el cliente también estará instalado en el host de Docker, pero no es un requisito obligatorio. En los siguientes apartados de este capítulo, se irá describiendo con más detalle cada uno de estos componentes.


Figura 1.2. Componentes de la arquitectura de Docker.

1.9. Cliente de Docker

Docker utiliza una arquitectura cliente-servidor, donde una aplicación cliente interactúa con un servicio llamado Docker daemon. Un mismo cliente puede comunicarse con más de un servicio Docker daemon. La comunicación entre el cliente y el servidor se realiza a través de una API HTTP, conocida como Docker Engine API.

Las aplicaciones cliente permiten que un usuario pueda interaccionar con el servicio Docker daemon para realizar acciones como crear y ejecutar contenedores. Las aplicaciones oficiales que se pueden utilizar como cliente son Docker CLI (Command Line Interface) y Docker Compose. Aunque cualquier aplicación cliente que haga uso de la API de Docker Engine puede ser un cliente válido.

El cliente y el servidor se pueden ejecutar en la misma máquina o pueden estar en máquinas separadas. Cuando el cliente y el servidor están en la misma máquina, la comunicación entre ambos se puede realizar a través de un socket IPC o un socket TCP. Y, cuando se encuentran en máquinas separadas, se realiza a través de un socket TCP.

A continuación, se muestran dos ejemplos donde se describe a alto nivel cómo es el flujo de ejecución de un comando y cuáles son los componentes que intervienen.

Ejemplo de ejecución del comando docker pull

En la figura 1.3, se muestra el flujo de ejecución a alto nivel del comando docker pull, que es el comando utilizado para descargar una imagen de un Docker Registry.

En este ejemplo, se realizan los siguientes pasos:

1. En primer lugar, el usuario ejecuta el comando docker pull desde la línea de comandos y el cliente Docker CLI se comunica con el servicio Docker daemon.

2. El servicio Docker daemon se encarga de gestionar la petición al Docker Registry para descargar la imagen solicitada por el cliente.

3. La imagen se descarga del Docker Registry y se almacena en el host de Docker.


Figura 1.3. Ejemplo del flujo de ejecución a alto nivel del comando docker pull.

Ejemplo de ejecución del comando docker run

En la figura 1.4, se muestra el flujo de ejecución a alto nivel del comando docker run, que es el comando utilizado para crear y ejecutar un contenedor a partir de una imagen.

En este ejemplo, se realizan los siguientes pasos:

1. En primer lugar, el usuario ejecuta el comando docker run desde la línea de comandos y el cliente Docker CLI se comunica con el servicio Docker daemon.

2. El servicio Docker daemon comprueba si la imagen que ha seleccionado el usuario para crear el contenedor se encuentra en el host de Docker. Si la imagen no estuviese en el host, entonces la descargaría automáticamente del Docker Registry.

3. Se crea un contenedor a partir de la imagen seleccionada y se inicia la ejecución.


Figura 1.4. Ejemplo del flujo de ejecución a alto nivel del comando docker run.

1.9.1. Docker CLI

Docker CLI es el cliente oficial de Docker. Es una interfaz de línea de comandos que permite a los usuarios interaccionar con el servicio Docker daemon. El comando base de esta aplicación es docker.

El caso de uso más habitual de Docker CLI es cuando se quiere interactuar con un único contenedor, mientras que Docker Compose se suele utilizar para trabajar con aplicaciones que ejecutan varios contenedores a la vez.

En las distribuciones Linux, podemos instalar la versión Community Edition de Docker CLI con el paquete docker-ce-cli, que es un paquete independiente de Docker Engine, mientras que, en los sistemas operativos Windows y Mac, viene incluido en la aplicación Docker Desktop, que incluye también Docker Engine, entre otros componentes.

1.9.2. Docker Compose

Docker Compose es una aplicación utilizada desde la línea de comandos y permite a los usuarios interaccionar con el servicio Docker daemon.

Esta aplicación permite definir y ejecutar aplicaciones con múltiples contenedores. Utiliza un archivo de configuración con formato YAML, para definir los servicios, las redes y los volúmenes de los que consta la aplicación que queremos ejecutar. Una de las ventajas que nos ofrece Docker Compose es que solo hay que ejecutar un comando para crear y ejecutar todos los servicios que se han definido en el archivo YAML de configuración.

Actualmente, existen dos versiones de Docker Compose. La versión v1 está desarrollada en Python y tiene que ser instalada como una herramienta adicional con el nombre de docker-compose, mientras que la nueva versión v2 está desarrollada en Go e integra el comando compose dentro del cliente oficial de Docker CLI. Por lo tanto, para utilizar la nueva versión, se utiliza el comando docker compose.

En el momento de escribir este libro, la versión v2 de Docker Compose solo está incluida en la aplicación Docker Desktop para Windows y macOS. Se espera que, muy pronto, también estará disponible en el cliente oficial Docker CLI para Linux. De momento, se puede instalar de forma manual como un plugin de Docker CLI.

1.10. Docker Engine

Docker Engine es el componente principal de Docker, encargado de crear, ejecutar y gestionar contenedores. Tiene un diseño modular y está formado por varios componentes que cumplen los estándares abiertos de la Open Container Iniciative (OCI). Entre sus componentes, destacamos los siguientes:

Docker Engine API.

Docker daemon.

Container Runtime.

Gestión de redes y almacenamiento.

Docker Build (BuildKit), para la creación de imágenes.

Distribution, para la interacción con los registros de contenedores.

Soporte nativo para la orquestación de contenedores con Docker Swarm (SwarmKit).

Gestión de plugins.

El componente principal de Docker Engine es el Docker daemon, que es un proceso encargado de administrar las imágenes, contenedores, redes y volúmenes. En muchas ocasiones, cuando nos referimos a Docker Engine, nos estamos refiriendo realmente al proceso Docker daemon.

En las primeras versiones, al instalar Docker Engine, se incluía el cliente Docker CLI, el Docker daemon y el Container Runtime, pero, actualmente, son tres componentes independientes que se tienen que instalar en paquetes separados.

Docker Engine se ejecuta de forma nativa en los sistemas Linux y Windows Server. En el resto de los sistemas operativos Windows, que no sean Windows Server, y en los sistemas operativos Mac, no se ejecuta de forma nativa, sino que lo hace sobre una máquina virtual Linux.

En las distribuciones Linux, podemos instalar la versión Community Edition de Docker Engine con el paquete docker-ce, mientras que, en los sistemas operativos Windows y Mac, viene incluido en la aplicación Docker Desktop.


Figura 1.5. Componentes de Docker Engine.

1.10.1. Docker Engine API

La comunicación entre un cliente Docker y el servicio Docker daemon se realiza a través de una API HTTP conocida como Docker Engine API.

Esta API implementa todas las operaciones que un usuario puede realizar desde el cliente oficial de Docker CLI; por ejemplo, cuando un usuario ejecuta el comando docker ps desde la línea de comandos, el cliente Docker CLI está haciendo una petición GET al endpoint /containers/json de la API. El servicio Docker daemon ejecuta la petición del cliente y le devuelve una respuesta en formato JSON.

La API suele cambiar cada vez que se libera una nueva versión de Docker Engine. Para que los clientes que tienen una versión antigua de la API puedan seguir manteniendo compatibilidad con las nuevas versiones de Docker Engine, se incluye un prefijo en la URL de los endpoints de la API indicando la versión que quieren utilizar para comunicarse; por ejemplo, una llamada al endpoint /v1.41/containers/json utilizaría la versión 1.41 de la API, mientras que una llamada a /v1.40/containers/json usaría la versión 1.40.

Puede consultar la especificación completa de la API en la web oficial de Docker. En el momento de escribir este libro, la última versión disponible es la v1.41:


En la actualidad, existe un SDK oficial para Go y otro para Python, que permite a los desarrolladores crear aplicaciones que interactúan con la API de Docker Engine. También existe una gran variedad de librerías no oficiales que han sido desarrolladas por la comunidad para otros lenguajes de programación. A continuación, se muestra un ejemplo de cómo se puede hacer uso de la API de Docker Engine con la utilidad curl.

Ejemplo

En este ejemplo, vamos a utilizar la utilidad curl como cliente para realizar una llamada al endpoint http://localhost/v1.41/containers/json de la API de Docker Engine, para obtener un listado de todos los contenedores que están en ejecución:


1. En este ejemplo, utilizamos un socket UNIX porque el cliente y el servicio Docker daemon se encuentran en la misma máquina. Como este ejemplo se ha realizado en una máquina Linux, el socket que utiliza el servicio Docker daemon está ubicado en /var/run/docker.sock.

2. Indicamos el endpoint de la API de Docker Engine al que queremos hacer la llamada.

Si no existe ningún contenedor en ejecución, obtendremos una respuesta vacía:


Pero, si existen contenedores en ejecución, obtendremos una respuesta similar a la que se muestra a continuación. Tenga en cuenta que se han omitido algunos valores de la respuesta para simplificarla y mejorar su legibilidad:


Si desea profundizar más sobre el empleo de los SDKs de Docker, puede consultar la web oficial, donde encontrará diferentes ejemplos de uso:


1.10.2. Docker daemon

El servicio Docker daemon es el encargado de crear y gestionar todos los objetos con los que trabaja Docker, como las imágenes, los contenedores, las redes y los volúmenes. Este servicio se ejecuta en un proceso llamado dockerd.

El cliente Docker se comunica con el servicio Docker daemon a través de una API HTTP y el servicio Docker daemon se comunica con el container runtime. En las primeras versiones, el Docker daemon también incluía el container runtime, pero, actualmente, son dos componentes independientes. El container runtime de Docker está formado por containerd y runc, de los que hablaremos más adelante.

El servicio Docker daemon expone una API HTTP para comunicarse con los clientes Docker y puede utilizar tres tipos de sockets para interaccionar con ellos: unix, tcp y fd.

En una instalación habitual, el cliente Docker y el Docker daemon suelen estar en la misma máquina. Cuando trabajamos con contenedores Linux, se utiliza un socket de tipo UNIX que estará en la ruta /var/run/docker.sock. Para poder hacer uso de este socket, es necesario tener permisos de root o pertenecer al grupo de usuarios del sistema docker. Cuando trabajamos con contenedores Windows, se utiliza un named pipe, que estará en la ruta \\.\pipe\docker_engine.

Si vamos a trabajar en un entorno donde el cliente y el Docker daemon se ejecutan en diferentes máquinas, entonces necesitaremos utilizar un socket TCP. En este caso, la comunicación se realiza por defecto sobre un canal no seguro en el puerto 2375. Esta configuración puede ser adecuada para un entorno de desarrollo, pero nunca se debe utilizar en un entorno de producción. En un entorno de producción, se debe usar una conexión cifrada con TLS y se suele emplear el puerto 2376.

1.11. Container runtime

El container runtime es el software encargado de ejecutar los contenedores. Docker Engine utiliza dos tipos de container runtime:

containerd: container runtime de alto nivel.

runc: container runtime de bajo nivel.

1.11.1. containerd

Es un container runtime de alto nivel, que se ejecuta como un proceso daemon. Este componente se encarga de administrar el ciclo de vida de un contenedor dentro de un host. Realiza tareas como descargar las imágenes de los registros de los contenedores, almacenarlas en el host, supervisar la ejecución de los contenedores o gestionar el almacenamiento y las redes.

Este componente está diseñado para ser embebido dentro de otros sistemas más complejos. Aunque puede ser utilizado desde la línea de comandos con el cliente ctr, que se incluye en la instalación por defecto.

Se trata de un proyecto open source, que fue creado por Docker, Inc. en 2016, junto a Google e IBM. En 2017, fue donado a la Cloud Native Computing Foundation (CNCF) y, en 2019, se convirtió en un proyecto graduado de la CNCF. Esto indica que el proyecto se encuentra en un nivel de madurez adecuado para ser utilizado por las empresas más conservadoras a la hora de adoptar nuevas tecnologías.

El componente containerd también implementa la interfaz CRI (Container Runtime Inferface) de Kubernetes. Esto quiere decir que este container runtime puede ser utilizado en un cluster de Kubernetes para crear y ejecutar contenedores a partir de imágenes Docker, que son imágenes compatibles con la especificación OCI.

1.11.2. runc

Es un container runtime de bajo nivel, encargado de interaccionar con el kernel del host de la máquina anfitriona donde se ejecutan los contenedores. Utiliza el componente libcontainer para interaccionar con el sistema operativo del host.

Se trata de una implementación de código abierto de la especificación OCI Runtime Specification, que describe cómo tiene que ser la configuración, el entorno de ejecución y el ciclo de vida de un contenedor.


Figura 1.6. Ejemplo de cómo interaccionan containerd y runc con el resto de los componentes.

1.12. Docker Registry

Un Docker Registry, o registro de contenedores Docker, es un servicio encargado de almacenar y distribuir repositorios de imágenes Docker. Los usuarios pueden utilizar este servicio para publicar sus repositorios de imágenes y compartirlos con otros usuarios de una forma sencilla.

Un repositorio de imágenes es un conjunto de imágenes que se agrupan bajo el mismo nombre dentro del mismo registro. Cada una de las imágenes de un repositorio está etiquetada con un tag, que se suele utilizar para indicar su versión.

En el capítulo 3, estudiaremos con más detalle qué es un registro y los diferentes tipos que existen. En este apartado, solo se trata de mostrar una descripción general que nos ayude a entender, de forma global, cuál es el papel de cada uno de los componentes de Docker.

1.12.1. Docker Hub

Docker Hub es el registro de contenedores oficial de Docker. Es el registro que viene configurado por defecto cuando se instala Docker Engine, aunque puede ser reemplazado por otros registros de contenedores.

Los usuarios pueden utilizar repositorios públicos de Docker Hub para almacenar y compartir sus imágenes de forma gratuita, o pueden contratar una suscripción de pago para disponer de repositorios privados ilimitados.

Entre las principales funcionalidades de Docker Hub, podemos destacar las siguientes:

Permite crear equipos y organizaciones.

Posibilita descargar y utilizar una gran cantidad de imágenes oficiales y de organizaciones verificadas, de forma gratuita.

Facilita crear y publicar imágenes de manera automática a partir del contenido de un repositorio externo de GitHub o Bitbucket; por ejemplo, un repositorio de Docker Hub se puede configurar para crear una imagen de modo automático cada vez que se publican nuevos cambios en el código de una aplicación que está alojada en un repositorio de GitHub o BitBucket. Además, se pueden configurar una serie de test para que la imagen solo se publique cuando los test se hayan ejecutado con éxito.

También proporciona el uso de webhooks para desencadenar acciones en otros servicios externos; por ejemplo, cada vez que se publica una imagen en Docker Hub, se puede activar un webhook, que hace una petición POST a una determinada URL que podemos configurar en Docker Hub.

1.12.2. Otros registros

Además de Docker Hub, podemos hacer uso de otros registros de contenedores como:

GitHub Container Registry.

GitLab Container Registry.

DigitalOcean Container Registry.

Amazon Elastic Container Registry.

Azure Container Registry.

Google Cloud Container Registry.

1.13. Objetos de Docker

Los principales objetos de Docker con los que vamos a trabajar a lo largo del libro son:

Imágenes.

Contenedores.

Volúmenes.

Redes.

Hemos dedicado un capítulo para estudiar con detalle cada uno de estos objetos. En esta sección, solo mostraremos una descripción general de cada uno de ellos.

1.13.1. Imágenes

Las imágenes contienen el sistema de archivos que utilizarán los contenedores Docker. Para crear un contenedor, es necesario utilizar una imagen de forma obligatoria. A partir de la misma imagen, se pueden crear todos los contenedores que se necesiten. Por lo tanto, podemos decir que las imágenes son como unas plantillas que contienen el estado inicial del sistema de archivos raíz del contenedor.

En el capítulo 3, aprenderemos cómo crear una imagen, cómo publicarla en Docker Hub y todos los comandos básicos para poder gestionar las imágenes en un host de Docker.

1.13.2. Contenedores

Un contenedor Docker se crea a partir de una imagen. Se puede definir como un proceso que ha sido aislado de todos los demás procesos de la máquina donde se está ejecutando, también conocida como el «host de Docker». Los contenedores pueden tener más de un proceso en ejecución, pero las buenas prácticas recomiendan ejecutar un solo proceso por contenedor.

En el capítulo 4, estudiaremos todos los comandos necesarios para gestionar el ciclo de vida completo de un contenedor.

Contenedores Linux y contenedores Windows

En Docker, existen dos tipos de contenedores.

Contenedores Linux

Los contenedores Linux se pueden ejecutar en los sistemas operativos Linux, macOS y Windows. Estos contenedores solo se pueden crear a partir de imágenes específicas para contenedores Linux.

Cuando estos contenedores se ejecutan en un sistema operativo Linux, utilizan el kernel del sistema operativo de la máquina anfitriona. Sin embargo, cuando se ejecutan en macOS, lo hacen en una máquina virtual ligera sobre el hipervisor HyperKit, que es específico de macOS. En Windows, su ejecución dependerá del backend utilizado en Docker Desktop. En este caso, existen dos posibilidades:

WSL 2 como backend de Docker Desktop. En este caso, los contenedores Linux se ejecutan de forma nativa, sin ningún tipo de emulación, utilizando el kernel de Linux desarrollado por Microsoft para WSL 2.

Hyper-V como backend de Docker Desktop. En este caso, los contenedores Linux se ejecutan en una máquina virtual en Hyper-V basada en LinuxKit. Esta solución ofrece un rendimiento mucho menor que WSL 2; por este motivo, no se recomienda su uso para ejecutar contenedores Linux.


Figura 1.7. Contenedores Linux.

Contenedores Windows

Estos contenedores solo se pueden crear en los sistemas operativos Windows y Windows Server. Las imágenes que utilizan son imágenes específicas para contenedores Windows.

Los contenedores Windows disponen de dos modos de aislamiento en tiempo de ejecución:

Aislamiento de Hyper-V. En este modo, los contenedores se ejecutan en una máquina virtual en Hyper-V y cada contenedor tiene su propio kernel. Ofrece un buen nivel de aislamiento en el ámbito del hardware entre los contenedores y el host, así como un buen nivel de seguridad. Este es el modo de aislamiento que utilizan por defecto los contenedores Windows que se ejecutan en Windows 10.

Aislamiento de procesos. En este modo, los contenedores no tienen su propio kernel, sino que utilizan el kernel del sistema operativo anfitrión, del mismo modo que lo hacen los contenedores Linux de forma nativa. Este es el modo de aislamiento que utilizan por defecto los contenedores Windows que se ejecutan en Windows Server.


Figura 1.8. Contenedores Windows.

1.13.3. Volúmenes

Los volúmenes son un mecanismo que nos ofrece Docker para implementar persistencia de datos en un contenedor. Los contenedores que no tienen volúmenes asociados perderán todos los datos cuando el contenedor finalice su ejecución y se elimine. Si queremos conservar los datos que se han generado durante la ejecución del contenedor, necesitamos utilizar volúmenes.

Un contenedor puede tener asociados uno o varios volúmenes. Estos permiten almacenar en el host de Docker los datos de los directorios del contenedor que queremos conservar cuando el contenedor se elimine. El ciclo de vida de los volúmenes es independiente del ciclo de vida de los contenedores. Por lo tanto, los volúmenes seguirán estando disponibles, aunque se eliminen los contenedores que los están utilizando.

En el capítulo 5, estudiaremos las posibilidades que nos ofrece Docker para implementar persistencia de datos entre los contenedores y el host de Docker.

1.13.4. Redes

Docker nos permite crear diferentes tipos de redes para que los contenedores puedan comunicarse entre ellos y con el exterior. El componente principal de Docker Engine que se encarga de la gestión de las redes en Docker es libnetwork.

En el capítulo 6, estudiaremos los diferentes tipos de redes que podemos crear en Docker y los comandos básicos para poder gestionarlas.

1.14. Orquestación de contenedores

En muchas situaciones, vamos a necesitar que las aplicaciones se ejecuten sobre un cluster de servidores, para garantizar la alta disponibilidad y escalabilidad de los servicios.

Para desplegar una aplicación basada en contenedores en un cluster, vamos a necesitar el uso de herramientas adicionales, para realizar tareas que no se pueden hacer de forma manual. Estas herramientas son conocidas como «orquestadores de contenedores» y los más conocidos dentro del ecosistema Docker son Docker Swarm y Kubernetes.

Entre las tareas que suele realizar un orquestador de contenedores, podemos destacar las siguientes:

Automatiza el despliegue de una aplicación en un cluster de servidores.

Crea y ejecuta los contenedores entre los diferentes nodos del cluster.

Balancea la carga entre todos los contenedores.

Escala los servicios de forma automática cuando sea necesario.

Permite que una aplicación se recupere automáticamente de los errores.

Posibilita actualizar una aplicación sin que exista tiempo de inactividad.

Docker Swarm

Docker Swarm es un orquestador que viene integrado de forma nativa en Docker Engine. Este orquestador está siendo desarrollado por Docker, Inc. y forma parte del proyecto Moby Project, con el nombre de SwarmKit.


Figura 1.9. Ejemplo de un cluster de Docker Swarm formado por tres nodos Managers y cuatro Workers.

Kubernetes

Kubernetes, también conocido como K8s, es el orquestador más utilizado en la actualidad. Este orquestador fue desarrollado originalmente por Google, pero fue donado a la Cloud Native Computing Foundation (CNCF), que actualmente es la encargada de su desarrollo.

Kubernetes puede utilizar diferentes container runtimes para ejecutar contenedores. El único requisito reside en que sean compatibles con una API llamada Container Runtime Interface (CRI), que es la que permite interaccionar al container runtime con Kubernetes.

Kubernetes es compatible con containerd, que es el container runtime que utiliza Docker Engine. Por lo tanto, en un cluster de Kubernetes, se pueden crear y ejecutar contenedores a partir de imágenes Docker, que son imágenes que cumplen con la especificación OCI.

La aplicación Docker Desktop para macOS y Windows incluye soporte para crear un cluster de Kubernetes de un único nodo, que se ejecuta de forma local. Esta funcionalidad está deshabilitada por defecto y solo se debe utilizar en un entorno local de pruebas.


Figura 1.10. Ejemplo de un cluster de Kubernetes formado por un nodo Master y tres nodos Workers.

1.15. Organizaciones y estándares

La Open Container Initiative (OCI) y la Cloud Native Computing Foundation (CNCF) son dos proyectos que forman parte de la Fundación Linux, que trabajan para el impulso de las tecnologías de contenedores y las tecnologías abiertas en la nube.

La OCI se centra en el desarrollo de especificaciones y estándares abiertos, mientras que la CNCF está orientada al desarrollo de proyectos open source.

1.15.1. Open Container Initiative (OCI)

La Open Container Initiative (OCI) fue creada en 2015 por Docker, Inc., CoreOs y otras empresas, con el objetivo de diseñar estándares abiertos para que las tecnologías de contenedores no estuviesen vinculadas a ninguna empresa ni proyecto específico.

En la actualidad, la OCI cuenta con tres especificaciones:

OCI Runtime Specification

En esta especificación, se describe cómo tiene que ser la configuración, el entorno de ejecución y el ciclo de vida de un contenedor.

OCI Image Format Specification

Esta especificación define cómo tiene que ser una imagen OCI, para que todas las herramientas que cumplan este estándar puedan hacer uso de ella.

Las imágenes OCI están formadas por un archivo de manifiesto, un índice (opcional) que apunta a otros archivos de manifiesto para diferentes arquitecturas, el conjunto de capas que forman el sistema de archivos de la imagen y un archivo de configuración.

OCI Distribution Specification

Esta especificación define una API para facilitar y estandarizar la distribución de imágenes OCI.


1.15.2. Cloud Native Computing Foundation (CNCF)

La Cloud Native Computing Foundation (CNCF) es una organización que fue creada en 2015, donde las grandes empresas de la industria tecnológica colaboran entre sí para impulsar el uso de las tecnologías abiertas en la nube mediante proyectos de código abierto que no están vinculados a un único proveedor. Esta organización forma parte de la Fundación Linux y actualmente cuenta con el apoyo de las principales empresas del sector.

Las tecnologías conocidas como «Cloud Native» hacen referencia a las tecnologías actuales, que permiten ejecutar aplicaciones escalables en entornos de nube pública, privada o híbrida. Algunos ejemplos de estas tecnologías son los contenedores, los microservicios, las mallas de servicios, la infraestructura inmutable y las API declarativas.

Los proyectos de la CNCF se clasifican según su nivel de madurez en:

Proyectos graduados.

Proyectos en incubación.

Proyectos en sandbox.

Entre los proyectos graduados, encontramos dos de los proyectos de los que hemos estado hablando en este capítulo:

containerd: se encuentra en la categoría de container runtime.

Kubernetes: se sitúa en la categoría de orquestación.


1.16. Alternativas a Docker

Docker no es la única tecnología de contenedores que existe en la actualidad. De hecho, existen varias alternativas, pero solo vamos a nombrar algunas de las más conocidas:

Podman

Se trata de un container engine desarrollado por Red Hat. A diferencia de Docker, Podman no utiliza ningún proceso daemon y no necesita privilegios de root. Solo está disponible para sistemas operativos Linux y es compatible con las especificaciones OCI.

cri-o

Es un container runtime de alto nivel para Kubernetes. Se trata de una implementación de la especificación Kubernetes CRI (Container Runtime Interface), que permite utilizar cualquier runtime compatible con la especificación OCI. Actualmente, tiene soporte para interaccionar con los runtimes de bajo nivel runc y Kata Containers.

LXD

Es un proyecto open source desarrollado por Canonical, pero también recibe contribuciones de otras empresas y desarrolladores individuales. Este container engine permite trabajar con contenedores LXC (Linux Containers).

rkt

Este proyecto fue desarrollado originalmente por CoreOS en 2014. Años más tarde, Red Hat adquirió CoreOS y donó el proyecto a la CNCF. En 2020, se suspendió su desarrollo.

CAPÍTULO 2
Instalación de Docker
2.1. Docker Engine Community

Cuando decimos que vamos a instalar Docker en una máquina, realmente queremos decir que vamos a instalar el componente Docker Engine. Y lo más probable es que nos estemos refiriendo a la versión de la comunidad o Docker Engine Community.

Actualmente, existen dos ediciones de Docker Engine:

Docker Engine Community Edition (CE)

Es la versión open source mantenida por la empresa Docker, Inc.

Docker Engine Enterprise Edition (EE) o Mirantis Container Runtime (MCR)

Es una versión empresarial para sistemas Linux y Windows Server. Es uno de los productos que adquirió la empresa Mirantis cuando compró la plataforma Docker Enterprise en noviembre de 2019. Su nombre original era Docker Engine Enterprise, pero ha sido renombrado a Mirantis Container Runtime (MCR).

En este capítulo, nos vamos a centrar en la instalación de la versión Docker Engine Community para los sistemas operativos Linux, Windows y macOS.

Para instalar la versión Docker Engine Community, utilizaremos los siguientes productos:

Docker Engine para Linux.

Docker Desktop para Windows.

Docker Desktop para macOS.

En los sistemas operativos Linux es posible instalar, de forma aislada, el componente Docker Engine, pero, en los sistemas Windows y macOS, necesitamos instalar la aplicación Docker Desktop que, además de Docker Engine, incluye otros componentes, como Docker CLI, Docker Compose, Docker Content Trust, Kubernetes y Credential Helper.

Docker Engine para Linux es de uso gratuito, mientras que Docker Desktop solo se puede utilizar de forma gratuita con la suscripción Docker Personal, que permite su utilización en pequeñas empresas, para uso personal, educación y proyectos open source sin fines comerciales. Si desea utilizar Docker Desktop con fines comerciales en una gran empresa, deberá contratar una suscripción Pro, Team o Business.

2.2. Instalación de Docker Engine en Linux

En el momento de escribir este libro, Docker Engine está disponible para las siguientes distribuciones Linux para arquitecturas de 32 y 64 bits.


64 bits 32 bits
x86_64 o amd64 ARM64 o AArch64 ARM
CentOS ✓ ✓
Debian ✓ ✓ ✓
Fedora ✓ ✓
Raspbian ✓ ✓
Ubuntu ✓ ✓ ✓

Tabla 2.1. Distribuciones Linux y arquitecturas donde está disponible Docker Engine.

En la página web oficial de Docker, encontramos todos los detalles del proceso de instalación para cada una de estas distribuciones Linux. En este capítulo, solo vamos a realizar la instalación de Docker Engine para Ubuntu:


2.2.1. Métodos de instalación en Ubuntu

Para instalar Docker Engine en un sistema operativo Ubuntu, podemos utilizar tres métodos diferentes:

Utilizar un script oficial disponible en la URL https://get.docker.com, que permite realizar la instalación de forma rápida y no interactiva. Esta opción puede ser útil en entornos de desarrollo y no se recomienda su uso en entornos de producción.

Realizar la instalación desde los repositorios oficiales de Docker. Esta es la opción más utilizada por los usuarios, por su facilidad de instalación y actualización. Es la opción recomendada.

Descargar el paquete .deb directamente desde la web oficial y realizar la instalación de forma manual. Tiene el inconveniente de que también habría que gestionar las actualizaciones de manera manual. Este método puede ser útil cuando sea necesario instalar Docker Engine en sistemas que no dispongan de una conexión a Internet.

2.2.2. Instalación en Ubuntu utilizando el script oficial

Esta es la forma más sencilla de instalar Docker Engine en un entorno de desarrollo. Solo tenemos que ejecutar el siguiente comando:


Lo que estamos haciendo con este comando es utilizar la herramienta curl para descargar un script de la URL https://get.docker.com y, una vez que se ha descargado, lo ejecutamos con el intérprete de comandos sh. Observe que es necesario ejecutarlo con privilegios de root.

El script se encarga de detectar la distribución y la versión de Linux desde la que estamos realizando la descarga. Instala todas las dependencias, recomendaciones y paquetes que necesite sin solicitar ninguna confirmación al usuario. Es una forma rápida y sencilla de instalar Docker Engine en un sistema operativo Linux, pero tenga en cuenta que no se recomienda su uso para entornos de producción.

Una vez que haya finalizado la instalación, es necesario realizar una serie de pasos que se describen más adelante, en el apartado 2.2.4.

2.2.3. Instalación en Ubuntu desde los repositorios oficiales de Docker

La opción que vamos a utilizar es la que nos recomiendan desde la página oficial: la de instalar Docker Engine haciendo uso de los repositorios oficiales. A continuación, vamos a describir los pasos necesarios para instalar Docker Engine en Ubuntu Server 20.04 LTS sobre una arquitectura de 64 bits de tipo x86_64/amd64.

Configuración del repositorio oficial de Docker

En primer lugar, actualizamos la lista de paquetes de nuestro sistema:


Una vez que hemos actualizado la lista de paquetes, instalamos los siguientes:

apt-transport-https: permite a la herramienta apt acceder y descargar paquetes de los repositorios utilizando el protocolo HTTPS.

ca-certificates: contiene los certificados de las autoridades más comunes de certificación.

curl: es una herramienta que posibilita transferir datos a través de una URL. Se puede utilizar para simular las peticiones de un usuario desde un navegador web, pero desde la línea de comandos.

gnupg: se trata de una herramienta para la comunicación y almacenamiento de datos de forma segura. Puede utilizarse para cifrar datos y crear firmas digitales.

lsb-release: constituye una herramienta que permite identificar la distribución Linux que se está utilizando.


Añadimos a nuestro sistema la clave GPG pública del repositorio oficial de Docker. Este paso es necesario para poder añadir un repositorio externo a nuestro sistema y verificar las firmas de los paquetes que descargamos de ese repositorio:


En el siguiente paso, vamos a añadir el repositorio oficial de Docker a la lista de repositorios de nuestro sistema. Para hacer esto, crearemos un archivo llamado docker.list dentro del directorio /etc/apt/sources.list.d. Y, dentro de este archivo, añadiremos los datos del repositorio oficial de Docker, para que podamos instalar sus paquetes con la utilidad apt.

Utilizaremos el comando lsb_release -cs, para obtener el nombre de la distribución que estamos utilizando y poder configurar el repositorio correctamente para esta distribución. Como este ejemplo lo estamos realizando con la versión 20.04 LTS de Ubuntu Server, el nombre de la distribución que obtendremos será focal. Tenga en cuenta que este nombre cambiará dependiendo de la versión que esté utilizando.

Otro detalle importante es que debemos indicar cuál es el canal de actualización que vamos a utilizar. Docker Engine tiene tres tipos de canales:

stable: en este canal, se encuentran las versiones definitivas disponibles para su uso. El software se encuentra en la etapa GA (General Availability) del ciclo de vida del lanzamiento del software.

test: en este canal, se hallan las versiones que están en una fase previa a la etapa GA (General Availability) y se encuentran preparadas para ser testeadas.

nightly: en este canal, se sitúan las versiones que todavía no han sido liberadas y están en fase de desarrollo. Dichas versiones se crean diariamente con el estado de la rama principal del repositorio.

En nuestra instalación, seleccionaremos el canal stable:


Después de la ejecución del comando anterior, el archivo docker.list tendrá el siguiente contenido:


En este caso, podemos ver cómo el repositorio se ha configurado para una arquitectura de tipo amd64, para la distribución focal de Ubuntu y el canal stable.

Instalación de Docker Engine

Una vez que hemos añadido el repositorio oficial de Docker, tenemos que volver a actualizar la lista de paquetes de nuestro sistema:


Ahora tenemos todo preparado para realizar la instalación de Docker Engine. Lo mínimo que necesitamos para tener instalado Docker Engine en una máquina Linux son estos dos paquetes:

docker-ce: contiene la versión Community de Docker Engine.

containerd.io: es el container runtime que usa Docker Engine.

De forma opcional, también podemos instalar el cliente oficial Docker CLI, que nos va a permitir interactuar con el servicio Docker daemon de Docker Engine:

docker-ce-cli: contiene la versión Community de Docker CLI.

Aunque lo más habitual es instalar el cliente y servicio Docker daemon en la misma máquina, tenga en cuenta que los puede tener en máquinas separadas.

En nuestro caso, vamos a instalar Docker CLI y Docker Engine en la misma máquina, que será la opción más común:


En la página web oficial de Docker, puede encontrar más detalles sobre cómo realizar la instalación de Docker Engine en Ubuntu:


Comprobación de la instalación

Vamos a comprobar que la instalación se ha realizado de forma correcta ejecutando un comando que nos muestra información del cliente y del servicio Docker daemon.

Observe que vamos a ejecutar el comando como superusuario escribiendo sudo antes del comando docker version. Ahora explicaremos por qué lo hacemos:


Al ejecutar este comando, obtendremos una salida similar a esta:


1. Indica la versión del cliente Docker CLI.

2. Indica la versión de la API de Docker Engine que utiliza el cliente.

3. Indica la versión de Go que está utilizando el cliente.

4. Indica los siete primeros caracteres del hash SHA del commit que se ha utilizado para hacer la release de esta versión del cliente.

5. Indica la fecha de la release de esta versión del cliente.

6. Indica el sistema operativo y la arquitectura donde se está ejecutando el cliente.

7. Indica el contexto que está activo y está siendo utilizado por el cliente. Un mismo cliente puede tener configurados diferentes contextos para administrar clusters Swarm, clusters Kubernetes o nodos independientes con Docker Engine.

8. Indica que el cliente tiene activadas las características experimentales que todavía se encuentran en fase de testing.

9. Indica la versión de Docker Engine.

10. Indica la versión de la API de Docker Engine que utiliza el servidor y cuál es la mínima versión con la que puede comunicarse.

11. Indica la versión de Go que está utilizando el servidor.

12. Indica los siete primeros caracteres del hash SHA del commit que se ha utilizado para hacer la release de esta versión del servidor.

13. Indica la fecha de la release de esta versión del servidor.

14. Indica el sistema operativo y la arquitectura donde se está ejecutando el servidor.

15. Indica que el servidor tiene desactivadas las características experimentales de Docker Engine.

16. Indica la versión de containerd y el hash SHA del commit que se está utilizando.

17. Indica la versión de runc y el hash SHA del commit que se está utilizando.

18. Indica la versión de docker-init y el hash SHA del commit que se está utilizando.

Si obtenemos una salida similar a la anterior, es que la instalación se ha realizado de forma correcta.

Ahora vamos a ejecutar el mismo comando, pero sin utilizar sudo:


Deberíamos obtener una salida similar a esta:


En este caso, solo hemos obtenido información del cliente y un mensaje de error que indica que no hemos podido conectar con el servicio Docker daemon.

Cuando el cliente y el servicio Docker daemon se ejecutan en la misma máquina, se comunican con un socket de tipo UNIX que está ubicado en /var/run/docker.sock.

Para poder hacer uso de este socket, el usuario necesita tener permisos de root o pertenecer al grupo de usuarios del sistema docker.

Para solucionar este problema, podemos ejecutar los comandos con sudo o añadir a nuestro usuario al grupo de usuarios docker, que es lo que vamos a explicar en la siguiente sección:


2.2.4. Pasos posteriores a la instalación en Linux

Una vez que hemos realizado la instalación de Docker Engine en Linux, la documentación oficial nos recomienda realizar dos pasos opcionales: la configuración del usuario con el que vamos a utilizar el cliente Docker CLI y habilitar el servicio de Docker, para que se inicie automáticamente al poner en funcionamiento el sistema.

Configuración del usuario

Si hemos instalado el cliente y el servicio Docker daemon en la misma máquina, van a utilizar por defecto un socket UNIX para comunicarse. Los únicos usuarios que pueden utilizar dicho socket son el usuario root y los usuarios que pertenecen al grupo docker.

Para evitar tener que escribir sudo cada vez que vayamos a ejecutar un comando del cliente, tenemos que añadir al usuario con el que vamos a trabajar al grupo docker.

Para añadir al usuario actual al grupo docker, vamos a utilizar el comando usermod:


En este ejemplo, estamos utilizando la variable de entorno $USER, que contiene el nombre del usuario actual que está ejecutando el comando. En lugar de utilizar la variable $USER, podemos indicar el nombre del usuario de forma explícita.

Para activar los cambios en los grupos sin tener que cerrar la sesión, podemos ejecutar el siguiente comando:


Configuración de Docker Engine para que se inicie automáticamente

El siguiente paso consiste en configurar los servicios de docker y containerd, para que se inicien automáticamente cuando se inicie el sistema.

En las distribuciones Debian y Ubuntu, estos servicios se configuran por defecto durante la instalación. Pero, para el resto de las distribuciones Linux, hay que configurarlo de forma manual. En estos casos, utilizaremos el comando systemctl:


2.3. Instalación de Docker Desktop en Windows 10

Docker Desktop para Windows es una aplicación que ofrece el entorno de desarrollo ideal para trabajar con contenedores Docker en Windows. Esta aplicación tiene soporte para ejecutar contenedores Linux y Windows. Más adelante, explicaremos qué diferencias existen entre ambos.

Además de la versión Community Edition (CE) de Docker Engine, también incluye otros componentes, como Docker CLI, Docker Compose, Docker Content Trust, Kubernetes y Credential Helper.

Docker Desktop para Windows 10 tiene soporte para dos tipos de backends:

Hyper-V.

WSL 2 (Windows Subsystem for Linux, version 2).

La opción recomendada es WSL 2 aunque, si queremos utilizar contenedores Windows, vamos a necesitar activar Hyper-V.

Hyper-V

Hyper-V es el hipervisor de Windows y Windows Server, que proporciona virtualización de hardware para ejecutar máquinas virtuales.

En Windows 10, solo está disponible para las versiones de 64 bits de las ediciones Pro, Enterprise y Education. No está disponible para la edición Home.

En mayo de 2020, se publicó la versión 2004 (Build 19041) de Windows 10 y fue, a partir de esta versión, cuando se añadió el soporte para múltiples hipervisores. Antes de esta versión, no era posible ejecutar las aplicaciones de virtualización de terceros, como VirtualBox y VMware, si el hipervisor Hyper-V estaba habilitado.

WSL 2

El subsistema de Windows para Linux (WSL) permite ejecutar un entorno GNU/Linux sobre un sistema operativo Windows sin tener que utilizar una máquina virtual tradicional, ni una configuración de arranque dual. Con WSL, podemos ejecutar comandos y aplicaciones Linux dentro del sistema operativo Windows.

Las principales mejoras que aporta la versión 2 de WSL frente a la versión 1 son que aumenta el rendimiento de las operaciones de entrada/salida del sistema de archivos y que utiliza su propio kernel de Linux completo, con total compatibilidad con las llamadas del sistema.

WSL 2 utiliza una máquina virtual muy ligera, que se administra y se ejecuta en segundo plano. Utiliza la arquitectura de Hyper-V, para habilitar su virtualización; por lo tanto, es necesario habilitar en las características de Windows el componente «Plataforma de máquina virtual».

WSL 2 está disponible para las versiones de Windows 10 Pro y Home.

2.3.1. Instalación de Docker Desktop utilizando WSL 2 como backend

En este apartado, vamos a explicar cómo realizar la instalación de Docker Desktop utilizando WSL 2 como backend, ya que es la opción más recomendada.

Requisitos mínimos del sistema

Vamos a necesitar una máquina que cumpla los siguientes requisitos:

Sistema operativo Windows 10 de 64 bits.

Las ediciones Home y Pro necesitan una versión igual o superior a la 2004 (Build 19041).

Las ediciones Enterprise y Education necesitan una versión igual o superior a la 1909 (Build 18363).

Es necesario tener habilitadas las siguientes características de Windows:

Subsistema de Windows para Linux.

Plataforma de máquina virtual.

Los requisitos hardware necesarios son los siguientes:

Procesador de 64 bits compatible con SLAT (Second Level Address Translation).

4 GB de memoria RAM.

Tener activado el soporte de virtualización de hardware a nivel de BIOS.

Haber instalado el paquete de actualización del kernel de Linux.

Instalación de WSL 2 en Windows 10

Antes de instalar Docker Desktop para Windows, es necesario descargar WSL. Existen dos opciones para realizar la instalación de WSL en Windows:

Instalación simplificada

Es posible realizar la instalación con un solo comando. Para poder realizar este tipo de instalación, necesitamos:

Ser miembros del programa Windows Insider.

Tener instalada una versión preview de Windows 10, con el Build 20262 o superior.

Ejecutar el comando wsl --install en la línea de comandos con privilegios de administrador.

Instalación manual

La instalación manual de WSL 2 requiere realizar los siguientes pasos:

Habilitar las características de Windows:

Subsistema de Windows para Linux.

Plataforma de máquina virtual.

Instalar el último paquete de actualización del kernel de Linux.

Configurar WSL 2 como la versión por defecto.

Puede encontrar una descripción más detallada del proceso de instalación de WSL en la web oficial de Microsoft:


Instalación de Docker Desktop en Windows 10

Una vez que hemos instalado WSL 2 en nuestro sistema, podemos realizar la instalación de Docker Desktop para Windows:

1. En primer lugar, tendremos que descargar y ejecutar el instalador de Docker Desktop para Windows, que está disponible desde la web oficial o desde Docker Hub.

2. El asistente de instalación nos preguntará si queremos instalar los componentes de Windows necesarios para WSL 2. Asegúrese de instalarlos.

3. Siga las instrucciones del asistente hasta finalizar el proceso de instalación.

4. Una vez que ha finalizado el proceso de instalación, Docker se inicia de forma automática y el icono de la ballena de Docker aparecerá en la barra de estado.

A continuación, se muestra una imagen del dashboard de la aplicación Docker Desktop, desde el que se pueden gestionar todos los contenedores, imágenes y volúmenes que hay en el equipo.


Figura 2.1. Dashboard de la aplicación Docker Desktop 4.0.1 para Windows.

Puede encontrar una descripción más detallada del proceso de instalación de Docker Desktop en la web oficial de Docker:


Si tiene algún problema durante la instalación de Docker Desktop, puede consultar la solución de los problemas más comunes en la web oficial:


Opciones de configuración de Docker Desktop

Para acceder a las opciones de configuración de Docker Desktop, hay que mostrar el menú contextual que aparece al pulsar el botón derecho sobre el icono de Docker de la barra de estado. Desde ahí, podemos seleccionar la opción «Settings».


Figura 2.2. Menú contextual que muestra la opción Settings, que permite configurar Docker Desktop.

Al hacer esto, nos aparecerá una ventana con las opciones de configuración de Docker Desktop, que están divididas en cinco grupos:

General.

Resources.

Docker Engine.

Experimental Features.

Kubernetes.

En una instalación básica, no es necesario modificar ninguna de las opciones de configuración. Si ha realizado la instalación de Docker Desktop utilizando WSL 2 como backend, asegúrese de que la opción «Use the WSL 2 based engine» aparece seleccionada en el apartado de configuración general.


Figura 2.3. Configuración general de la aplicación Docker Desktop 4.0.1 para Windows.

Contenedores Linux y contenedores Windows

Docker Desktop para Windows 10 nos permite trabajar con contenedores Linux y Windows. En el capítulo 1 de este libro, puede encontrar las principales diferencias que existen entre ellos.

En la instalación por defecto de Docker Desktop para Windows 10, están activados los contenedores Linux. Para trabajar con contenedores Windows, tenemos que mostrar el menú contextual que aparece al pulsar el botón derecho sobre el icono de Docker de la barra de estado. En este menú, aparecerá la opción «Switch to Windows containers».


Figura 2.4. Menú contextual que muestra la opción para seleccionar los contenedores Windows.

Para poder utilizar contenedores Windows en Windows 10, hay que tener activadas las características de Windows «Hyper-V» y «Contenedores».


Figura 2.5. Aquí se muestran las características de Windows «Hyper-V» y «Contenedores» activadas.

Comprobación de la instalación

En este apartado, vamos a mostrar qué información nos tendría que devolver el comando docker version, dependiendo del tipo de contenedores que hayamos elegido en Docker Desktop.

Contenedores Linux


1. Indica el sistema operativo y la arquitectura donde se está ejecutando el cliente. En ese caso, el cliente se ejecuta en el sistema operativo Windows en una arquitectura amd64.

2. Señala el sistema operativo y la arquitectura donde se está ejecutando el servicio Docker daemon. En este caso, se ejecuta en el sistema operativo Linux, en una arquitectura amd64.

Contenedores Windows



1. Indica el sistema operativo y la arquitectura donde se está ejecutando el cliente. En ese caso, el cliente se ejecuta en el sistema operativo Windows en una arquitectura amd64.

2. Señala el sistema operativo y la arquitectura donde se está ejecutando el servicio Docker daemon. En este caso, se ejecuta en el sistema operativo Windows en una arquitectura amd64.

2.4. Instalación de Docker Engine en Windows Server

En los sistemas operativos Windows Server, no vamos a poder instalar Docker Engine Community Edition (CE); solo podremos instalar la versión empresarial Mirantis Container Runtime (MCR). Además, esta versión solo dispone de soporte a partir de Windows Server 2019.

Mirantis nos proporciona un script para realizar la instalación de MCR de una forma muy sencilla. Solo tenemos que abrir una consola de PowerShell como administrador y ejecutar los siguientes comandos.

En primer lugar, descargamos el script install.ps1, de la web oficial de Mirantis:


Configuramos una directiva de ejecución de PowerShell para poder ejecutar el script que hemos descargado en la sesión actual. Este paso es opcional:


-ExecutionPolicy RemoteSigned. Esta directiva de ejecución requiere que los scripts que se han descargado de Internet estén firmados por una entidad de confianza.

-Scope Process. Este ámbito hace que la configuración elegida solo afecte a la sesión actual y los cambios se eliminen al cerrar la sesión de PowerShell.

-Force. Esta opción suprime todas las solicitudes de confirmación.

Ejecutamos el script de instalación:


Puede encontrar una descripción más detallada del proceso de instalación en la web oficial de Mirantis:


Comprobación de la instalación

Para comprobar que la instalación se ha realizado de forma correcta, podemos ejecutar el comando docker version, que nos muestra información del cliente y del servicio Docker daemon:


1. Indica que estamos utilizando el cliente de Mirantis Container Runtime.

2. Señala que estamos utilizando el servidor de Mirantis Container Runtime.

2.5. Instalación de Docker Desktop en macOS

Docker Desktop también está disponible para el sistema operativo macOS. En este caso, la aplicación solo tiene soporte para ejecutar contenedores Linux, que se ejecutan en una máquina virtual ligera. El componente encargado de ejecutar los contenedores es HyperKit, que es un hipervisor que hace uso del Hypervisor.framework de macOS.

A la hora de instalar Docker Desktop en el sistema operativo macOS, debemos tener en cuenta cuál es la arquitectura del procesador del equipo, ya que los equipos Mac pueden tener procesadores con chip de Intel (arquitectura amd64) o chip de Apple (arquitectura arm64).

Requisitos mínimos del sistema para un Mac con chip de Apple (arm64)

En este caso, el único requisito es que debe instalar Rosetta 2. Puede instalarlo ejecutando el siguiente comando desde la línea de comandos:


Requisitos mínimos del sistema para un Mac con chip de Intel (amd64)

Vamos a necesitar que el equipo cumpla los siguientes requisitos:

Sistema operativo macOS con la versión 10.14 o superior.

Al menos, debe tener 4 GB de memoria RAM.

Instalación de Docker Desktop en macOS

1. En primer lugar, tendremos que descargar y ejecutar el instalador de Docker Desktop para macOS, que está disponible desde la web oficial o desde Docker Hub. Tendrá que seleccionar el instalador que se corresponda con la arquitectura del procesador de su equipo.

2. Le aparecerá una ventana, donde tiene que arrastrar el icono de Docker a la carpeta de aplicaciones.


Figura 2.6. Este es el paso donde hay que copiar la aplicación Docker a la carpeta de aplicaciones.

3. Cuando finalice el proceso de copia de Docker Desktop a la carpeta de aplicaciones del sistema, tenemos que buscar la aplicación Docker y abrirla. Cuando la aplicación se inicie por primera vez, mostrará un tutorial de iniciación.

4. En la barra de menús de estado, aparecerá el icono de la ballena de Docker, que nos ayuda a conocer el estado del servicio y a realizar algunas operaciones, como acceder a la configuración o reiniciar el servicio.


Figura 2.7. Icono de Docker en la barra de menús de estado y menú contextual.

Puede encontrar una descripción más detallada del proceso de instalación de Docker Desktop para macOS en la web oficial de Docker:


Opciones de configuración de Docker Desktop

Para acceder a las opciones de configuración de Docker Desktop para macOS, hay que mostrar el menú contextual que aparece al pulsar sobre el icono de Docker de la barra de estado. En ese menú, tenemos que seleccionar la opción «Preferences».

Las opciones de configuración están clasificadas en cinco grupos:

General.

Resources.

Docker Engine.

Experimental Features.

Kubernetes.

En la instalación por defecto, la opción de iniciar Docker Desktop automáticamente al arrancar el sistema está desactivada. Si queremos activarla, tenemos que acceder a la configuración general y activar el checkbox de la opción «Start Docker Desktop when you log in».


Figura 2.8. Configuración general de la aplicación Docker Desktop 3.6.0 para macOS.

Comprobación de la instalación

Para comprobar que la instalación se ha realizado de forma correcta, podemos ejecutar el comando docker version que nos muestra información del cliente Docker y del servicio Docker daemon:



1. Indica el sistema operativo y la arquitectura donde se está ejecutando el cliente. En ese caso, aparece que el cliente se ejecuta en el sistema operativo Darwin, en una arquitectura amd64. Darwin es un sistema operativo basado en UNIX y es el componente principal de macOS.

2. Señala el sistema operativo y la arquitectura donde se está ejecutando el servicio Docker daemon. En este caso, se ejecuta en el sistema operativo Linux en una arquitectura amd64.

2.6. Play with Docker

Existe una forma muy sencilla de utilizar Docker sin tener que realizar el proceso de instalación en una máquina. Se trata del proyecto Play with Docker (PWD), un proyecto desarrollado por Marcos Lilljedhal y Jonathan Leibiusky, que cuenta con el apoyo de Docker, Inc.

Este proyecto permite ejecutar los comandos de Docker desde un navegador web. Al acceder a la web, nos aparecerá un terminal de Alpine Linux, donde es posible crear imágenes, contenedores e incluso un cluster de Docker Swarm. Es una buena opción para aquellos usuarios que quieran iniciarse en Docker y deseen experimentar un poco:


CAPÍTULO 3
Imágenes Docker
3.1. ¿Qué es una imagen Docker?

Las imágenes Docker son la base de los contenedores Docker. Un contenedor se crea a partir de una imagen; por lo tanto, podemos decir que las imágenes son como unas plantillas de solo lectura que utilizamos para crear contenedores. Al crear un contenedor, la imagen se convierte en el sistema de archivos raíz del contenedor.

Las imágenes no tienen estado y su contenido es inmutable. Están formadas por la unión de múltiples capas o layers, donde cada una contiene las diferencias que existen entre ella misma y la capa anterior. La capa base es la primera capa que se utiliza para crear una imagen. A partir de la capa base, se van aplicando todos los cambios que contienen cada una de las capas. La unión de todas las capas forma el sistema de archivos que utilizará el contenedor.

Las imágenes se pueden crear a partir de un archivo Dockerfile, o también se pueden crear a partir del estado de un contenedor con el comando docker commit. Las buenas prácticas recomiendan crear las imágenes a partir de archivos Dockerfile. Esto permite que cualquier usuario pueda conocer cómo se ha creado la imagen y cuál es su contenido.

Para compartir las imágenes con otros usuarios, se pueden publicar en un registry. El registry oficial de Docker es Docker Hub. Aunque también es posible utilizar otros servicios de registry, así como crear nuestro propio registry privado.

Las imágenes Docker cumplen la especificación del formato de imágenes desarrollado por la OCI (Open Container Initiative). Se trata de un estándar abierto cuyo objetivo es permitir la creación de herramientas que hagan uso de este formato de imágenes, para que las tecnologías de contenedores no se hallen vinculadas a una empresa ni a un proyecto específico.

3.2. ¿Qué es un repositorio de imágenes?

Un repositorio es un grupo de imágenes que están agrupadas bajo el mismo nombre. Para diferenciar las imágenes del mismo repositorio, se utilizan etiquetas o tags. A menudo, se suele confundir el nombre del repositorio con el nombre de la imagen, así que vamos a tratar de explicar la diferencia entre ambos con un ejemplo.

En Docker Hub, existe un repositorio oficial llamado mysql, que contiene imágenes con diferentes versiones del sistema gestor de bases de datos relacionales MySQL. Las imágenes que forman este repositorio están etiquetadas con versiones como 8.0, 5.7 o latest, entre otras.

En este ejemplo, el nombre del repositorio sería:

mysql

Mientras que los nombres de las imágenes serían:

mysql:latest

mysql:8.0

mysql:5.7


Figura 3.1. Ejemplo de un Registry con tres repositorios de imágenes.

Podemos establecer una clasificación de repositorios de imágenes en función del lugar donde están almacenados. Según este criterio, podemos diferenciar dos tipos de repositorios de imágenes:

Repositorios locales. Estos repositorios están almacenados de forma local en una máquina donde se ha instalado el componente Docker Engine o Docker Desktop. Están formados por los repositorios de imágenes que se han creado de forma local en la máquina y por los repositorios que se han descargado de un servicio de registry.

Repositorios remotos. Son los repositorios de imágenes que están almacenados en un servicio de registry, como Docker Hub. Dentro de los repositorios remotos, podemos diferenciar entre repositorios públicos y privados.

Públicos. Son repositorios de imágenes que no tienen ninguna restricción de acceso y están disponibles a cualquier persona a nivel global.

Privados. Son repositorios de imágenes que solo están disponibles para los usuarios que los han creado, colaboradores o miembros de su organización.

3.3. ¿Qué es un tag?

Un tag es una etiqueta que se le asigna a una imagen dentro de un repositorio. Se utiliza para indicar la versión de una imagen y nos permite diferenciar, de una forma sencilla, las imágenes que forman parte de un repositorio.

En el momento de escribir este libro, podemos encontrar las siguientes etiquetas dentro del repositorio ubuntu de Docker Hub:

21.10, impish, devel

21.04, hirsute, rolling

20.10, groovy

20.04, focal, latest

El nombre de la imagen está formado por el nombre del repositorio y la etiqueta de la imagen, de modo que la imagen ubuntu:20.04 hace referencia a la imagen que está etiquetada con el tag 20.04 dentro del repositorio ubuntu.

La etiqueta latest es una etiqueta especial utilizada para indicar cuál será la imagen por defecto que se va a descargar del repositorio cuando no se indique una etiqueta de forma explícita en el comando docker pull o docker run.

Una imagen puede tener varias etiquetas; por lo tanto, en el ejemplo del repositorio ubuntu de Docker Hub, la imagen ubuntu:20.04, ubuntu:focal y ubuntu:latest hacen referencia a la misma imagen.

Otra de las etiquetas que podemos encontrar entre las imágenes de un repositorio es la etiqueta slim. Esta etiqueta se utiliza para indicar que la imagen contiene los mínimos paquetes necesarios para poder ejecutar la aplicación que contiene. Las imágenes con la etiqueta slim suelen ser más ligeras que el resto.

Ejemplo de una imagen con varias etiquetas

En este ejemplo, vamos a demostrar que una imagen puede tener varias etiquetas. Para ello, vamos a descargar, con el comando docker pull, las imágenes del repositorio ubuntu de Docker Hub que están etiquetadas como latest, 20.04 y focal:


Ejecutamos el comando docker images para obtener un listado de todas las imágenes que tenemos descargadas en la máquina donde estamos ejecutando Docker:


Observe cómo las imágenes que están etiquetadas con las versiones 20.04, focal y latest comparten el mismo identificador de imagen (c29284518f49). Esto quiere decir que, realmente, solo tenemos una imagen que está etiquetada con tres tags diferentes.

3.4. ¿Qué es el digest de una imagen?

Un digest es un identificador inmutable de una imagen. Es un hash de 64 caracteres que se obtiene al aplicar el algoritmo criptográfico SHA256 sobre el contenido del archivo de manifiesto de la imagen. El archivo de manifiesto se crea de forma automática cuando la imagen se publica en un Docker Registry de tipo v2 o se puede crear de manera explícita, con el comando docker manifest.

Una imagen puede tener múltiples tags, pero solo puede tener un digest. Una de las ventajas que nos aporta el uso del digest es que permite identificar una imagen de forma permanente. Un digest siempre hará referencia a la misma imagen, mientras que un tag puede hacer referencia a diferentes imágenes a lo largo del tiempo.

Imagine que la imagen ubuntu:21.04 recibe actualizaciones de seguridad de forma periódica y, cada cierto tiempo, se crea una nueva imagen con ese mismo tag. Después de aplicar las actualizaciones, el contenido de la imagen va cambiando y su digest será totalmente diferente; sin embargo, el tag sigue siendo el mismo.

Cuando descargamos una imagen de Docker Hub, se muestra el digest de la imagen; por ejemplo, vamos a descargar la imagen ubuntu:21.04 para obtener su digest:


1. Este hash es el digest de la imagen ubuntu:21.04.

El digest completo de la imagen ubuntu:21.04 es el siguiente:


3.5. ¿Qué es el namespace de un repositorio?

Un namespace o espacio de nombres permite agrupar un conjunto de repositorios de imágenes bajo el mismo nombre. Se pueden utilizar para organizar los repositorios dentro de un registro de contenedores. Otra de las ventajas que ofrecen es que permiten que puedan existir repositorios con el mismo nombre en espacios de nombres diferentes.

La ruta completa que identifica de forma única un repositorio o una imagen dentro de un registro se compone de los siguientes elementos y en el mismo orden en el que aparecen a continuación:


Observe que el namespace siempre aparece entre el nombre del registro y el repositorio. El puerto que utiliza el registro, el tag y el digest son opcionales. Cuando no se indica ni el tag ni el digest, estamos haciendo referencia a un repositorio de imágenes y, cuando se incluye alguno de los dos, estamos haciendo referencia a una imagen específica dentro de un repositorio.

Namespaces utilizados en Docker Hub

En Docker Hub, existen tres tipos de repositorios de imágenes y cada uno de ellos utiliza un namespace diferente:

Los repositorios de imágenes oficiales utilizan el namespace library:


Ejemplos:

docker.io/library/httpd

docker.io/library/python store, seguido del nombre de la organización:

Los repositorios de imágenes de organizaciones verificadas utilizan el namespace store, seguido del nombre de la organización:


Ejemplos:

docker.io/store/oracle/mysql-enterprise-server

docker.io/store/elastic/heartbeat

Los repositorios de imágenes de la comunidad utilizan el nombre del usuario de Docker Hub:


Ejemplos:

docker.io/pihole/pihole

docker.io/jupyter/datascience-notebook

Namespaces anidados

Docker Hub no permite definir espacios de nombres anidados, pero algunos registros de contenedores sí. Los espacios de nombres anidados pueden ser útiles para organizar los equipos de desarrollo de una organización o para separar los entornos de desarrollo, pruebas y producción.

Suponga que, en su organización, existen dos equipos de desarrollo que van a utilizar el mismo registro de contenedores y ambos necesitan trabajar con sus propios repositorios de forma independiente. Si el registro que estamos utilizando permite definir espacios de nombres anidados, podemos crear un espacio para cada equipo dentro del espacio de la organización; por ejemplo, podríamos crear los siguientes espacios de nombres:

organization/team-a/

organization/team-b/

Si, en este mismo ejemplo, quisiéramos separar los entornos de desarrollo, pruebas y producción, podríamos crear un espacio de nombres para cada uno de ellos:

organization/dev/team-a/

organization/dev/team-b/

organization/staging/team-a/

organization/staging/team-b/

organization/prod/team-a/

organization/prod/team-b/


3.6. ¿Qué es un registry?

Un registry, o registro de contenedores, es un servicio que almacena repositorios de imágenes para facilitar su distribución.

Los usuarios pueden utilizar este servicio para descargar y publicar imágenes. Permite que los equipos de desarrollo puedan compartir sus imágenes de forma fácil y segura con otros desarrolladores del equipo. En los sistemas de integración y entrega continua (CI/CD), el registry es un componente indispensable dentro del flujo de trabajo.

Un registry utiliza una arquitectura cliente-servidor, donde una aplicación cliente se comunica con el registry a través de una API HTTP. Existe una especificación de la OCI que define cómo tiene que ser la API para facilitar y estandarizar la distribución de contenido a través de los servicios de registry. Esta especificación se conoce como OCI Distribution Specification.

Los registros de contenedores pueden ser públicos o privados:

Registros públicos. Estos registros están gestionados por un proveedor externo y están alojados en la infraestructura del proveedor. Es la solución ideal cuando buscamos una solución sencilla y lista para empezar a trabajar, sin tener que preocuparnos de ninguna configuración específica, ni de gestionar la infraestructura sobre la que se ejecuta.

Los registros públicos pueden ofrecer a sus usuarios repositorios públicos y privados.

El registro de contenedores oficial de Docker es Docker Hub, pero también existen otros registros públicos como:

Amazon Elastic Container Registry.

Azure Container Registry.

Google Cloud Container Registry.

Registros privados. Estos registros son gestionados por la propia organización que hará uso de ellos. Pueden estar alojados en la infraestructura física de la organización, lo que se conoce con el término on-premise, o también pueden estar alojados en la infraestructura cloud de un proveedor externo.

Un registro privado le proporciona a la organización un mayor control sobre el lugar donde se almacenan las imágenes, cómo acceder a ellas y cómo integrar el registro en sus flujos de trabajo.

Para crear nuestro propio registro privado, podemos utilizar el proyecto Harbor o un repositorio oficial de Docker Hub llamado registry.

Darmowy fragment się skończył.

Gatunki i tagi

Ograniczenie wiekowe:
0+
Objętość:
653 str. 656 ilustracji
ISBN:
9788426734488
Wydawca:
Właściciel praw:
Bookwire
Format pobierania:

Podobne książki