Crónicas de un informático

Crónicas de un informático es un blog enfocado a configurar nuevos servicios informáticos, informar de su utilidad y centrado en la Educación y la FP.


Introducción a docker para FP

Para la generación de este artículo me he basado en la documentación de la guía oficial que creo que puede ser de gran utilidad adaptándola para el alumnado de FP. Puede ser muy interesante tanto para DAW/DAM como para ASIR.

¿Qué es un contenedor?

Un contenedor es una unidad de software que empaquete código y todas las dependencias necesarias para que una aplicación pueda ejecutarse independientemente del entorno de computación en el que se encuentre.

Cuando hablamos de un contenedor de tipo Docker, nos referimos a un paquete ejecutable de software que incluye todo lo necesario para ejecutar una aplicación (el código, librerías, ajustes, herramientas del sistema…)

Las imágenes se convierten en contenedores cuando ejecutan el motor de Docker y son temporales.

Están disponibles tanto para Linux, Windows y Mac OS X y se ejecutarán de la misma forma independientemente de la infraestructura en la que se encuentren.

Los contenedores permiten aislar el software de la infraestructura en la que se ejecutan.

Los contenedores que se ejecutan sobre Docker se basan en un estándar, son ligeras (comparten el kernel del S.O. y no requieren un sistema operativo por aplicación y seguras (el aislamiento de un contenedor proporcionar capacidades de aislamiento muy fuertes).

Los podemos encontrar en cualquier parte…

Los contenedores se lanzaron en 2013 como open source.

El enfoque de Docker se centra en los desarrolladores y los administradores de sistemas separando las dependencias de la aplicación de la infraestructura.

Ha sido un éxito en el mundo de Linux que desembocó en una asociación que trajo los contenedores de Docker y sus funcionalidades a Windows Server (Docker Windows Containers).

La tecnología disponible de Docker ha sido adaptada por los proveedores de la nube y muchos de ellos la proporcionas en formato IaaS o incluso CaaS.

Contenedores VS Máquinas virtuales

Contenedores:

  • Son una abstracción a nivel de aplicación que empaquetan todo el código y las dependencias necesarias.
  • Se ejecutan en la misma máquina y comparten el kernel del sistema operativo con otros contenedores, cada uno ejecutando un proceso aislado.
  • Ocupan menos espacio en disco que las máquinas virtuales.

Máquinas virtuales:

  • Permiten abstraer el hardware físico permitiendo convertir un servidor en múltiples servidores.
  • El hipervisor permite ejecutar múltiples máquinas virtuales en una única máquina.
  • Cada máquina virtual tiene su sistema operativo ocupando más espacio en disco.
Contenedores VS Máquinas Virtuales

Instalación de Docker en Ubuntu

Podemos seguir los siguientes pasos de la documentación: https://docs.docker.com/engine/install/ubuntu/

sudo apt-get install ca-certificates curl gnupg lsb-release

Añadiremos la clave GPG de Docker:

sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

Instalar el repositorio estable:

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Instalar Docker Engine:

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

Verificar que Docker está correctamente instalado:
sudo docker run hello-world

Verificación que el hello-world de docker ha funcionado

Conceptos básicos

sudo docker run -dp 80:80 docker/getting-started

-d ejecuta el contenedor en segundo plano
-p 80:80 mapea el puerto 80 del host al 80 del contenedor docker/getting-started la imagen a utilizar

Si lo ejecutáis, podréis iniciar un asistente al que accederéis vía web:

Dockerfile

Docker puede crear imágenes automáticamente leyendo las instrucciones de un fichero Dockerfile. Dicho fichero, contiene todos los comandos necesarios para crear la imagen. Con el comando docker build, podremos crear una imagen a partir del fichero dockerfile que generemos. Pongamos en práctica lo visto hasta ahora “apartado OUR APPLICATION del asistente”:

Desempaquetar el fichero zip.
Crear el fichero Dockerfile siguiendo las instrucciones del asistente
en la misma ubicación que el package.json:
Vamos a crear una imagen ejecutando el siguiente comando dentro de
la carpeta app donde hemos creado el Dockerfile:

Dockerfile de ejemplo

sudo docker build -t prueba .

Nota: termina con un punto.

Este comando creará un directorio app en el que se desplegará el contenido descargado en una máquina Linux de tipo Alpine. Descargará las dependencias necesarias con yarn y através del comando CMD se indicarán los comandos que se ejecutarán cuando se inicie el contenedor. Finalmente, arrancaremos un contenedor usando la imagen que hemos generando

sudo docker run -dp 3000:3000 prueba

Resultado de la ejecución del comando anterior

Componentes de un Dockerfile

FROM: “que sistema operativo queremos o que imagen vamos a usar”

RUN: “instrucciones que se pueden ejecutar en el terminal líneas de comando”

COPY: “copiar ficheros de nuestro sistema operativo a la imagen”

ENV: “Definir variables de entorno”

WORKDIR: “Directorios de trabajo donde nos ubicaremos en el contenedor”

EXPOSE: “exponer puertos distintos por defecto”

LABEL: “Definir etiquetas ej: versiones…”

USER: “Qué usuarios va a ejecutar la tarea”

VOLUME: “Volúmenes a emplear”

CMD: “Para tareas en background y mantiene vivo al contenedor. Ej: dejar apache en segundo plano o ejecutar un script”

Buenas prácticas con Dockerfile

Docker recomienda lo siguiente:

  • Un servicio por contenedor
  • Definir pocas capas “tratar de ejecutar los comandos en una única línea o Multi línea “\”
  • No instalar paquetes innecesarios
  • Emplear etiquetas “Labels”.

Comandos básicos

Listar imágenes:

docker images

Listar contenedores en ejecución:

docker ps

Cambiar nombre al contenedor:

docker rename id-contenedor nombre_nuevo

Reiniciar un contenedor:

docker restart id-contenedor

Acceder a un contenedor:

docker exec -ti nombre bash “para salir, ejecutamos el comando exit”

docker exec -u root -ti nombre bash “para entrar como root”

Nota: bash no tiene porque estar instalado en todas los contenedores, depende de la distribución de Linux del contenedor

Copiar ficheros desde nuestro S.O al contenedor:

docker cp “ruta fichero a copiar” id-contenedor :/rutaapegar

Copiar ficheros desde el contenedor al S.O

docker cp id-contenedor :/rutaacopiar “ruta s.o. a pegar”

Convertir un contenedor en una imagen “lo almacenado en los volúmenes no se va a guardar”

docker commit “idecontenedor” “nombredelanuevaimagen”

Modificar o eliminar un contenedor

Imaginemos que queremos modificar el contenido de la página de inicio del contenedor en ejecución. ¿Cómo podemos saber que contenedores tenemos en ejecución?

Si ejecutamos sudo docker ps, podremos visualizar los contenedores en ejecución:

Ejecución sudo docker ps

Es muy importante, que nos fijemos en el campo ID, ya que para detener un contenedor, lo necesitaremos:

sudo docker stop “ID”

Ahora, ya podremos eliminarlo:

sudo docker rm “id”

Nota: podremos detener y eliminar un contenedor ejecutando directamente docker rm -f “id”. Podemos ver los contenedores detenidos con el comando: sudo docker ps -a

Persistencia

Los cambios que se produzcan en el contenedor una vez arrancados, se perderán si se detiene el contenedor. Por lo tanto, por defecto, no tenemos persistencia.

Si nos interesa disponer de persistencia, deberemos de utilizar volúmenes. Los volúmenes permiten conectar rutas determinadas del contenedor al host en el que se ejecutan. Es decir, si montamos un directorio, los cambios se visualizarán en el host.

Los volúmenes nombrados: se crean con el comando “docker volume create nombre” Ejemplo:

sudo docker run -dp 3000:3000 –v datos:/etc/todos prueba

Nota: estamos mapeando al volumen datos la ruta “/etc/todos”. Se puede especificar directamente una ruta de nuestro equipo en vez de crear el volumen y luego asociar la ruta del contenedor “este volumen es de tipo host”

sudo docker run -dp 3000:3000 -v /home/user/Desktop/Docker/app/ruta:/etc/todos prueba

En cualquier momento, podemos obtener información de los volúmenes mediante la ejecución del comando siguiente:

sudo docker volume ls

También podremos obtener información adicional del mismo ejecutando el siguiente comando:

sudo docker inspect “nombre del volumen”

Inspección de un volumen.

A este respecto, destacar que un volumen puede ser compartido entre 1 o varios contenedores.

Redes

Docker crea por defecto una interfaz de red “docker” en la que crea una red en la cual estarán los contenedores que desplegaremos posteriormente. A los contenedores se le asignará una dirección IP de dicha red que es te tipo bridge.

Se pueden listar las redes que tenemos con: docker network ls

Para crear una red escribimos: docker network create “nombre de la red”

Para crear la red con mas datos:

docker network create “nombre de la red” -d “tipo de red” –subnet “dirección de red” –gateway “ip gw” “nombre de red”

Para inspeccionar una red:

docker network inspect “nombre de la red”

Asignar una dirección IP a un contenedor

docker run –network “nombre de la red” –ip “ip de la máquina” …

Existe un tipo de red basada en la red en la que se encuentra nuestro host “hereda todas las redes que tiene el anfitrión”

docker run –network host ..

Por otro lado, tenemos la red none para que los contenedores no tenga red

docker run –network none ..

Multicontenedores

Todos los casos que hemos visto hasta ahora están basado en arrancar un único contenedor. En la vida real, es muy común arrancar múltiples contenedores a la vez.

Por otra parte, recordaréis que los contenedores por defecto están aislados y no tienen visibilidad de procesos externos u otros contenedores. Por lo tanto, la forma en la que podemos hacer que se comuniquen dos contenedores es a través de la creación de redes.

Para crear una red, ejecutaremos el siguiente comando: docker network create “nombre de la red”.

Posteriormente, vamos a iniciar un contenedor de la siguiente forma:

docker run -d –network prueba –network-alias mysql -v todo-mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=secret -e MYSQL_DATABASE=todos mysql:8

Nota: estamos montando en un volumen llamado todo-mysql-data /var/lib/mysql que es donde se almacenan los datos de mysql. Por otro lado network-alias nos permite generar un puntero DNS que permita a otros contenedores acceder al mismo mediante dicho puntero.

Ahora podemos conectarnos a la bbdd de la instancia ejecutando lo siguiente:

docker exec -it “id del contenedor” mysql -p

Vamos a ejecutar otro contenedor que use la base de datos que hemos creado “parad el anterior prueba”:

sudo docker run -dp 3000:3000 -w /app -v “$(pwd):/app” –network prueba -e MYSQL_HOST=mysql -e MYSQL_USER=root -e MYSQL_PASSWORD=secret -e MYSQL_DB=todos node:18 sh -c “yarn install && yarn run dev”

Esas variables de entorno son soportadas por el contenedor en concreto. Nota: el comando es necesario ejecutarlo dentro de la carpeta app…

Accederemos vía web y añadiremos unos elementos. Ahora nos conectaremos a la base de datos y veremos si se han introducido los datos en cuestión:

docker exec -ti “id contenedor de la bbdd” mysql -p todos

Docker compose

Docker compose es una herramienta que nos permite definir y compartir aplicaciones multi-contenedores. Docker compose emplea ficheros con formato YAML.

El funcionamiento es muy sencillo, define las características de tus contenedores en el fichero y cualquiera puede utilizarlo para hacer uso de tu proyecto.

Para instalarlo en Ubuntu/Debian se ejecutará el siguiente comando:

sudo apt install docker-compose

Vamos a crear un fichero en la raíz de nuestro proyecto de antes denominado docker-compose.yml y vamos a introducir los datos en el mismo. Generalmente, un fichero de tipo docker-compose.yml se compone de los siguientes apartados:

version: “obligatorio” siempre la que recomienda docker.
services: “obligatorio” se definen los aspectos como el nombre, puerto, imagen y similares…
volumes: “opcional”
networks: “opcional”

Nota: para mas información de los distintos apartados acceder a docs.docker.com Parad de nuevo el frontal y la bbdd…

Ejemplo de docker compose

Finalmente, ejecutaremos nuestro programa de la siguiente forma (es necesario tener un fichero docker-compose.yml con el contenido de la diapositiva anterior):

sudo docker-compose up -d

Ejecución de docker compose up

Podemos ver los logs de la aplicación de la siguiente forma:

sudo docker-compose logs -f

sudo docker-compose down “para eliminar todos los servicios arrancados”

Nota: si usáis volúmenes, tendréis que borrarlos si hacéis cambios en el docker compose…

Docker hub

Podemos acceder a multitud de imágenes de contenedores en dockerhub https://hub.docker.com

Por ejemplo, podemos buscar wordpress y arrancar inmediatamente un contenedor de ese tipo:

Dockerhub búsqueda de imágenes

Posible ejercicio con el alumnado: buscad en la documentación como se arranca wordpress con docker-compose y generar el fichero correspondiente para arrancarlo en vuestras máquinas.

Solución:

Docker en Windows, Mac OS X, …

Para poder utilizar Docker en Windows nos descargaremos Docker Desktop desde la siguiente pagina: https://docs.docker.com/desktop/install/ubuntu/

La instalación os solicitará activar WSL 2 en Windows 10 y Windows 11

Notas finales

En ocasiones, será necesario borrar absolutamente todo lo generado por Docker. A tal efecto, habrá que ejecutar el siguiente comando:

docker system prune -a

Ejercicio 1

Generar un Dockerfile que tenga en cuenta las siguientes casuísticas:

  • Usar una plantilla de Debian.
  • Instalar Apache2.
  • Establecer el directorio por defecto en /var/www/html
  • Mover una página web que os descarguéis de Internet a dicho directorio.
  • Generar una variable de entorno que tenga como valor prueba y guardar su valor en un fichero prueba.html
  • El Puerto 80 debe de estar abierto.

Nota: la forma para dejar de fondo apache 2 es empleando el siguiente tag

CMD [“/usr/sbin/apache2ctl”,”-DFOREGROUND”]

Solución:

Ejercicio 2

Generar un volumen compartido por dos contenedores mapeados a la ruta /var/www/html de los dos contenedores:

  • Generar un index.html dentro de una ubicación en vuestro host.
  • Uno de los contenedores mapeará el Puerto 80 al 80.
  • El otro contenedor mapeará el Puerto 8080 al 80.
  • Verificar que se muestra un index.html correctamente almacenado en vuestro host.
  • Modificar el index.html y verificar que los dos contenedores están visualizando adecuadamente los datos.


Acerca de

Me llamo Iñigo Aramendi actualmente soy docente de formación profesional. Apasionado del mundo de las nuevas tecnologías, informática, ciberseguridad y la docencia. Siempre con ganas de seguir formándome y mejorando mis capacidades técnicas. Colegiado en el Colegio Oficial de Ingenieros en Informática.

suscríbete

Si quieres donarme uno o varios cafés…

1,00 €

Anuncios
A %d blogueros les gusta esto: