Docker en DAW
Uso de docker en DAW
Virtualización: introducción
Virtualización tradicional
Es una abstracción de la capa de hardware
Despliegues más sencillos
Ahorro costes
Aislamiento
...
Hypervisor
Hypervisor type 1
Nativo o Bare Metal Hypervisor
Corre directamente en el hardware de la máquina, hacen la función de HAL (Hardware Abstraction Layer)
Ej: VMWare ESXI, Microsoft Hyper-V, Citrix/Xen Server
Hypervisor type 2
Host OS Hypervisor.
Corre sobre el sistema operativo, como una aplicación más.
Ej: VMware Workstation, VMware Player, VirtualBox, Parallel Desktop (MAC), ¿KVM?
No es adecuado cuando hay un workload elevado: Active Directory, bbdd...
Adecuados para entornos de test
Más baratos
Instalación más sencilla
Contenedores
Son una abstracción de la capa de aplicación
Ventajas contenedores
Más ligeros
Portabilidad
Contrato entre el sysadmin y el developer
Despliegues más rápidos
Mas eficientes -> menor coste
Son efímeros
Desventajas
Menor seguridad y aislamiento
Depende del host
Snapshots
Migraciones en caliente (VMWare vMotion)
Son efímeros
Google Trends
Docker
Qué es Docker
Herramienta open-source que nos permite realizar una virtualización ligera, con la que poder empaquetar entornos y aplicaciones que posteriormente podremos desplegar en cualquier sistema que disponga de esta tecnología
Objetos de Docker
Los objetos principales en Docker son las imágenes, los contenedores y los servicios
Hay otros conceptos relacionados con ellos como volúmenes, registro de imágenes que los veremos conforme los necesitemos.
Imagen
Plantilla que define todas las dependencias de mi aplicación
Es habitual que las imágenes se creen en base a otras (herencia)
Ejemplo:
Contenedor
Instancia ejecutable de una imagen
Son efímeros, la persistencia se logra mediante el uso de volúmenes
Cada contenedor se ejecuta en un entorno aislado (podemos controlar el nivel de aislamiento):
variables de entorno
Volúmenes montados
Interfaces de red
Podemos crear una imagen a partir de un estado del contenedor.
Servicios
Los servicios permiten escalar contenedores a través de múltiples demonios de Docker, los cuales trabajarán conjuntamente como un enjambre (swarm).
Desarrollo en Docker
Un contenedor -> Un proceso
Mejor escalabilidad
Mejor reutilización
Actualizaciones
Docker en Linux (I)
En Linux Docker no es virtualizado, no hay un hipervisor.
Los procesos que corren dentro de un contenedor de docker se ejecutan con el mismo kernel que la máquina anfitrión.
Docker en Linux (II)
Linux aisla los procesos, ya sean los propios de la máquina anfitrión o procesos de otros contenedores.
Controla los recursos que se le asignan a contenedores pero sin la penalización de rendimiento de los sistemas virtualizados.
Docker en Windows
Actualmente docker puede usarse en Windows
De las múltiples maneras posibles, la mejor es Docker Desktop
Windows puede crear contenedores Windows o contenedores Linux, pero no simultaneamente. Debemos decirle si vamos a usar contenedores de un tipo u otro.
El uso de contendeores linux requiere instalar LSW, Linux Subsystem for Windows. Es decir, poner un kernel linux a disposición de docker.
Instalación
Dejo estas notas aunque no explicamos nada. Nosotros ya tenemos instalado docker.
Versiones de Docker
Hasta el 2019 había dos productos:
Docker Enterprise Edition
Docker Community Edition
La versión Enterprise la compró la empresa Mirantis
Nos centraremos en la versión libre, que es la única a la que hace referencia ahora la web de Docker
Tipos de instalación
Ir a la web de Docker
Se puede instalar el Docker Desktop en Windows
Se puede instalar el Docker Engine en Linux
Se puede desplegar una imagen mediante Vagrant que tenga todo
Se puede usar una OVA.
Instalación en Linux
Lo más usual es usar imágenes basadas en Linux https://docs.docker.com/engine/install/ubuntu/
El proceso habitual de instalación es:
Añadir el repositorio de docker
Instalar Docker Engine
Configurar usuarios para uso de docker (sin privilegios root). Ver Linux PostInstall
Instalar Docker Compose
Trabajar con Docker
Utilizaremos la terminal (cliente docker)
Utilizaremos Visual Studio Code
Terminal integrada
Extensión Docker
Debug dentro de contenedores
Comandos básicos
Contenedores
Ejecutar un contenedor nuevo:
docker run
docker container run
Iniciar un contenedor existente:
docker start
docker container start
Parar un contenedor:
docker stop
docker container stop
Borrar contenedor
docker rm
docker container rm
Inspeccionar contenedor
docker inspect
docker container inspect
Ejecutar comando en un contenedor:
docker exec
docker container exec
Ver logs:
docker logs
docker container logs
Imágenes
Ver listado de imágenes
docker images
Borrar una imágen
docker rmi
Descargar imágen:
docker pull
Publicar imágen:
docker push
Descargar imágenes
Traemos la última versión de la imagen de redis:
Listado de imáges locales
Aparecen datos útiles:
Órigen de la imágen
Versión
Tamaño que ocupa
Fecha de creación
Ejecución imágen (I)
Recordemos que una imagen en ejecución es un contenedor
CTRL + D para pararlo y podemos comprobar que ya no está
Ejecución imagen (II)
Mejor ejecutar en modo detached:
Si queremos arrancarlo de nuevo (no sabemos id)
Configuración de redes
Por defecto, no es necesario especificarlo. Los contenedores se comunican entre sí.
Son las más utilizadas
Déjemos que docker se encargue de todo :-)
Ejecutar comandos:
Debug de un contenedor
La forma más evidente es entrar a la terminal del contenedor:
Variables de entorno
Estructura ficheros
pocos comandos disponibles!
Ejercicio
Comprueba que efectivamente los contenedores se pueden comunicar entre sí.
Ejercicio - solución
Accede al fichero /etc/host de cada contenedor para ver su ip
Haz un ping entre contenedores
Logs de un contenedor
Los contenedores tienen un nombre aleatorio, pero se puede dar de forma explícita:
Ejercicio
Comprueba el estado de imágenes y contenedores de tu equipo
Elimina todas las imágenes
Elimina todos los contenedores (también los parados)
Solución
Estado actual:
Borrar imágenes:
Borrar contenedores:
Ejercicio
Descarga redis:latest y comprueba su versión
Descarga esa versión específica (redis:x.y.z)
Comprueba que tienes dos imágenes al hacer un listado pero que:
Ambas ocupan el mismo tamaño
Son idénticas:
Mismo IMAGE ID
No se ha producido ninguna descarga de layers adicionales.
Solución
Ejecutar contenedor latest y ver versión
Descargar versión actual y comprobar que ambas son idénticas
Versiones imágenes
No es aconsejable utilizar imágenes con etiqueta latest
Se pueden producir breaking changes
No está claro el versionado de la imágen.
Docker Hub
Registros de imágenes
Podemos crear una imagen de cero pero lo normal es usar o partir de una ya creada.
Hay un registro oficial de imágenes proporcionado por Docker: Docker Hub
También podemos crear nuestro propio servicio.
¿Qué es Docker hub?
Un repositorio de imágenes: descarga y publicación.
Repositorio de imágenes oficiales de Docker, de alta calidad.
Repositorio de imágenes verificadas publicadas por terceros.
¿Que más ofrece?
Gestor de equipos y organizaciones: acceso a repositorios privados.
Autobuilds: crea nuevas versiones de imágenes en base a cambios en repos de Github/Bitbucket
Webhooks: Ejecuta acciones después para integrar DockerHub con otros servicios
Limitaciones descargas
Desde final del 2020 Docker impuso limitaciones en el uso de su registro.
100 descargas de imágenes cada 6 horas para usuarios anónimos (por IP)
200 descargas de imágenes cada 6 horas para usuarios autenticados
Cuentas pro y team para aumentar los límites.
Conclusión: ¡¡¡Debemos hacer docker login!!!
Autenticación
Crear cuenta en Docker Hub
Hacer login desde consola
Se crea un fichero de configuración en $HOME/.docker/config.json
Las siguientes veces que nos autentiquemos, al hacer docker login leerá directamente el fichero
Observa que si cerramos la sesión la entrada auths del fichero config.json queda vacía
Workflows
Si queremos un repositorio compartido entre varios usuarios necesitamos crear una organización
Desde Junio 2021 los autobuilds son de pago
Si usamos GitHub podemos usar GitHub Actions
Nuestro propio registro
Docker viene configurado por defecto para buscar las imágenes de Docker Hub
Es posible usar nuestro propio registro:
Podemos usar la misma implementación vanilla del Docker registry que usa Docker Hub
Otros más avanzados como Harbor (Open Source, era VMWare), Artifactory (JFrog), Nexus (Sonatype), etc.
Otros registros
Docker también ofrece una versión enterprise de su registro llamada Docker Trusted Registry (DTR)
Google Container Registry (GCR), Amazon Elastic Container Registry (ECR), Azure Container Registry (ACR), Quay (Redhat, versión On-Prem y versión cloud), Gitlab Container Registry, Github Packages, etc.
Repositorios
Pueden ser públicos o privados (1 gratis)
Se crean desde Docker Hub
Cada repo puede tener una o varias imágenes, en función de la tag
Las imágenes se publican mediante el comando
Se pueden consultar mediante
docker search <keyword>
Lo más habitual es hacerlo vía web, no con consola
Prácticas DockerHub
Práctica 1
redis y redis-commander dockerizados
Evitamos problemas de dependencias
las máquinas host se quedan "limpias"
redis-comander
Paquete de npm para acceder a Redis desde el navegador
Instalación:
Debemos instalar nodejs, la versión de la distribución de Ubuntu es antigua (v10)
Instalamos usando el PPA oficial
Comunicación entre contenedores
Queremos que se comuniquen entre sí utilizando redes bridge:
default: las que utilizabamos hasta ahora
user defined:
Interacionan solo los contenedores definidos en esta red
Hay resolución de nombres
User defined vs default bridge
Buscar imagen en Docker Hub
Opciones
Construir nuestra propia imagen (todavía no sabemos)
Utilizar una imagen ya preparada en Docker Hub:
Menos propenso a errores
Más rápido
Modificar una imagen ya preparada:
¿Dockerfile? ¿FROM?
User defined network
Creación de red:
Uso de red:
Solución
Comprueba que efectivamente funciona (docker log)
Entra a uno de los dos contenedores y comprueba el ping por name
Práctica 2
Monta un escenario como el anterior con MySQL o MariaDB y phpMyAdmin
Práctica 3
Comprueba las versiones de imágenes de httpd
¿Vía web?
¿Vía docker search?
Práctica 3 - opciones
docker search no nos sirve
Vía web aunque es algo "laborioso"
Prueba y error con la versión que queremos
Usando hub tool
Práctica 4
Ejecuta una imagen 2.2 de Apache en DockerHub y modifica el index.html para que aparezca HolaMundo
¿Cómo has modificado el index.html?
Práctica 4 - opciones
Instalando en el contenedor un editor y entrando mediante:
Mediante el comando cp de Docker
Mediante el plugin Docker de Visual Studio Code (lo más sencillo)
Práctica 5
Imagina que hay un bug importante en Apache que está arreglado en la versión 2.4
Actualiza la versión de nuestra aplicación HolaMundo anterior a Apache2.4
Práctica 5 - opciones
Las dos opciones más adecuadas serían:
Generar una nueva imagen de nuestra aplicación
No sabemos hacerlo todavía
Realmente tampoco lo habíamos hecho, utilizabamos directamente la imagen de Apache
Buscar persistencia de algún modo en nuestro contenedor efímero.
Usámos volúmenes o bind-mounts
Volúmenes
Docker gestiona el volumen de forma transparente
Ejemplo con nginx:
Bind mounts
El volumen se mapea a un directorio físico acccesible no solo por Docker.
Si el directorio no existe, se crea.
Construcción imágenes en Docker (1)
Objetivos
Aprender a crear ficheros Dockerfile
Aprender a crear y publicar imágenes
Entender el concepto de layers en imágenes.
¿Qué es un dockerfile?
Plantilla en texto plano que define las dependencias de mi aplicación y la imagen.
Cada línea del fichero Dockerfile contiene una serie de comandos que generan una capa en la imágen
Se ejecutan de manera secuencial
Existe una caché que funciona por cada línea o capa.
Es habitual que las imágenes se creen en base a otras (herencia)
Concepto de capas
Una imágen es un conjunto de capas de solo lectura, generadas por el Dockerfile
¿Qué es un contenedor?
Una imagen en ejecución
Una imágen con una capa de lectura/escritura encima del resto de capas llamada container layer
Cualquier cambio que hagamos en un contenedor, se lleva a cabo en la container layer
Ejemplo
Vamos a crear una imagen que visualice el contenido de un fichero al ejecutar el contenedor
Crea un directorio y coloca un fichero holaMundo.txt con el texto ¡Hola Mundo!
Crea un fichero Dockerfile en el mismo directorio con el siguiente contenido:
Creamos la imagen y etiquetamos:
Ejecutamos la imagen:
Subimos la imagen con todas sus tags
Análisis Dockerfile
FROM nos sirve para partir de una imagen previa
RUN: ejecuta comandos
COPY: copia ficheros de nuestro contexto a la imagen
CMD: Ejecuta un comando al iniciar el contenedor
Más info en las referencias de Dockerfile
Explorar capas
Podemos ver las capas también mediante docker inspect y docker history
No todos los pasos generan una nueva capa, algunos comandos solo alteran configuración (CMD, ENV, ENTRYPOINT, EXPOSE, etc.).
La herramienta Dive nos sirve para explorar con más detalle las capas de las imágenes de Docker https://github.com/wagoodman/dive
Cache
Las líneas del Dockerfile en principio se cachean
Si se produce un MISS ya no se usa más caché en esa compilación
Escribir las líneas más "frecuentes primero"
Si hay líneas "con dependencias", ej apt-get update y apt-install juntas.
Si no queremos caché (ni para FROM image):
PRACTICAS IMÁGENES
PRACTICA 1
Crea una imagen que se base en Ubuntu y que permita:
Editar ficheros con vim
Ejecutar el comando ping
Solución
Observa el -y para evitar la parte interactiva del comando apt-get install
Comprueba con dive los recursos utilizados
Mejor solución
¿Qué falla aquí?
PRÁCTICA 2
Crea una imagen a partir de las instrucciones del ejercicio anterior (vim + ping) pero con el comando docker commit
Verifica la imagen (capas y tamaño)
PRÁCTICA 3
Vamos a crear una versión v2.0 de nuestro holaMundo, que en vez de coger el fichero de local lo coja de una URL mediante el comando ADD
Compila la imagen y ejecútala
Cambiaremos los datos del fichero apuntado por la URL
Compila de nuevo la imagen y ejecuta otra vez
¿Qué pasa? ¿Comó lo solucionas?
Construcción imágenes en Docker (2)
Almacenamiento
En docker, las imágenes se construyen a base de capas
Cada capa contiene únicamente las diferencias respecto a la capa padre.
Docker utiliza mecanismos de union filesystems para montar en una carpeta la combinación de las distintas capas.
Almacenamiento
Al crear un contenedor, Docker añade una capa adicional (la capa de contenedor), que es la única sobre la que es posible escribir.
El contenedor modifica aparentemente la imagen base, como si tuviera una copia real, pero únicamente está modificando esta última capa.
Podemos crear múltiples contenedores sobre una misma imagen, reutilizando todas las capas excepto la capa de contenedor.
Al destruir un contenedor, esta capa con las modificaciones se destruye.
Tamaño de las imágenes
Borrar un archivo en un paso del Dockerfile no elimina ese archivo de las capas anteriores de la imagen.
El archivo sigue presente, pero no es accesible desde el contenedor.
Es la forma de comportarse de los union filesystems
Build Context
Al hacer un build se envían al daemon docker los ficheros de la ruta especificada como contexto:
Es recomendable usar una carpeta separada para almacenar el contexto.
Podemos crear un fichero .dockerignore
Tipos de imágenes
Used: Las que aparecen al hacer un docker ps -a
Unused: Las que no aparecen (se usaron en su momento pero se ha borrado el contenedor)
Dangling images: Imágenes que se crean sin nombre, y se muestran como <none>.
Útil cuando estamos haciendo pruebas de compilación
Gestión de espacio
Conforme vamos usando docker, descargando imágenes... empezamos a ocupar espacio
Comprobar el espacio usado:
Eliminación de imágenes:
Multistage builds
Se crea la primera imagen que sirve para obtener lo que se usa en el segundo stage (ver --from=n)
Todo lo que no se usa queda fuera del último stage que es el definitivo
Útil para entorno de compilación
Se reduce el tamaño final de la imagen al quedarnos solo con el ejecutable
Ejemplo multistage
Docker Compose
Qué es Docker Compose
Herramienta para definir y ejecutar aplicaciones con varios contenedores Docker.
Se definen los contenedores (servicios) de la aplicación mediante un fichero YAML.
Se levantan mediante el comando
docker-compose up
Prueba de uso
Vamos a analizar un caso sencillo con 3 contenedores:
web server con php
db con MySQL
phpMyAdmin
Clona este repositorio
Docker-compose con Image
Óptimo para producción, más rápido que un build y todo empaquetado
Crea una imagen de Apache con un HolaMundo
Ejecútala mediante docker-compose.yml
Proxy inverso
Para dar un servicio externo, en web el puerto es el 80
¿Cómo hacemos para que los servicios anteriores funcionen todos en el 80?
Proxy inverso en función de la url
Similar a un virtual host de apache pero que se configura solo en función de las peticiones que le llegan al docker daemon
Usaremos nginx-proxy o traefik
Práctica ODOO
Seleccionar en DockerHub una imagen de Odoo
Desplegar la imagen con la bbdd adecuada como servicios (usando docker-compose.yml)
Práctica Dolibarr
Seleccionar en DockerHub una imagen de Dolilbarr
Desplegar la imagen con la bbdd adecuada como servicios (usando docker-compose.yml)
Práctica Wordpress
En la web de Docker hay ejemplos de Wordpress, Django o Rails
Mooodle
Problema de espera entre contenedores
Una buena forma es usar dockerize
Instalación:
crontab
¿Añadir un servicio de crontab a nuestro contenedor?
¡¡¡no!!! Filosofía docker: 1 contenedor = 1 servicio
Podemos crear un crontab en el host con comandos como:
Práctica copias de seguridad
Propongo uso de rsnapshot
rsync para hacer instantáneas con hard links
Interfaz gráfico para su gestión
Y para hacer deploy en Docker
¿Existe esto?
Monitorización
Visión general
Datos en docker
Ver uso contenedores
Procesos en ejecución
Consultas al demonio de docker
Consultas específicas por contenedor
Configuraciones intrínsecas a los servicios (por ej. mod_status en Apache)
Gestión de la memoria
El kernel si no tiene suficiente memoria arroja un OOME (Out of memory exception).
Empieza a matar procesos para liberar memoria
Puede tirar todo el sistema si mata el proceso equivocado (por ej. el demonio de Docker)
Docker ajusta la prioridad de OOM del demonio para reducir la probabilidad de recibir un kill.
Gestion de memoria de los contenedores
La prioridad de los contenedores no se debe ajustar.
El host debe tener suficiente memoria
Para evitar errores se debe limitar el uso de memoria de los contenedores
Ejemplo configuración
La configuración cambia bastante entre versiones de docker-compose
Workflow con docker
Desarrollo con Vagrant
Buena opción si trabajamos en equipos Windows y no queremos preocuparnos de despliegues
Descargamos Vagrant
Configuramos Vagrant (ver después) o hacemos un git clone de https://github.com/juanda99/vagrant-deploy-virtualbox-docker
Configuración Vagrant-Virtual Box
Nos situamos en un directorio e inicializamos mediante
vagrant init
Modificamos el fichero Vagrantfile creado con algo como:
Añadimos servicios mediante docker-compose cuyo punto de entrada se mapee al host en el 8000
Workflow en local
Workflow global
Development
CI/CD
Deployment
Last updated