Docker para principiantes: ¡dile adiós a las pesadillas del despliegue!

Docker para principiantes: ¡dile adiós a las pesadillas del despliegue!

Los desarrolladores novatos a menudo enfrentan problemas como actualizaciones, lanzamientos y despliegues de código ineficientes, junto con desafíos para mantener la consistencia del entorno. El código que funciona sin problemas en el entorno de desarrollo puede encontrar errores en otra máquina. En la era de la computación en la nube, desplegar código con métodos tradicionales se siente anticuado. Esta publicación de blog te presentará Docker.

Docker, basado en el lenguaje Go y de código abierto bajo la licencia Apache 2.0, es un motor de contenedores de aplicaciones. Esta tecnología de contenerización permite a los desarrolladores empaquetar sus aplicaciones y dependencias en contenedores ligeros y portátiles. Estos contenedores pueden desplegarse en cualquier máquina Linux popular sin preocuparse por discrepancias en el entorno.

Docker vs. Máquinas Virtuales (VMs)

Como se mencionó, Docker utiliza virtualización. Al hablar de virtualización, las Máquinas Virtuales (VMs) inevitablemente entran en juego. Dado que ambas dependen de la virtualización, es natural preguntarse sobre sus diferencias. Analicemos eso.

En primer lugar, examinemos un diagrama típico de arquitectura de VM. Por encima de la infraestructura (que representa el hardware subyacente), hay un hipervisor. Actuando como intermediario entre el servidor físico y los sistemas operativos, permite que múltiples sistemas operativos y aplicaciones compartan el hardware subyacente. Las máquinas virtuales ejecutan múltiples sistemas operativos distintos sobre el sistema operativo anfitrión y utilizan el hipervisor para acceder al hardware subyacente.

Si necesitaras ejecutar tres aplicaciones aisladas, crearías tres máquinas virtuales. Esto significa que tres sistemas operativos se ejecutarían sobre el hipervisor, lo que resulta en una sobrecarga significativa de recursos.

un diagrama típico de arquitectura de VM

(Nota: El diagrama idealmente debería mostrar un Sistema Operativo Anfitrión encima del Hipervisor)

Docker, en contraste, es notablemente ligero. Su demonio (Docker Daemon) reemplaza al hipervisor, ejecutándose directamente sobre el sistema operativo. El código fuente de la aplicación y sus dependencias se empaquetan en una imagen de Docker. Luego, el motor de Docker utiliza esta imagen para crear un contenedor. Diferentes aplicaciones se ejecutan en contenedores aislados.

Además, el demonio de Docker se comunica directamente con el sistema operativo para asignar recursos a los contenedores Docker. Sin la sobrecarga de un sistema operativo completo, el tiempo de inicio del contenedor se reduce de minutos para las máquinas virtuales a meros milisegundos para los contenedores Docker, aumentando significativamente la eficiencia y ahorrando un espacio considerable en disco y otros recursos del sistema.

Aunque Docker ofrece ventajas convincentes, no es un reemplazo completo de las máquinas virtuales. Cada tecnología tiene sus fortalezas. Las máquinas virtuales destacan en aislar todo el entorno de ejecución, comúnmente utilizadas por los proveedores de nube para separar a los usuarios mediante VMs. Docker, por otro lado, típicamente aísla diferentes aplicaciones.

Cómo usar Docker

Instalación de Docker (Ejemplo CentOS 7)

  1. Instalar herramientas esenciales del sistema:
yum install -y yum-utils device-mapper-persistent-data lvm2 
  1. Actualizar el kernel del sistema y la caché de yum:
yum update
yum makecache fast
  1. Instalar Docker e iniciarlo:
yum -y install docker-ce
systemctl start docker 
  1. Probar si Docker se instaló correctamente:
docker run hello-world 

Si ves “Hello from Docker” en tu pantalla, ¡felicidades! La instalación está completa.

Conceptos

Antes de profundizar en Docker, repasemos algunos conceptos clave para un aprendizaje más fluido.

  1. Imágenes de Docker: Una imagen de Docker es una plantilla utilizada para crear contenedores Docker
  2. Contenedor de Docker: Docker crea contenedores a través de imágenes para ejecutar un conjunto de aplicaciones independientes
  3. Registro de Docker: Repositorio de código para guardar imágenes

Normalmente, descargamos la imagen adecuada de un registro de Docker y la usamos para crear contenedores para ejecutar nuestras aplicaciones.

Ejemplos

Conectemos estos conceptos a través de dos ejemplos comunes para ilustrar cómo usar Docker.

Instalar Python con Docker

Como se mencionó, el primer paso para usar un contenedor Docker es descargar la imagen correspondiente de un repositorio. Esto nos lleva al primer comando de nuestro tutorial:

  • Propósito: Buscar una imagen específica en el repositorio de imágenes.
  • Sintaxis: docker search [OPTIONS] TERM
  • Ejemplo: docker search python
  • Explicación: Buscar imágenes relacionadas con Python en el repositorio.
[root@novita ~]# docker search pythonINDEX       NAME                                       DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
docker.io   docker.io/python                           Python is an interpreted, interactive, obj...   4356      [OK]
docker.io   docker.io/django                           Django is a free web application framework...   856       [OK]
docker.io   docker.io/pypy                             PyPy is a fast, compliant alternative impl...   196       [OK]
docker.io   docker.io/kaggle/python                    Docker image for Python scripts run on Kaggle   125                  [OK]
docker.io   docker.io/arm32v7/python                   Python is an interpreted, interactive, obj...   38
docker.io   docker.io/centos/python-35-centos7         Platform for building and running Python 3...   36

Elegiremos la imagen oficial con la etiqueta (versión) 3.7.

docker pull

  • Propósito: Obtener o actualizar una imagen especificada desde el repositorio de imágenes.
  • Sintaxis: docker pull [OPTIONS] NAME:TAG
  • Ejemplo: docker pull python:3.7
  • Explicación: Descargar la imagen de Python con etiqueta 3.7 desde el repositorio.
[root@novita ~]# docker pull python:3.7
Trying to pull repository docker.io/library/python ...3.7: Pulling from docker.io/library/python
5ae19949497e: Downloading [=============>                                     ] 13.72 MB/50.38 MB
ed3d96a2798e: Download complete
f12136850781: Downloading [============================================>      ] 8.789 MB/9.978 MB
1a9ad5d5550b: Downloading [==>                                                ] 2.628 MB/51.77 MB
6f18049a0455: Waiting
ce39fa9d79d1: Waiting
Digest: sha256:d8718f4c8f28360c88d2d8b53681edb3c95e6a7bacedabd32eb5b1d120a75dc5
Status: Downloaded newer image for docker.io/python:3.7

Docker ahora ha descargado la imagen especificada. Para ver las imágenes Docker existentes:

docker images

  • Propósito: Listar imágenes locales.
  • Sintaxis: docker images [OPTIONS] [REPOSITORY[:TAG]]
  • Ejemplo: docker images
  • Explicación: Ver todas las imágenes Docker locales.
[root@novita ~]# docker images
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
docker.io/python        3.7                 42d620af35be        6 days ago          918 MB
docker.io/rabbitmq      3-management        7aae48fa6ef6        7 days ago          179 MB
docker.io/golang        latest              f50db16df5da        9 days ago          774 MB

La imagen de python3.7 está presente. Vamos a crear un contenedor usándola.

docker run

Antes de crear el contenedor, hablemos brevemente sobre los IDs. En Docker, los IDs identifican de manera única imágenes o contenedores. Interactuamos con ellos usando “comando + ID”. Por ejemplo, en el código anterior, el ID de la imagen de python3.7 es 42d620af35be.

  • Propósito: Crear un nuevo contenedor.
  • Sintaxis: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

Para probar el entorno de Python, creemos un archivo hello.py localmente:

#!/usr/bin/python 
import sys 

print("Hello, Docker!") 
print(sys.version)  # Output the Python version number 

Suponiendo que este código está guardado en /root/code/python:

[root@novita python]# docker run  -v $PWD:/usr/src/code  -w /usr/src/code python:3.7 python hello.py 
Hello, Docker! 
3.7.4 (default, Jul 13 2019, 14:04:11) [GCC 8.3.0] 

Analicemos este comando:

  • docker run: Crea un contenedor.
  • -v $PWD:/usr/src/code: Monta el directorio local en el contenedor Docker. Aquí, monta el directorio donde se ejecuta el comando en /usr/src/code dentro del contenedor. Los dos puntos separan la ruta local de la ruta del contenedor. Puedes usar rutas absolutas en lugar de $PWD.
  • -w /usr/src/code: Establece el directorio de trabajo para el contenedor. Dado que el directorio del código Python está montado en /usr/src/code, lo configuramos como directorio de trabajo.
  • python:3.7: Especifica la imagen. Puedes usar el ID de la imagen en su lugar.
  • python hello.py: Ejecuta este comando dentro del contenedor.

Ejercicio mental: Si tienes un archivo hello.go en /root/data/ y deseas ejecutarlo usando un contenedor Golang con ID de imagen f50db16df5da, ¿cuál sería el comando? (Pista: El comando para ejecutar código Go es go run FILENAME)

Instalar MariaDB con Docker

Suponiendo que ahora puedes buscar y descargar una imagen de MariaDB, enfoquémonos en iniciarla. Los servicios, como las bases de datos, requieren que los puertos correspondientes estén abiertos en el anfitrión. ¿Cómo logramos esto con Docker? Usaremos mapeo de puertos, similar al montaje de directorios.

[root@novita python]# docker run -d -v /data/mysql/:/var/lib/mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456  --restart unless-stopped 3a2ef06682ac 
  • -d: Ejecuta el contenedor en segundo plano.
  • -p 3306:3306: Mapea el puerto 3306 en el contenedor al puerto 3306 en el anfitrión.
  • -e MYSQL_ROOT_PASSWORD=123456: Establece la contraseña de root para MariaDB en 123456.
  • --restart unless-stopped: Reinicia el contenedor automáticamente si se detiene inesperadamente.
  • 3a2ef06682ac: El ID de la imagen para crear el contenedor.

Ahora, verifiquemos si el servicio de base de datos está funcionando:docker ps

  • Propósito: Listar contenedores.
  • Sintaxis: docker ps [OPTIONS]
[root@novita ~]# docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                                                                        NAMES
107b52416c13        3a2ef06682ac        "docker-entrypoint..."   5 minutes ago       Up 5 minutes        0.0.0.0:3306->3306/tcp                                                                       quizzical_mcnulty 

A continuación, accederemos al entorno interno del contenedor.docker exec

  • Propósito: Ejecutar un comando en un contenedor en ejecución.
  • Sintaxis: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
  • Ejemplo: docker exec -it 107b52416c13 bash
  • Explicación: Acceder al contenedor con ID 107b52416c13 y ejecutar el comando bash.

Dentro del contenedor, puedes interactuar con él como si fuera un entorno Linux normal. Usando las credenciales configuradas previamente, puedes acceder a MariaDB.

[root@novita ~]# docker exec -it 107b52416c13 bash 
root@107b52416c13:/# mysql -u root -p123456 
Welcome to the MariaDB monitor.  Commands end with ; or \g. 
Your MariaDB connection id is 11 
Server version: 10.4.6-MariaDB-1:10.4.6+maria~bionic mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. 
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. 
MariaDB [(none)]> 

Hasta ahora, has aprendido los conceptos básicos de Docker. Intenta explorar más.

Novita AI es la plataforma integral en la nube que impulsa tus ambiciones de IA. Con API integradas sin problemas, computación sin servidor y aceleración de GPU, proporcionamos las herramientas rentables que necesitas para construir y escalar rápidamente tu negocio impulsado por IA. Elimina los dolores de cabeza de infraestructura y comienza gratis: Novita AI hace realidad tus sueños de IA.