1. el_pichon,
¡Hola, habitantes de la sala!
Aunque este vuelve a ser el típico tutorial que sólo váis a aprovechar 4 gatos (no, los que tienen la palabra gato en el nick no), lo escribo por aquí, que siempre me extiendo a gusto y luego lo encuentro deprisa.
Vengo a cumplir lo prometido, pero vamos a ir despacio, haciendo altos por el camino, porque el paisaje es hermoso y hay que admirarlo y entenderlo para poder llegar al final. Si todo va bien, acabaremos con una instancia de Mastodon montada en Docker, utilizando Apache y Cloudflare. Hoy vamos a conocer Docker.
Requisitos
Estos requisitos se aplican a toda la serie de posts del hilo.
- Un servidor con Debian 11 o Ubuntu. Se recomienda que esté protegido, sólo con los puertos ssh, http y https abiertos.
- Acceso por SSH y conocimientos del manejo de la consola.
- Apertura de puertos con Iptables o ufw.
Introducción a Docker
Docker es una tecnología que nos permite desplegar aplicaciones y simular ciertas condiciones para que funcionen correctamente. Estas aplicaciones se ejecutan dentro de "contenedores". Un contenedor se queda a medio camino entre el equipo anfitrión y una máquina virtual:
- Engaña a la aplicación contenida.
- Simula redes que en el equipo anfitrión no están.
- Simula un sistema de archivos propio.
- Le da a la aplicación las versiones de las librerías que necesita, que a lo mejor no se corresponden con las del equipo anfitrión. Eso ofrece más garantías de que siempre funcionará igual, esté donde esté.
Sin embargo, un contenedor no se ejecuta sobre un núcleo separado. Una aplicación preparada para tal fin puede escalar y acceder al equipo anfitrión sin nuestro permiso.
Los contenedores tienden a ser efímeros: cuando terminan de ejecutarse, lo normal es destruirlos. Se crean a partir de imágenes, que podemos construir por nuestra cuenta o descargar de algún registro. El registro por defecto, si no configuramos ninguno, es el Docker Hub, y allí es donde suelen subirse las imágenes con las que vamos a trabajar. De hecho, si nos hacemos una cuenta, podemos subir nuestras propias imágenes.
Instalación de Docker
Una vez instalado, los comandos para interactuar con Docker son los mismos en cualquier plataforma, también en Windows. Ya que en todos los tutoriales de la sala hemos trabajado con Debian, vamos a usar Debian aquí también:
- Instalamos paquetes que nos permitirán agregar repositorios https:
apt update && apt install apt-transport-https ca-certificates curl gnupg lsb-release
- Agregamos la clave GPG del repositorio de Docker:
mkdir -m 0755 -p /etc/apt/keyrings && curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
- Agregamos el repositorio:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
- Instalamos el motor de Docker:
apt update && apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Se puede cambiar la palabra debian por ubuntu en la URL de los repositorios si queremos hacer la instalación en ese sistema.
En la consola, hemos encadenado dos comandos para que se ejecuten seguidos. Esto se hace con el operador &&, que no habíamos visto hasta ahora.
Nuestro primer contenedor: Fedora
Comprar un servidor VPS sólo para probar una nueva distribución de Linux cuesta dinero, y virtualizarla puede ser imposible cuando no hay accesibilidad. Antes de lanzarnos a cambiar de distribución, puede ser una buena idea hacer algunas pruebas y ver si entendemos sus comandos.
En primer lugar, vamos a bajarnos la imagen más reciente de Fedora: docker pull fedora:latest
En Docker, es habitual que la etiqueta latest apunte a la versión estable más reciente de la imagen deseada. De hecho, la palabra latest se asume si no indicamos otra etiqueta.
Una vez descargada, podemos verla con el siguiente comando: docker images
La imagen, además de su nombre, lleva un identificador asociado. Gracias a él, podremos eliminarla cuando ya no la queramos: docker rmi identificador
Pero es un poco pronto para eliminarla, teniendo en cuenta que no la hemos usado. Creemos un contenedor:docker run --rm -t -i fedora:latest /bin/bash
En este comando, hemos indicado que el contenedor será destruido al apagarse. Se acoplará una terminal para él, así como la entrada estándar de teclado, usará la imagen de Fedora con el tag latest, y dentro ejecutará el comando /bin/bash. El resultado es una consola dentro del contenedor. Podemos experimentar con ella, llamar a dnf update
para actualizar los paquetes, y salir con control+d o el comando exit. Al abandonarla, el contenedor será destruido.
Si queremos hacer un contenedor que no se destruya, el comando varía ligeramente:docker run --name micontenedor -t -i fedora:latest /bin/bash
En este caso, el contenedor guardará y recordará los cambios que hagamos en su interior. Al salir se detendrá, pero no se destruirá. Podremos volver a él con este comando:docker start -i -a micontenedor
Si queremos eliminarlo: docker rm micontenedor
Es muy importante eliminar todos los contenedores creados a partir de una imagen antes de eliminar la imagen. Se puede hacer al revés con el modificador --force
, pero puede tener efectos no deseados.
Segundo contenedor: un servidor de NVDA Remote
Tener la consola en pantalla es útil para experimentar, pero no es lo habitual. Lo ideal es que cada contenedor ofrezca sus servicios en segundo plano. Para ello, durante su creación, prescindiremos de los modificadores -t y -i.
El contenedor que vamos a crear ahora ofrece un servicio de red. Por defecto, Docker no abre los puertos del contenedor al exterior, sino que es algo que debemos pedirle nosotros. Para ello, usaremos el argumento -p, seguido del puerto exterior, y finalmente del interior. Sabemos que la imagen de NVDA Remote Server abre el puerto 6837. Sin embargo, desde la red del trabajo sólo nos dan libertad para acceder a los puertos 80 y 443, así que configuraremos el 443 como puerto de entrada. Con el argumento -d, además, le diremos al contenedor que se ejecute en segundo plano y nos devuelva el control de la consola en cuanto se inicie:docker run -d -p 443:6837 --name micontenedor jmdaweb/nvda-remote-server:latest
Como se puede observar, esta imagen no estaba descargada, pero se descarga en cuanto la solicitamos.
Ahora, con el comando docker ps
, podemos ver que el contenedor está activo. El comando docker logs micontenedor
mostrará por pantalla la salida de la aplicación. Y si con start iniciábamos, docker stop micontenedor
detendrá el contenedor indicado.
Con el contenedor activado, podremos conectarnos a un servidor de remote totalmente operativo en ipDelServidor:443.
Comunicación entre contenedores
Docker permite crear y gestionar redes. No profundizaremos demasiado en ello, ya que sólo necesitaremos unos conocimientos básicos.
El comando docker network --help
nos dará más información. Cuando conectamos varios contenedores a una misma red, estos pueden interactuar entre sí sin que sus puertos estén abiertos al exterior. Por ejemplo, si tenemos una arquitectura en la que PHP se ejecuta con Wordpress en un contenedor, Apache en otro y MySQL en otro, nos interesará que todos se conecten entre sí, pero sólo Apache aceptará conexiones entrantes del exterior. Al crear un contenedor con docker create o docker run, se puede especificar su red con el argumento --network
, seguido del nombre de la misma. Si escribimos --network host
, el contenedor se comportará como cualquier aplicación del equipo anfitrión, ofreciendo sus puertos sin ninguna clase de traducción de red. Por tanto, el modificador -p
dejaría de ser necesario.
Compartir archivos con volúmenes
Y si lo normal es destruir un contenedor al acabar de usarlo, ¿qué sucede con los datos que se generan en su interior? ¿De qué vale la base de datos que me he montado en MySQL? Cuando queremos preservar información, se emplean volúmenes. Dichos volúmenes pueden ser carpetas del sistema montadas en el contenedor, o almacenes gestionados por el propio Docker. Quizá la primera opción nos interese más, ya que así tendremos en todo momento los datos a mano. Hagamos un experimento sencillo con la imagen de Fedora que ya tenemos:
- Creamos una carpeta dentro de /root que actuará como volumen:
mkdir /root/contenedores-pruebas
- Arrancamos un nuevo contenedor con Fedora:
docker run --rm -v ./contenedores-pruebas:/root/contenedores-pruebas -t -i fedora:latest /bin/bash
- Desde la consola de Fedora, escribimos información en un fichero de texto dentro del volumen:
echo hola > /root/contenedores-pruebas/prueba.txt
- Salimos de la consola, lo que provoca la destrucción del contenedor. Sin embargo, en la carpeta asociada al volumen, permanece el archivo txt con lo que escribimos.
¡Importante! Para que Docker monte volúmenes a partir de carpetas existentes, se debe indicar la ruta absoluta. De lo contrario, pensará que se trata de un volumen administrado, y fallará si el volumen no existe.
Ejecución de comandos dentro de un contenedor
Normalmente, cada contenedor ejecuta un único proceso, pero viene equipado de tal forma que podemos ejecutar más. Si queremos modificar el fichero de configuración del servidor de NVDA Remote, debemos usar Nano dentro del contenedor. De hecho, se ha incluido a propósito en la imagen original para poder hacerlo. Mientras el contenedor está activado, podemos llamar al comando docker exec, indicando el nombre y el comando que se ejecutará. Por ejemplo:docker exec -t -i my_nvda_remote nano /etc/NVDARemoteServer.conf
Esto se aplicará más adelante en Mastodon para hacer copias de seguridad de la base de datos o gestionar aspectos de la instancia, por ejemplo.
Los ficheros docker-compose.yml
Cuando queremos desplegar un servicio que necesita usar varios contenedores, redes y volúmenes, poner en marcha cada elemento puede convertirse en una tarea repetitiva y no exenta de fallos. Docker-compose viene a solucionar el problema. Podemos crear un archivo docker-compose.yml con una serie de instrucciones en su interior que siguen un formato concreto en lenguaje Yaml, y esta herramienta se encargará de levantar o destruir el servicio a petición, creando y eliminando contenedores en el camino.
Tiempo atrás, docker-compose se distribuía como un ejecutable independiente. Había que prestar atención para actualizarlo cada vez que salía una nueva versión. Ahora, viene en forma de plugin de Docker, y ya lo hemos instalado al principio de este capítulo. El gestor de paquetes de nuestra distribución ayudará a mantenerlo al día junto con todo lo demás.
Para utilizar un archivo docker-compose.yml, navegamos al directorio donde se encuentra. A continuación, podemos ejecutar algunos de estos comandos:
docker compose up -d
: pone en marcha todos los servicios del archivo. Descarga imágenes si es necesario, y luego crea redes, volúmenes y contenedores.docker compose down
: apaga el servicio. Elimina redes, contenedores y volúmenes, pero no imágenes.docker compose run --rm servicio comando
: crea sólo un contenedor con el servicio indicado, cuyo nombre está en el archivo docker-compose.yml, y ejecuta en su interior el comando solicitado.docker compose pull
: actualiza todas las imágenes relacionadas con el servicio a sus versiones más recientes.
Archivo docker-compose.yml de ejemplo para Libre Translate
Libre Translate es un traductor gratuito, de código abierto y autoalojado. Con poco más de 20 GB libres, cualquier persona puede montarlo en su servidor con todos los modelos de idioma disponibles. A continuación hay un archivo docker-compose.yml que lo pone en marcha. ¿Alguien sabría dar más detalles del proceso leyendo sólo el contenido? ¿Va a funcionar así como está, o hay algo que se deba preparar antes en el equipo anfitrión?
version: "3"services:
libretranslate:
container_name: libretranslate
image: libretranslate/libretranslate:latest
restart: unless-stopped
command: --req-limit 30 --char-limit 5000 --api-keys --disable-files-translation --req-limit-storage redis://127.0.0.1:6379 --update-models
environment:
- LT_API_KEYS_DB_PATH=/app/db/api_keys.db
volumes:
- /root/libretranslate/api_keys:/app/db
- /mnt/resource/libretranslate:/home/libretranslate
network_mode: host
Después de esta introducción, lo dejamos por hoy. En el próximo capítulo, clonaremos el código fuente de Mastodon y haremos una serie de preparativos para ponerlo en marcha. Mientras tanto, dejo por aquí el enlace al Docker Hub para quien quiera descubrir imágenes distintas a las mencionadas en este mensaje y experimentar con ellas: https://hub.docker.com
¡Hasta la próxima!
Resultado: +1
Última edición por el_pichon, 13.03.2024 12:43:19