Tutoriales, noticias y soluciones informáticas

PiServer con Docker – Parte 2: ¿Qué es Docker? Ventajas, componentes, tipos de Dockers e instalación.

Hemos visto en nuestro último artículo cómo instalar la última version de Raspberry Pi OS en una Raspberry, de forma que quede lista para funcionar como servidor. A partir de ahora vamos a ver cómo instalar varios programas que harán que nuestra Raspberry se convierta en un magnífico servidor doméstico. Sin embargo vamos a instalarlos de una forma un poco especial. En lugar de instalar los programas directamente en el sistema operativo, vamos a usar Docker para meter cada uno en un contenedor separado para que…

Espera, espera. ¿Por qué te complicas tanto la vida? ¿Para qué me va a interesar hacer cosas raras con los programas que vamos a instalar si al final el objetivo es simplemente que funcionen? ¿No podemos simplemente instalarlos y ya está? Hay que ver cómo te gusta retorcer las cosas, majete.

Si no tuviera sentido no estaría aquí dando la chapa y estaría escribiendo sobre otra cosa, Usuario Anónimo. En realidad, sobre todo en servidores, tiene mucho sentido usar Docker en lugar de instalaciones directas de los programas. En este artículo vamos a ver, en primer lugar las ventajas de usar Docker respecto a hacer instalaciones directas para montar un servidor. Luego analizaremos qué tipos de Dockers son los más adecuados para su uso en pequeñas instalaciones y por último aprenderemos a instalar Docker tanto en una Raspberry como en un servidor Debian.

Vale... lo que quieras, pero ¿Qué demonios es eso de docker?

Tiene razón. Debería haber comenzado por ahí. Hazte la imagen mental de que Docker es como un conjunto de archivos empaquetados, sólo que con la característica de que tienen todo lo necesario para que funcione la aplicación que quieres usar (y cuando digo todo lo necesario me refiero a TODO. Archivos, dependencias, librerías, configuraciones, etc…). En lugar de hacer la instalación de la aplicación, haces la instalación de ese docker en concreto, y si lo has hecho correctamente, todo debería funcionar exactamente igual que haciendo la instalación de la forma «tradicional».

Que sí. Vale. Hurra por empaquetar todo, pero ¿Eso de qué me sirve? Si me estás diciendo que al final va a funcionar todo igual. Sigo preguntándome para qué te complicas tanto la vida. 

Te voy a poner varios ejemplos en los que vas a ver claro que instalar de esta forma las aplicaciones en un servidor tiene su utilidad.

1) Ventajas de usar Docker en un servidor.

Caso 1: Aplicaciones separadas que requieren versiones diferentes de componentes del sistema (Gestión de dependencias)

Imagina que, por ejemplo, quieres instalar en un único equipo dos aplicaciones que actúen como servidores independientes, por ejemplo, un servidor de Nextcloud y un servidor de OSTicket (podrían ser otro tipo de servicios. Esto sólo es un ejemplo). Puede que la configuración que requiera uno de estos servicios sea diametralmente opuesta a la que requiere el otro. Por ejemplo, puede que uno necesite un componente de linux superior a la versión 8, pero el otro sólo pueda trabajar con versiones inferiores a la 7. En este caso no podrían coexistir las dos instalaciones en el mismo sistema. Docker resuelve este problema, porque cada una de las instalaciones se convertiría en completamente independiente de la otra al estar empaquetadas en dos contenedores distintos. Cada una podría tener sus componentes y ser incompatibles los de un contenedor con el otro, pero funcionar de forma independiente. Cada contenedor sólo debe preocuparse en satisfacer las dependencias de sus componentes, sin preocuparse de las dependencias de otros contenedores que corran en el mismo sistema operativo base.

Caso 2: Paradas, cuelgues o reinicios controlados de una única aplicación.

Imagina ahora que tenemos de nuevo dos aplicaciones en el mismo hardware. Ambas usan el servidor Apache y hemos hecho cambios en una de ellas, pero hemos metido la pata hasta el fondo y ahora, por el motivo que sea, el servicio apache no arranca. Si hubiéramos hecho la instalación de las dos aplicaciones sobre el mismo servidor sin «empaquetarlas», ambas se verían afectadas por la incidencia y ninguna de las dos funcionaría. Con Docker, al correr cada una de forma independiente en dos servidores Apache independientes, lo que hagamos en una no interfiere nunca en lo que hagamos en la otra, por lo que nos podemos equivocar y estropear uno de los dockers pero el otro no se vería afectado en absoluto. Se habrá caído el primero y lo deberemos arreglar, pero el segundo ni se entera. Es más… podemos parar o reiniciar completamente uno de los Dockers y el otro simplemente seguiría funcionando sin preocuparse de lo que hubiera pasado fuera de su empaquetado. Al final, la única forma en la que un contenedor de Docker pueda afectar a otros es que esos contenedores compartan recursos (almacenamiento o tráfico de red). Por ejemplo, si un contenedor se pone a escribir datos en el disco sin parar y llena el disco, evidentemente puede poner todo el sistema en riesgo, pero supongo que entiendes que es un caso muy concreto y obvio.

Caso 3: Rollbacks controlados..

Ahora imagina que sólo tenemos una aplicación. Le hemos realizado una actualización pero descubrimos que esta nueva versión tiene un fallo crítico o no es compatible con ciertos componentes del sistema. En un entorno sin Docker, volver al estado anterior (rollback) puede llegar a ser complicado y arriesgado. A lo mejor tenemos que revertir cambios en todo el sistema y podríamos estar afectando a otras aplicaciones. Sin embargo, con Docker, podemos realizar rollbacks de manera controlada y aislada. Podemos volver a una versión anterior de la imagen de Docker de esa aplicación específica sin afectar otras partes del sistema. Esto nos daría tranquilidad a la hora de deshacer cambios (sabríamos que aunque tocáramos esa aplicación, el resto del sistema se mantendría estable).

Caso 4: Portabilidad

Si hemos desplegado nuestra aplicación en Docker, podremos llevarla junto con todas sus dependencias a cualquier otro equipo que tenga Docker instalado, ya sea en la nube o en un servidor local. Y esto en particular es algo que está muy bien. Por ejemplo, podemos probar nuestra aplicación en un entorno local y si vemos que funciona correctamente, luego podemos migrarla a entorno de producción o a una máquina en la nube sin tener que preocuparnos por configuraciones complicadas o diferencias en el sistema operativo principal de la máquina. Por ejemplo, podemos pasar una aplicación que ya está funcionando en un Debian a un Red Hat o viceversa. Y de nuevo… ¡¡Esto mola mucho!!

Caso 5: Escalabilidad

Esto es algo que viene derivado del caso 4. Imaginaos que tenemos una aplicación en producción (por ejemplo una página web). Funciona perfectamente, pero vemos que nuestra página ha tenido un éxito inusitado y cada vez entra más y más gente y nuestro servidor empieza a no ser suficiente para tramitar tantas peticiones. Las solicitudes de nuestros usuarios empiezan a ir más lentas e incluso se caen. La portabilidad de Docker nos permitirá migrar todo a un servidor más rápido de forma sencilla, otorgándole más recursos en un nuevo sistema.

Y para los más técnicos sólo una puntualización sobre este último punto: para escalar de forma eficiente hay más herramientas que facilitan esta labor y que no vamos a explicar en este artículo (como kubernetes). De momento no vamos a entrar en ellas.

Podría poner más ejemplos, pero creo que a grandes rasgos se entiende que en un servidor mola mucho tener las aplicaciones dockerizadas. Te da mucha libertad a la hora de cambiar la aplicación de servidor y el hecho de tener dependencias separadas puede resolver muchos problemas.

2) Componentes fundamentales de Docker.

A la hora de explicar cómo funciona Docker, debemos siempre tener presentes sus tres componentes fundamentales (imágenes, contenedores y volúmenes) y saber las diferencias entre los tres. De nuevo voy a intentar explicar qué es cada cosa de forma lo más didáctica posible (y de nuevo que me perdonen los más técnicos, pero mi objetivo es simplificar las explicaciones al máximo).

1) Imágenes.

Una imagen en Docker es como un paquete que contiene todo lo necesario para ejecutar un programa. Por poner una analogía: es como un archivo comprimido en el que está el código del programa, las dependencias que necesita para funcionar, y cualquier otra cosa que requiera para operar correctamente. Es algo similar a cuando nos descargamos un programa en Windows. La imagen sería ese instalador en el que está el programa (recuerda… todo esto es una analogía. No hay tal archivo comprimido ni tal instalador). Es algo que se usa para crear el contenedor, pero que no estará en ejecución cuando tengamos nuestro programa en marcha. Sólo se utiliza como base durante la instalación para crear y ejecutar el contenedor que nos interesa.

2) Contenedores

Es algo así como la imagen «descomprimida» y lista para ser usada (recuerda: no hay tal compresión. Lo explico así para que lo veáis claro). Si nos ponemos algo más técnicos es como una instancia en ejecución de un programa, creada a partir de una imagen. Podríamos decir que el contenedor es algo así como el programa ya instalado en el sistema. Contiene todos los elementos necesarios para que el software funcione correctamente, incluyendo el código del programa, las configuraciones y las herramientas. A diferencia de la imagen, el contenedor es la instancia en funcionamiento que se mantiene activa mientras el programa está en ejecución.

3) Volúmenes

El docker que tengamos instalado puede que genere datos (logs, datos en una base de datos, archivos de cualquier tipo, etc…). Esos datos que nos genera no van a ir dentro del contenedor (que lo tenemos aislado y no suele cambiar nunca), sinó que debemos definir dónde se almacenan. A ese almacén de datos que van por fuera del contenedor le llamamos volumen. Un ejemplo sería instalar un Docker que almacene imágenes que subamos a una web (se me viene a la cabeza PicSur). Esas imágenes que iremos subiendo no se van a almacenar dentro del contenedor, sino que se guardaran fuera del mismo. Pues bien… esa carpeta que dejamos fuera del contenedor, que contiene los datos que se van moviendo en el Docker y a la que podemos acceder a través del sistema de archivos de forma normal se llama volumen. Incluso podríamos decir que un volumen es un medio para persistir los datos más allá de la vida útil del contenedor

Es muy importante tener estos tres conceptos siempre claros, porque vamos a usarlos a partir de ahora contínuamente. Si instalamos un docker que hemos descargado de internet, comenzaremos por descargarnos la imagen y esta imagen creará un contenedor que es el que ejecutará el programa. Todos los datos que nos genere irán en volúmenes.

Vale. Imágenes, contenedores y volúmenes. Pero ¿Y la configuración de cada Docker? Supongo que irá dentro del contenedor de ese docker en concreto ¿No? ¿O la pongo dentro del volumen?

No. En Docker Compose la configuración del docker la solemos poner en un archivo de configuración a parte o en variables de entorno que se le pasan al contenedor cuando se inicia. Pero no vayas tan deprisa ni te agobies con esto. Lo de la configuración de cada Docker lo explicaremos más adelante. Ahora vamos a hablar de los diversos tipos de Dockers que existen.

¿Aún encima hay varios tipos de Dockers? Uffff... Está siendo un poco tedioso este artículo ¿No crees?

Sí. En este artículo vamos a ver mucha teoría, pero esto luego nos va a facilitar las cosas. Podremos llamar así a las cosas por su nombre y aplicar todo esto a cualquier otra información que hayáis encontrado por internet.

3) Tipos de Dockers (para un usuario medio)

La forma más habitual de clasificar los Dockers es mediante la solución que se ha empleado para orquestarlos. Hay muchas formas de orquestar contenedores, algunas más de «andar por casa» y otras más orientadas a empresas y a grandes instalaciones. En este artículo no nos vamos a parar a explicar éstas últimas (como Docker Swarm o Kubernetes), pero sí que hablaremos de las dos que se usan más habitualmente en instalaciones domésticas, que son Docker Cli y Docker Compose. Veamos con calma sus diferencias.

Docker CLI.

En el nombre, ese «CLI» significa «Command Line Interface». Es una forma de desplegar contenedores mediante una única línea de comando para ejecutar contenedores individuales. Os voy a dar un ejemplo, pero que nadie ponga esta línea en el terminal de su linux. Sólo voy a usar esto como ejemplo.

sudo docker run -d --name bitwarden -v /vw-data/:/data/ -e DOMAIN=https://vaultwarden.tudominio.com -e ADMIN_TOKEN=tutoken -e ROCKET_PORT=8181 -e WEBSOCKET_ENABLED=true -p 127.0.0.1:8181:8181 -p 127.0.0.1:3012:3012 --restart always vaultwarden/server:latest

Fijaos. Esta línea está diseñada para escribirla directamente en el terminal y cuando se ejecuta primero se descargará la imagen del docker que queremos instalar (En este caso se trata de VaultWarden, un gestor de contraseñas), luego con esa imagen se crea el contenedor correspondiente y también el volumen. Los parámetros de configuración fijaos que los pasamos directamente en la línea de comandos. No me voy a parar mucho en este método de desplegar Dockers porque no me apasiona especialmente. Por tanto no os voy a explicar cómo se usa ni para qué sirven los parámetros que he puesto en el ejemplo. Sin embargo sí considero conveniente que lo conozcáis (de hecho este método lo hemos usado alguna vez en este mismo Blog).

Docker Compose.

Esta opción es la que usaremos a partir de ahora y en los siguientes tutoriales. Bajo mi punto de vista tiene varias ventajas respecto a Docker CLI:

Por un lado, en lugar de ejecutarse a través de una línea de comando larga, se pone toda la configuración del Docker en un archivo con extensión ".yml" que está mucho más organizado y resulta mucho más sencillo de leer. En ese archivo pondremos la configuración de los volúmenes, las redes, las variables de entorno, los puertos expuestos, etc…

Además Docker Compose puede ejecutar múltiples contenedores al mismo tiempo. Se utiliza para orquestar múltiples contenedores como parte de una única aplicación (como por ejemplo, una instancia de Vikunja y a la vez su base de datos). Es especialmente útil para simplificar el despliegue y la gestión de aplicaciones complejas con varios servicios interconectados.

Muy bien. Ahora me lo explicas en cristiano, por favor. 

A ver… lo que quiero decir es que a veces hay aplicaciones que necesitan ejecutar varias cosas a la vez. Por ejemplo, hay páginas web que necesitan a la vez un servidor web (por ejemplo Apache) pero también necesitan una base de datos (por ejemplo MySQL). Docker compose nos permite ejecutar las dos cosas a la vez en el mismo docker, consiguiendo una conexión perfecta entre Apache y MySQL sin pérdida de rendimiento. Además, aunque el Docker sólo ejecute un único servicio, personalmente lo considero una forma más sencilla y visual para usar Docker que Docker Cli.

Y tal y cómo os he dicho antes, no me voy a liar con más métodos y herramientas. Simplemente por ahora sabed que existen más cosas además de Docker Cli y Docker Compose.

4) Instalación de Docker Compose

Como diría el Chino Cudeiro ¡¡Al turrón!! Vamos a instalar Docker Compose a nuestra Raspberry, pero ya que estamos os voy a indicar cómo se instala también en cualquier entorno basado en Debian (Ubuntu server, etc…).

Instalación de Docker Compose en una Raspberry.

El proceso es sumamente sencillo porque literalmente se puede hacer con tres comandos. Primero, tal y cómo os indiqué en el anterior tutorial, debéis entrar a vuestra Raspberry por SSH.

Una vez os hayáis logado, vamos a instalar el «Convenience Script«, que es un pequeño script que logrará automatizar el proceso de instalación. No os preocupéis, que no se trata de ninguna ñapa mía. Es un script creado por los desarrolladores de Docker y es muy útil para facilitar la instalación y no poner tantos comandos.

Pero antes de descargarlo y para ser un poco ordenados, vamos a crear una carpeta de descargas dentro de la carpeta del usuario de nuestra raspberry con este comando.

mkdir descargas

Una vez creada, entraremos dentro de la carpeta con este otro comando.

cd descargas

Ya estamos dentro de la carpeta. Ahora sí que vamos a descargar el script con este comando.

curl -fsSL https://get.docker.com -o get-docker.sh

Una vez descargado, lo ejecutamos con este otro comando.

sudo sh get-docker.sh

(Y sí… estamos haciendo una instalación, así que como necesitamos hacerla con privilegios administrativos ponemos delante el «Sudo» que significa «superuser do», o «hazlo como superusuario»).

Después de un ratito, este script nos habrá instalado docker, pero no docker compose, que habrá que instalarlo a parte. Pero nada que no se pueda arreglar con una única línea de comando. Ejecutamos lo siguiente:

sudo apt-get install docker-compose

Nos preguntará si estamos seguros de que vamos a hacer todos esos cambios. Pulsamos «Y» para decirle que sí y luego presionamos enter, y así nos quedará instalado Docker Compose en nuestra Raspberry, esperando a que montemos nuestro primer Docker.

¿Me estás diciendo que me estoy tragando un artículo inmenso para que me muestres tres míseros comandos? Tienes un problema serio para ir al grano ¿no?

Para nada. Por poder, puedo poner los tres comandos que te van a permitir instalar Docker en la Raspberry y luego una ristra de comandos para hacer una instalación de algún software mediante docker… pero si no se explica el funcionamiento no habría servido de nada. Simplemente demostraría que sabes copiar comandos de una página web y ponerlos en la Raspberry. La gracia de esto es entender cómo funciona, porque así luego verás que todo es mucho más sencillo de lo que parece.

Instalación de Docker Compose en Debian.

El «Convenience Script» no suele funcionar tan bien en estos sistemas (y además no se recomienda usarlo en máquinas que se van a usar «en producción» (es decir, para cosas serias) así que vamos a ver cómo se hace la instalación de docker en un servidor Debian. Ya os adelanto que son más comandos y más complicados, pero creo que está bien dar esta información en este artículo. Si lo que tenéis es una Raspberry, saltaos este punto, que no os servirá de nada. Y evidentemente en otro tipo de sistemas (RHEL y similares) los comandos no serán los mismos, pero no voy a ponerme a explicar como se instala en todos los sistemas, porque no es el objetivo del artículo.

Vamos a ello. Primero instalamos en nuestro Debian, desde los repositorios del sistema operativo, dos cosas:

  • ca-certificates: Un paquete que verifica la autenticidad de certificados durante conexiones seguras.
  • curl: una herramienta muy versátil para realizar descargas.

Instalamos ambas con este comando:

sudo apt-get install ca-certificates curl

Ahora creamos un directorio en /etc/apt/keyrings (os recuerdo que el directorio «/etc» en linux se usa principalmente para poner las configuraciones de los programas) y le damos unos permisos específicos. Lo hacemos con este comando.

sudo install -m 0755 -d /etc/apt/keyrings

Descargamos mediante «curl» el archivo «gpg» a la carpeta que acabamos de crear en el paso anterior y lo renombramos con el nombre «docker.asc»

sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc

Le decimos al sistema que ese archivo puede ser leído por todos los usuarios del sistema con este comando:

sudo chmod a+r /etc/apt/keyrings/docker.asc

Ahora vamos a agregar una fuente nueva a la lista de repositorios del sistema operativo (le dice al sistema operativo dónde poder descargar todo lo relativo a Docker). Ojo, que todo esto que os pongo es un único comando.

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Esto que viene ahora es sencillo. Como hemos agregado un elemento nuevo a los repositorios del sistema, los vamos a actualizar para que el sistema sepa qué cosas nuevas puede descargarse.

sudo apt-get update

Y por último descargamos todo lo relativo a Docker y Docker compose con este último comando.

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

…y con esto quedaría instalado docker en nuestro Debian.

Conclusiones

Estaba pensando en poner en este mismo artículo una lista de comandos para gestionar las imágenes, contenedores, volúmenes y logs que nos pueda crear nuestro Docker, pero estoy convencido de que llegados a este punto estaréis deseando montar vuestro primer docker, así que vamos a dejarlo de momento aquí. Si habéis seguido con atención el artículo, ahora ya conocéis los componentes fundamentales de cualquier docker, los tipos de docker que podéis encontrar para realizar pequeñas instalaciones y cómo instalar docker en vuestro equipo. En el siguiente artículo instalaremos Pi-Hole en nuestra Rasberry usando Docker Compose y en el que venga después sí que nos pararemos un rato para ver comandos interesantes para gestionar todos nuestros Dockers.

Sé que este artículo ha resultado muy teórico pero espero haber sido claro en la explicación y que no haya resultado demasiado pesado. ¿has tenido alguna duda en algún momento? ¿Quieres aportar algo más sobre este tema? Espero ansioso tus comentarios.

Share

4 comentarios

  1. Yepaswepas

    Más madera! Me quedo con las ganas

  2. Lacayo

    Gracias Marcos,
    Ya tenía ganas de un artículo dedicado completamente a Docker.
    Estoy acostumbrado a trabajar con máquinas virtuales pero Docker se me hace muy abstracto y Linux no ayuda mucho a la hora de fijar conceptos.
    Publicas cosas muy interesantes en este blog que copiamos como loros y no nos paramos a investigar su funcionamiento.
    La duda que se me plantea es ¿Cómo se actualiza el contenido del Docker?
    Está claro que apt-get update actualizará Docker pero, cuando se instale Pi-Hole en su interior, o bitwarden, o cualquiera de los programas que has ido publicando en tu blog, ¿Cómo lo actualizamos a su última versión o cómo podemos ver qué hay dentro de Docker?
    En una maquina virtual esta parte es transparente pero no veo cómo se puede hacer en Docker.

    • Lacayo

      Vaya,
      parece que la pregunta se soluciona sola en las siguientes entradas,
      Me puede el ansia :).

  3. Jacinto

    En qué se diferencia un docker de enlazar estáticamente cada aplicación, sin necesidad de dependencias a librerías ni versiones del s.o. ni otra variación?.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

© 2024 Flopy.es

Tema por Anders NorenArriba ↑

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.

ACEPTAR
Aviso de cookies