Trabajar con imágenes de Docker

DockerDockerBeginner
Practicar Ahora

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

En este laboratorio, exploraremos las imágenes de Docker, que son la base para crear y ejecutar contenedores. Aprenderemos cómo descargar imágenes de Docker Hub, ejecutar contenedores utilizando diferentes versiones de imágenes, enumerar y eliminar imágenes, comprender las capas de las imágenes, buscar imágenes y realizar etiquetado básico de imágenes. Esta experiencia práctica te proporcionará las habilidades esenciales para trabajar de manera efectiva con las imágenes de Docker. No te preocupes si eres nuevo en Docker; te guiaremos a través de cada paso con explicaciones detalladas.

Descargar imágenes de Docker Hub

Docker Hub es un repositorio público de imágenes de Docker, similar a GitHub para el código. Es donde puedes encontrar imágenes preconstruidas para muchas aplicaciones de software populares y sistemas operativos. Comencemos descargando (pulling) la imagen oficial de Nginx.

Abre una terminal en tu sistema. Deberías ver un indicador que se parezca a esto:

labex:project/ $

Ahora, descarguemos la imagen de Nginx. Escribe el siguiente comando y presiona Enter:

docker pull nginx

Este comando le dice a Docker que descargue la última versión de la imagen de Nginx desde Docker Hub. Deberías ver una salida similar a esta:

Using default tag: latest
latest: Pulling from library/nginx
5040bd298390: Pull complete
d7a91cdb22f0: Pull complete
9cac4850e5df: Pull complete
Digest: sha256:33ff28a2763feccc1e1071a97960b7fef714d6e17e2d0ff573b74825d0049303
Status: Downloaded newer image for nginx:latest

Analicemos lo que está sucediendo aquí:

  1. "Using default tag: latest" - Cuando no especificas una versión, Docker asume que quieres la última versión.
  2. Las siguientes líneas muestran cómo Docker descarga diferentes "capas" de la imagen. Cada capa representa un conjunto de cambios en el sistema de archivos.
  3. El "Digest" es un identificador único para esta versión exacta de la imagen.
  4. La última línea confirma que la imagen se ha descargado correctamente.

Ahora que hemos descargado la imagen, verifiquemos que esté en nuestro sistema. Podemos hacer esto listando todas las imágenes que Docker tiene localmente:

docker images

Deberías ver una salida similar a esta:

REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
nginx         latest    605c77e624dd   2 weeks ago    141MB

Esto nos dice:

  • REPOSITORY: El nombre de la imagen (nginx)
  • TAG: La versión de la imagen (latest)
  • IMAGE ID: Un identificador único para esta imagen
  • CREATED: Cuándo se creó esta versión de la imagen
  • SIZE: Cuánto espacio en disco ocupa la imagen

No te preocupes si los números exactos son diferentes; lo importante es que veas una entrada para nginx.

Si te preguntas qué otras imágenes hay en tu sistema, es posible que veas entradas para "jenkins/jenkins" y "gcr.io/k8s-minikube/kicbase". Estas son imágenes preinstaladas que no usaremos en este laboratorio.

Ejecutar diferentes versiones de una imagen

Docker te permite ejecutar versiones específicas de una imagen utilizando etiquetas (tags). Las etiquetas son como alias para versiones específicas de una imagen. Exploremos este concepto con la imagen de Python.

Primero, descarguemos la última imagen de Python:

docker pull python

Verás una salida similar a cuando descargamos la imagen de Nginx. Esto está descargando la última versión de Python.

Ahora, descarguemos una versión específica de Python, digamos la versión 3.7:

docker pull python:3.7

Observa cómo agregamos :3.7 después de python. Esto le dice a Docker que descargue específicamente la versión 3.7, en lugar de la última versión.

Listemos nuestras imágenes de Python para ver las diferentes versiones:

docker images python

Deberías ver una salida similar a esta:

REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
python       3.7       1f1a7b570fbd   2 weeks ago    907MB
python       latest    98ccd1643c71   2 weeks ago    920MB

Ahora tenemos dos imágenes de Python: una etiquetada como latest (que en realidad es Python 3.9 o 3.10, dependiendo de cuándo realices este laboratorio) y otra etiquetada como 3.7.

Ejecutemos contenedores utilizando estas diferentes versiones para ver la diferencia:

docker run --rm python:latest python --version

Este comando hace varias cosas:

  1. docker run crea e inicia un nuevo contenedor
  2. --rm le dice a Docker que elimine el contenedor después de que salga
  3. python:latest especifica qué imagen utilizar
  4. python --version es el comando a ejecutar dentro del contenedor

Deberías ver la última versión de Python en la salida.

Ahora hagamos lo mismo con Python 3.7:

docker run python:3.7 python --version

Esta vez, deberías ver Python 3.7.x en la salida, donde x es la última versión de parche de Python 3.7.

Estos comandos demuestran cómo puedes utilizar diferentes versiones del mismo software utilizando diferentes etiquetas de imagen. Esto es increíblemente útil cuando necesitas ejecutar aplicaciones que requieren versiones específicas de Python (o cualquier otro software).

Listar y eliminar imágenes

A medida que trabajes con Docker, irás acumulando imágenes con el tiempo. Es importante saber cómo administrar estas imágenes, incluyendo cómo listarlas y eliminar aquellas que ya no necesites.

Comencemos listando todas las imágenes en tu sistema:

docker images

Deberías ver una lista de todas las imágenes que has descargado hasta ahora, incluyendo Nginx y las imágenes de Python.

Ahora, digamos que queremos eliminar la imagen de Python 3.7 para liberar algo de espacio. Podemos hacer esto utilizando el comando docker rmi (rmi significa "remove image", eliminar imagen):

docker rmi python:3.7

Si este comando tiene éxito, verás una salida como esta:

Untagged: python:3.7
Untagged: python@sha256:1f93c63...
Deleted: sha256:1f1a7b57...
Deleted: sha256:8c75ecde...
...

Sin embargo, es posible que en su lugar veas un mensaje de error como este:

Error response from daemon: conflict: unable to remove repository reference "python:3.7" (must force) - container <container_id> is using its referenced image <image_id>

Este error se produce si hay un contenedor (en ejecución o detenido) que se creó a partir de esta imagen. Docker te impide eliminar imágenes que están en uso para mantener la integridad del sistema.

Para resolver esto, primero debemos eliminar cualquier contenedor que utilice esta imagen. Listemos todos los contenedores (incluyendo los detenidos):

docker ps -a

Busca cualquier contenedor que se haya creado a partir de la imagen python:3.7. Si encuentras alguno, elimínalo utilizando el comando docker rm:

docker rm <container_id>

Reemplaza <container_id> con el ID real del contenedor que deseas eliminar.

Ahora intenta eliminar la imagen nuevamente:

docker rmi python:3.7

Esta vez debería tener éxito.

Verifiquemos que la imagen se haya eliminado listando las imágenes de Python nuevamente:

docker images python

Ya no deberías ver la imagen de Python 3.7 en la lista.

Comprender las capas de las imágenes

Las imágenes de Docker se construyen utilizando un sistema de archivos en capas. Cada capa representa un conjunto de cambios en el sistema de archivos. Este enfoque en capas permite que Docker sea eficiente en el uso de almacenamiento y red. Exploremos este concepto.

Primero, inspeccionemos las capas de la imagen de Nginx que descargamos anteriormente:

docker inspect --format='{{.RootFS.Layers}}' nginx

Verás una salida similar a esta:

[sha256:2edcec3590a4ec7f40cf0743c15d78fb39d8326bc029073b41ef9727da6c851f sha256:e379e8aedd4d72bb4c529a4ca07a4e4d230b5a1d3f7a61bc80179e8f02421ad8 sha256:b5357ce95c68acd9c9672ec76e3b2a2ff3f8f62a2bcc1866b8811572f4d409af]

Cada una de estas cadenas largas (llamadas hashes SHA256) representa una capa en la imagen. Cada capa corresponde a un comando en el Dockerfile utilizado para construir la imagen.

Para entender mejor las capas, creemos una imagen personalizada simple. Primero, crea un nuevo archivo llamado Dockerfile en tu directorio actual:

nano Dockerfile

En este archivo, agrega el siguiente contenido:

FROM nginx
RUN echo "Hello from custom layer" > /usr/share/nginx/html/hello.html

Este Dockerfile hace dos cosas:

  1. Comienza con la imagen de Nginx que descargamos anteriormente (FROM nginx)
  2. Agrega un nuevo archivo a la imagen (RUN echo...)

Guarda y sale del archivo (en nano, puedes hacer esto presionando Ctrl+X, luego Y, luego Enter).

Ahora construyamos esta imagen:

docker build -t custom-nginx.

Salida de ejemplo:

Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM nginx
 ---> 5ef79149e0ec
Step 2/2 : RUN echo "Hello from custom layer" > /usr/share/nginx/html/hello.html
 ---> Running in 2fa43e649234
Removing intermediate container 2fa43e649234
 ---> 73b62663b5c3
Successfully built 73b62663b5c3
Successfully tagged custom-nginx:latest

Este comando construye una nueva imagen basada en nuestro Dockerfile y la etiqueta como custom-nginx. El . al final le dice a Docker que busque el Dockerfile en el directorio actual.

Ahora, inspeccionemos las capas de nuestra imagen personalizada:

docker inspect --format='{{.RootFS.Layers}}' custom-nginx

Notarás que esta imagen tiene una capa más que la imagen original de Nginx. Esta capa adicional representa los cambios realizados por nuestro comando RUN.

Comprender las capas es crucial porque:

  1. Las capas se almacenan en caché, lo que acelera la construcción de imágenes similares.
  2. Las capas se comparten entre imágenes, lo que ahorra espacio en disco.
  3. Cuando se envían o se descargan imágenes, solo se necesitan transferir las capas modificadas.

Buscar imágenes en Docker Hub

Docker Hub alberga una vasta colección de imágenes. Aunque puedes buscar imágenes en el sitio web de Docker Hub, Docker también proporciona una herramienta de línea de comandos para buscar imágenes directamente desde tu terminal.

Comencemos buscando imágenes de Nginx:

docker search nginx

Esto devolverá una lista de imágenes relacionadas con Nginx. La salida incluye varias columnas:

  • NAME: El nombre de la imagen
  • DESCRIPTION: Una breve descripción de la imagen
  • STARS: El número de estrellas que tiene la imagen en Docker Hub (lo que indica su popularidad)
  • OFFICIAL: Indica si esta es una imagen oficial mantenida por Docker
  • AUTOMATED: Indica si esta imagen se construye automáticamente a partir de un repositorio de GitHub

Por ejemplo, podrías ver algo como esto:

NAME                              DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
nginx                             Official build of Nginx.                        15763     [OK]
jwilder/nginx-proxy               Automated Nginx reverse proxy for docker c...   2088                 [OK]
...

La imagen oficial de Nginx suele estar en la parte superior de esta lista.

Ahora, intentemos buscar una versión específica de Python:

docker search python:3.8

Notarás que esta búsqueda no funciona exactamente como podrías esperar. La búsqueda de Docker no admite la búsqueda de etiquetas específicas (como 3.8). En su lugar, buscará imágenes con "python:3.8" en su nombre o descripción.

Para encontrar versiones específicas de una imagen, a menudo es mejor:

  1. Buscar el nombre general de la imagen (por ejemplo, docker search python)
  2. Visitar el sitio web de Docker Hub para obtener información más detallada
  3. Usar docker pull para descargar la imagen y luego inspeccionarla localmente

Recuerda, docker search es una forma rápida de encontrar imágenes, pero para obtener información más detallada, el sitio web de Docker Hub suele ser más útil.

Guardar y cargar imágenes

Docker te permite guardar imágenes como archivos tar y cargarlas más tarde. Esto es útil para transferir imágenes entre sistemas sin utilizar un registro (registry), o para hacer copias de seguridad de las imágenes.

Comencemos guardando la imagen de Nginx en un archivo:

docker save nginx > nginx.tar

Este comando guarda la imagen de Nginx en un archivo llamado nginx.tar en tu directorio actual. El símbolo > se utiliza para redirigir la salida del comando docker save a un archivo.

Puedes verificar que se haya creado el archivo listando el contenido de tu directorio actual:

ls -lh nginx.tar

Deberías ver el archivo nginx.tar en la lista, junto con su tamaño (que debería ser superior a 100MB).

Ahora, eliminemos la imagen de Nginx de nuestro sistema para simular la transferencia de la imagen a un sistema que no la tiene:

docker rmi nginx

Verifica que la imagen se haya eliminado:

docker images nginx

No deberías ver resultados, lo que indica que la imagen de Nginx se ha eliminado de tu sistema.

Ahora, carguemos la imagen de nuevo desde el archivo tar:

docker load < nginx.tar

El símbolo < se utiliza para redirigir el contenido del archivo nginx.tar como entrada al comando docker load.

Después de que se complete la carga, verifica que la imagen de Nginx esté de vuelta:

docker images nginx

Deberías ver la imagen de Nginx en la lista nuevamente, tal como estaba antes de eliminarla.

Este proceso de guardar y cargar imágenes puede ser muy útil cuando necesites:

  • Transferir imágenes a un sistema sin acceso a Internet
  • Hacer copias de seguridad de versiones específicas de imágenes
  • Compartir imágenes personalizadas con otros sin utilizar un registro (registry)

Conceptos básicos de etiquetado (tagging) de imágenes

El etiquetado (tagging) es una forma de crear alias para tus imágenes de Docker. Se utiliza comúnmente para el control de versiones y la organización de imágenes. Exploremos cómo etiquetar imágenes.

Primero, creemos una nueva etiqueta (tag) para nuestra imagen de Nginx:

docker tag nginx:latest my-nginx:v1

Este comando crea una nueva etiqueta my-nginx:v1 que apunta a la misma imagen que nginx:latest. Esto es lo que significa cada parte:

  • nginx:latest es la imagen y etiqueta de origen.
  • my-nginx es el nuevo nombre de imagen que estamos creando.
  • v1 es la nueva etiqueta que estamos asignando.

Ahora, lista tus imágenes para ver la nueva etiqueta:

docker images

Deberías ver tanto nginx:latest como my-nginx:v1 en la lista. Observa que tienen el mismo ID de imagen; esto se debe a que en realidad son la misma imagen, solo con nombres diferentes.

Puedes usar esta nueva etiqueta para ejecutar un contenedor:

docker run -d --name my-nginx-container my-nginx:v1

Este comando hace lo siguiente:

  • -d ejecuta el contenedor en modo desasociado (en segundo plano).
  • --name my-nginx-container le da un nombre a nuestro nuevo contenedor.
  • my-nginx:v1 es la imagen y etiqueta que estamos usando para crear el contenedor.

Verifica que el contenedor esté en ejecución:

docker ps

Deberías ver tu contenedor en la lista de contenedores en ejecución.

El etiquetado es útil por varias razones:

  1. Control de versiones: Puedes etiquetar imágenes con números de versión (v1, v2, etc.).
  2. Separación de entornos: Puedes etiquetar imágenes para diferentes entornos (desarrollo, preproducción, producción).
  3. Legibilidad: Las etiquetas personalizadas pueden hacer más clara la finalidad de una imagen.

Recuerda, las etiquetas son solo alias; no crean nuevas imágenes, solo crean nuevos nombres que apuntan a imágenes existentes.

Resumen

En este laboratorio, exploramos varios aspectos del trabajo con imágenes de Docker. Aprendimos cómo:

  1. Descargar imágenes de Docker Hub
  2. Ejecutar contenedores utilizando diferentes versiones de imágenes
  3. Listar y eliminar imágenes
  4. Comprender las capas de las imágenes
  5. Buscar imágenes en Docker Hub
  6. Guardar y cargar imágenes
  7. Realizar etiquetado básico de imágenes

Estas habilidades forman la base para gestionar eficazmente las imágenes de Docker en tus proyectos. A medida que continúes tu viaje con Docker, encontrarás que estas operaciones son esenciales para construir y desplegar aplicaciones en contenedores.

Recuerda, las imágenes de Docker son el núcleo de cómo funciona Docker. Proporcionan una forma consistente, portable y eficiente de empaquetar y distribuir aplicaciones. Al dominar estas operaciones de imágenes, estás en el camino correcto para convertirse en un experto en Docker.

Sigue practicando estos comandos y explorando diferentes imágenes. Cuanto más trabajes con Docker, más cómodo y competente te sentirás. ¡Que disfrutes trabajando con Docker!