Trabajando con Imágenes de Docker

DockerBeginner
Practicar Ahora

Introducción

En este laboratorio, exploraremos las imágenes de Docker, que son la base para crear y ejecutar contenedores. Aprenderemos a descargar imágenes desde Docker Hub, ejecutar contenedores utilizando diferentes versiones de una imagen, listar y eliminar imágenes, comprender las capas que las componen, buscar imágenes y realizar un etiquetado básico. Esta experiencia práctica le proporcionará las habilidades esenciales para trabajar con imágenes de Docker de manera efectiva. No se preocupe si es nuevo en Docker: le guiaremos en cada paso con explicaciones detalladas.

Descarga de Imágenes desde Docker Hub

Docker Hub es un repositorio público de imágenes de Docker, similar a lo que es GitHub para el código fuente. Es el lugar donde puede encontrar imágenes preconfiguradas para muchas aplicaciones de software y sistemas operativos populares. Comencemos descargando (haciendo un pull) la imagen oficial de Nginx.

Abra una terminal en su sistema. Debería ver un símbolo de sistema similar a este:

labex:project/ $

Ahora, descarguemos la imagen de Nginx. Escriba el siguiente comando y presione Enter:

docker pull nginx

Este comando le indica a Docker que descargue la versión más reciente de la imagen de Nginx desde Docker Hub. Debería 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 se especifica una versión, Docker asume que desea la versión más reciente.
  2. Las siguientes líneas muestran a Docker descargando 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 hacerlo listando todas las imágenes que Docker tiene localmente:

docker images

Debería ver una salida similar a esta:

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

Esto nos indica:

  • 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 se preocupe si los números exactos son diferentes; lo importante es que vea una entrada para nginx.

Si tiene curiosidad sobre qué otras imágenes hay en su sistema, es posible que vea entradas para "jenkins/jenkins" y "gcr.io/k8s-minikube/kicbase". Estas son imágenes preinstaladas que no utilizaremos en este laboratorio.

Ejecución de Diferentes Versiones de una Imagen

Docker le permite ejecutar versiones específicas de una imagen mediante el uso de etiquetas (tags). Las etiquetas funcionan como alias para versiones concretas de una imagen. Exploremos este concepto con la imagen de Python.

Primero, descarguemos la imagen más reciente de Python:

docker pull python

Verá 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, por ejemplo, la versión 3.7:

docker pull python:3.7

Observe cómo añadimos :3.7 después de python. Esto le indica a Docker que descargue específicamente la versión 3.7, en lugar de la más reciente.

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

docker images python

Debería 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 realice este laboratorio) y otra etiquetada como 3.7.

Ejecutemos contenedores usando estas diferentes versiones para ver la diferencia:

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

Este comando realiza varias acciones:

  1. docker run crea e inicia un nuevo contenedor.
  2. --rm le indica a Docker que elimine el contenedor automáticamente después de que termine su ejecución.
  3. python:latest especifica qué imagen utilizar.
  4. python --version es el comando que se ejecutará dentro del contenedor.

Debería ver la versión más reciente de Python en la salida.

Ahora hagamos lo mismo con Python 3.7:

docker run python:3.7 python --version

Esta vez, debería 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 puede utilizar diferentes versiones del mismo software mediante el uso de distintas etiquetas de imagen. Esto es increíblemente útil cuando necesita ejecutar aplicaciones que requieren versiones específicas de Python (o cualquier otro software).

Listado y Eliminación de Imágenes

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

Comencemos listando todas las imágenes en su sistema:

docker images

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

Ahora, supongamos que queremos eliminar la imagen de Python 3.7 para liberar espacio. Podemos hacerlo usando el comando docker rmi (rmi significa "remove image"):

docker rmi python:3.7

Si el comando tiene éxito, verá 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 vea 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 ocurre si hay un contenedor (en ejecución o detenido) que fue creado a partir de esta imagen. Docker impide la eliminación de imágenes que están en uso para mantener la integridad del sistema.

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

docker ps -a

Busque cualquier contenedor que haya sido creado a partir de la imagen python:3.7. Si encuentra alguno, elimínelo usando el comando docker rm:

docker rm <container_id>

Reemplace <container_id> con el ID real del contenedor que desea eliminar.

Ahora intente eliminar la imagen nuevamente:

docker rmi python:3.7

Esta vez debería funcionar correctamente.

Verifiquemos que la imagen ha sido eliminada listando las imágenes de Python otra vez:

docker images python

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

Comprendiendo las Capas de Imagen

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

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

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

Verá 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 sencilla. Primero, cree un nuevo archivo llamado Dockerfile en su directorio actual:

nano Dockerfile

En este archivo, añada 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 antes (FROM nginx).
  2. Añade un nuevo archivo a la imagen (RUN echo...).

Guarde y salga del archivo (en nano, puede hacerlo presionando Ctrl+X, luego Y y finalmente Enter).

Ahora construyamos esta imagen:

docker build -t custom-nginx .

Ejemplo de salida:

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 punto . al final le indica 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á 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, ahorrando espacio en disco.
  3. Al subir o bajar imágenes, solo es necesario transferir las capas que han cambiado.

Búsqueda de Imágenes en Docker Hub

Docker Hub alberga una vasta colección de imágenes. Aunque puede 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 su 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 (indica popularidad).
  • OFFICIAL: Si se trata de una imagen oficial mantenida por Docker.
  • AUTOMATED: Si esta imagen se construye automáticamente desde un repositorio de GitHub.

Por ejemplo, podría 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á que esta búsqueda no funciona exactamente como podría esperar. docker search no admite la búsqueda de etiquetas específicas (como 3.8). En su lugar, buscará imágenes que tengan "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 (ej. 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.

Recuerde que docker search es una forma rápida de encontrar imágenes, pero para obtener detalles precisos, el sitio web de Docker Hub suele ser más útil.

Guardado y Carga de Imágenes

Docker le permite guardar imágenes como archivos tar y cargarlas más tarde. Esto es útil para transferir imágenes entre sistemas sin usar un registro, o para realizar 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 su directorio actual. El símbolo > se utiliza para redirigir la salida del comando docker save hacia un archivo.

Puede verificar que el archivo se ha creado listando el contenido de su directorio actual:

ls -lh nginx.tar

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

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

Verifique que la imagen ha desaparecido:

docker images nginx

No debería ver resultados, lo que indica que la imagen de Nginx ha sido eliminada de su 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 para el comando docker load.

Una vez finalizada la carga, verifique que la imagen de Nginx ha vuelto:

docker images nginx

Debería 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 necesite:

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

Conceptos Básicos de Etiquetado de Imágenes

El etiquetado (tagging) es una forma de crear alias para sus 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 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. Aquí explicamos 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, liste sus imágenes para ver la nueva etiqueta:

docker images

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

Puede 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 desatendido (detached, en segundo plano).
  • --name my-nginx-container asigna un nombre a nuestro nuevo contenedor.
  • my-nginx:v1 es la imagen y etiqueta que estamos usando para crear el contenedor.

Verifique que el contenedor se está ejecutando:

docker ps

Debería ver su contenedor en la lista de contenedores en ejecución.

El etiquetado es útil por varias razones:

  1. Control de versiones: Puede etiquetar imágenes con números de versión (v1, v2, etc.).
  2. Separación de entornos: Puede etiquetar imágenes para diferentes entornos (dev, staging, prod).
  3. Legibilidad: Las etiquetas personalizadas pueden aclarar para qué sirve una imagen.

Recuerde que 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 a:

  1. Descargar imágenes desde Docker Hub.
  2. Ejecutar contenedores utilizando diferentes versiones de una imagen.
  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 un etiquetado básico de imágenes.

Estas habilidades constituyen la base para gestionar eficazmente las imágenes de Docker en sus proyectos. A medida que continúe su camino con Docker, encontrará que estas operaciones son esenciales para construir y desplegar aplicaciones en contenedores.

Recuerde que las imágenes de Docker están en el corazón del funcionamiento de Docker. Proporcionan una forma consistente, portátil y eficiente de empaquetar y distribuir aplicaciones. Al dominar estas operaciones con imágenes, está en el camino correcto para convertirse en un experto en Docker.

Siga practicando estos comandos y explorando diferentes imágenes. Cuanto más trabaje con Docker, más cómodo y competente se sentirá. ¡Feliz aprendizaje con Docker!