Recursos, reinicio automático y healthchecks
1. Introducción #
Hasta ahora hemos aprendido a:
- Crear contenedores.
- Publicar puertos.
- Utilizar volúmenes.
- Crear redes.
- Consultar logs.
- Monitorizar recursos.
Ahora vamos a dar un paso más.
Cuando ejecutamos servicios reales necesitamos controlar:
1cuánta memoria pueden utilizar 2cuánta CPU pueden consumir 3qué ocurre si fallan 4si deben reiniciarse automáticamente 5si realmente están funcionando correctamente
Para ello veremos:
1--memory 2--cpus 3--restart 4docker update 5HEALTHCHECK 6docker inspect 7docker ps
2. ¿Por qué limitar recursos? #
Por defecto, un contenedor puede utilizar los recursos disponibles del sistema según la configuración del entorno Docker.
Imaginemos que tenemos:
1MYSQL 2NGINX 3APLICACIÓN
y MySQL comienza a consumir mucha memoria.
Podría afectar a:
1Nginx 2la aplicación 3el propio sistema 4otros contenedores
Podemos evitarlo estableciendo límites.
3. Limitar memoria: --memory #
Podemos limitar la memoria de un contenedor mediante:
1docker run --memory <cantidad> <imagen>
Por ejemplo:
1docker run --memory 256m debian
Esto establece un límite de memoria de:
1256 MB
4. Ejemplo interactivo #
Podemos ejecutar:
1docker run -it --memory 256m debian bash
Después, desde otra terminal:
1docker stats
Podremos observar el límite asociado al contenedor.
5. Unidades de memoria #
Podemos utilizar valores como:
1128m 2256m 3512m 41g 52g
Por ejemplo:
1docker run --memory 512m nginx
6. Ejemplo con Nginx #
Creamos:
1docker run -d \ 2 --name nginx-limitado \ 3 --memory 128m \ 4 -p 8080:80 \ 5 nginx
Después comprobamos:
1docker stats nginx-limitado
Podremos ver el consumo actual y el límite.
7. Limitar CPU: --cpus #
También podemos limitar cuánto procesador puede utilizar un contenedor.
Por ejemplo:
1docker run --cpus 1 nginx
Esto limita el contenedor aproximadamente al equivalente de:
11 CPU
También podemos utilizar:
1docker run --cpus 0.5 nginx
para limitarlo aproximadamente a:
1medio núcleo de CPU
8. Combinar CPU y memoria #
Podemos establecer ambos límites:
1docker run -d \ 2 --name web-limitada \ 3 --memory 256m \ 4 --cpus 0.5 \ 5 -p 8080:80 \ 6 nginx
Tenemos:
1Memoria máxima: 2256 MB 3 4CPU: 50.5
9. Comprobar con docker stats #
Ejecutamos:
1docker stats web-limitada
Podremos observar:
1CPU % 2MEM USAGE / LIMIT
Esto permite comprobar si el contenedor se está acercando a sus límites.
10. ¿Qué ocurre si supera la memoria? #
Si un contenedor intenta utilizar más memoria de la permitida, el sistema puede terminar procesos dentro del contenedor.
Por eso debemos elegir límites adecuados.
No tendría sentido limitar:
1MySQL
a una cantidad extremadamente pequeña de memoria y esperar que funcione correctamente.
11. Modificar límites de un contenedor existente #
Docker permite modificar ciertos límites mediante:
1docker update
Por ejemplo:
1docker update --memory 512m web-limitada
También:
1docker update --cpus 1 web-limitada
Después podemos comprobar:
1docker stats web-limitada
12. docker update #
La sintaxis general es:
1docker update [opciones] <contenedor>
Por ejemplo:
1docker update --memory 1g mysql
Esto puede resultar útil si necesitamos ajustar recursos sin volver a crear el contenedor.
13. ¿Qué ocurre cuando Docker reinicia? #
Hasta ahora, si reiniciamos Docker o el ordenador, algunos contenedores pueden quedar detenidos dependiendo de su configuración.
Para servicios importantes podemos definir una política de reinicio.
Utilizamos:
1--restart
14. Política no #
El valor:
1no
significa que Docker no intentará reiniciar automáticamente el contenedor.
Por ejemplo:
1docker run --restart no nginx
Es el comportamiento básico cuando no especificamos otra política.
15. Política always #
Podemos utilizar:
1docker run --restart always nginx
Esto indica que Docker debe intentar volver a arrancar el contenedor cuando se detenga y cuando Docker vuelva a iniciarse.
Ejemplo:
1docker run -d \ 2 --name servidor-web \ 3 --restart always \ 4 -p 8080:80 \ 5 nginx
16. Política unless-stopped #
Otra opción habitual es:
1unless-stopped
Ejemplo:
1docker run -d \ 2 --name servidor-web \ 3 --restart unless-stopped \ 4 -p 8080:80 \ 5 nginx
La idea es:
1reiniciar automáticamente 2salvo que lo hayamos detenido explícitamente
17. Política on-failure #
También podemos utilizar:
1on-failure
Ejemplo:
1docker run --restart on-failure mi-aplicacion
Esta política intenta reiniciar el contenedor cuando el proceso termina con error.
18. Comparación de políticas #
Podemos resumir:
1no 2↓ 3no reiniciar automáticamente 4 5 6always 7↓ 8intentar mantenerlo arrancado 9 10 11unless-stopped 12↓ 13reiniciar salvo parada explícita 14 15 16on-failure 17↓ 18reiniciar cuando falla
19. Ejemplo práctico #
Creamos:
1docker run -d \ 2 --name nginx-reinicio \ 3 --restart unless-stopped \ 4 -p 8081:80 \ 5 nginx
Comprobamos:
1docker inspect nginx-reinicio
Dentro de la configuración podremos localizar la política de reinicio.
20. Cambiar la política #
También podemos utilizar:
1docker update --restart always nginx-reinicio
Después comprobamos:
1docker inspect nginx-reinicio
21. Contenedor arrancado no significa servicio sano #
Supongamos:
1docker ps
muestra:
1Up 5 minutes
Eso significa que el proceso principal está ejecutándose.
Pero no garantiza necesariamente que la aplicación responda correctamente.
Por ejemplo:
1el servidor web podría estar bloqueado 2la base de datos podría no aceptar conexiones 3una dependencia podría haber fallado
Para esto existen los:
1healthchecks
22. ¿Qué es un healthcheck? #
Un healthcheck es una comprobación que Docker ejecuta para determinar si un servicio está funcionando correctamente.
El estado puede ser:
1starting 2healthy 3unhealthy
23. HEALTHCHECK en Dockerfile #
Podemos añadir una instrucción:
1HEALTHCHECK
a un Dockerfile.
Por ejemplo, para un servidor web:
1FROM nginx 2 3HEALTHCHECK CMD curl -f http://localhost/ || exit 1
La idea es:
1Docker ejecuta una prueba 2 ↓ 3¿responde el servicio? 4 ↓ 5sí → healthy 6no → unhealthy
24. Problema del ejemplo anterior #
Para que:
1curl
funcione dentro de la imagen, esa herramienta debe estar instalada.
Por eso, para una práctica controlada podemos partir de una imagen donde instalemos la herramienta necesaria.
25. Dockerfile de ejemplo #
Podemos crear:
1FROM nginx 2 3RUN apt update && apt install -y curl 4 5HEALTHCHECK \ 6 CMD curl -f http://localhost/ || exit 1
Después:
1docker build -t nginx-health .
26. Ejecutar la imagen #
Creamos:
1docker run -d \ 2 --name web-health \ 3 -p 8080:80 \ 4 nginx-health
Después:
1docker ps
Podremos observar algo parecido a:
1Up ... (healthy)
cuando el servicio supera la comprobación.
27. Estados del healthcheck #
Inicialmente podemos ver:
1starting
Mientras Docker realiza las primeras comprobaciones.
Después:
1healthy
si todo funciona.
O:
1unhealthy
si las comprobaciones fallan repetidamente.
28. Opciones de HEALTHCHECK #
Podemos configurar:
1--interval 2--timeout 3--retries 4--start-period
Por ejemplo:
1HEALTHCHECK \ 2 34 \ 5 CMD curl -f http://localhost/ || exit 1
29. interval #
Ejemplo:
1--interval=30s
indica aproximadamente cada cuánto se realiza la comprobación.
30. timeout #
Ejemplo:
1--timeout=5s
indica cuánto esperamos a que termine la prueba antes de considerarla fallida.
31. retries #
Ejemplo:
1--retries=3
permite establecer cuántos fallos consecutivos se toleran antes de considerar el contenedor:
1unhealthy
32. Consultar el healthcheck #
Podemos utilizar:
1docker inspect web-health
y localizar la sección relacionada con:
1Health
Podremos encontrar información como:
1Status 2FailingStreak 3Log
33. Filtrar el estado #
También podemos utilizar:
1docker inspect \ 2 --format='{{.State.Health.Status}}' \ 3 web-health
Esto puede devolver:
1healthy
o:
1unhealthy
34. Healthcheck desde docker run #
También es posible definir ciertas comprobaciones mediante opciones de:
1docker run
aunque para un curso introductorio suele resultar más claro definirlas dentro del Dockerfile o de Docker Compose.
35. Healthcheck en Docker Compose #
Podemos definirlo en:
1compose.yaml
Por ejemplo:
1services: 2 3 web: 4 image: nginx 5 ports: 6 - "8080:80" 7 healthcheck: 8 test: ["CMD", "curl", "-f", "http://localhost"] 9 interval: 30s 10 timeout: 5s 11 retries: 3
Siempre debemos asegurarnos de que el comando de comprobación exista dentro del contenedor.
36. Healthcheck con MySQL #
Una comprobación puede ser especialmente útil en bases de datos.
Por ejemplo, conceptualmente queremos saber:
1¿MySQL está arrancado? 2¿acepta conexiones?
Esto es distinto de comprobar simplemente:
1docker ps
porque el proceso podría existir sin que el servicio esté todavía preparado.
37. depends_on y healthcheck #
En Docker Compose vimos:
1depends_on:
Podemos combinarlo con healthchecks.
Conceptualmente:
1Aplicación 2 │ 3 │ necesita 4 ↓ 5 MySQL 6 │ 7 ↓ 8 healthy
Así podemos expresar mejor cuándo una dependencia está realmente preparada.
38. Ejemplo Compose con MySQL #
Podemos plantear:
1services: 2 3 mysql: 4 image: mysql 5 environment: 6 MYSQL_ROOT_PASSWORD: Ad1234 7 MYSQL_DATABASE: curso 8 healthcheck: 9 test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-pAd1234"] 10 interval: 10s 11 timeout: 5s 12 retries: 5
Después:
1docker compose up -d
Podemos comprobar:
1docker compose ps
39. Combinar límites y política de reinicio #
Podemos crear un servicio web más controlado:
1docker run -d \ 2 --name web-produccion \ 3 --memory 256m \ 4 --cpus 0.5 \ 5 --restart unless-stopped \ 6 -p 8080:80 \ 7 nginx
Tenemos:
1Memoria limitada 2CPU limitada 3Reinicio automático 4Puerto publicado
40. Comprobar la configuración #
Podemos utilizar:
1docker inspect web-produccion
Y:
1docker stats web-produccion
para comprobar:
1estado 2consumo 3límites 4política de reinicio 5red 6puertos
41. Ejemplo con Docker Compose #
Podemos definir recursos y reinicio en una aplicación Compose.
Ejemplo sencillo:
1services: 2 3 web: 4 image: nginx 5 ports: 6 - "8080:80" 7 restart: unless-stopped
La sintaxis concreta de recursos puede depender del contexto de Compose utilizado, por lo que para prácticas iniciales los límites pueden enseñarse primero con docker run.
42. Práctica guiada: límites #
Paso 1 #
Crea:
1docker run -d \ 2 --name nginx-recursos \ 3 --memory 128m \ 4 --cpus 0.5 \ 5 -p 8080:80 \ 6 nginx
Paso 2 #
Comprueba:
1docker ps
Paso 3 #
Ejecuta:
1docker stats nginx-recursos
Observa:
1CPU % 2MEM USAGE / LIMIT
43. Modificar recursos #
Ejecuta:
1docker update --memory 256m nginx-recursos
Después:
1docker stats nginx-recursos
Comprueba que ha cambiado el límite.
44. Práctica de reinicio #
Crea:
1docker run -d \ 2 --name nginx-auto \ 3 --restart unless-stopped \ 4 -p 8081:80 \ 5 nginx
Comprueba:
1docker inspect nginx-auto
Busca su política de reinicio.
Después:
1docker stop nginx-auto
Y comprueba su comportamiento.
45. Práctica con healthcheck #
Crea una carpeta:
1nginx-health/
Dentro:
1Dockerfile
con:
1FROM nginx 2 3RUN apt update && apt install -y curl 4 5HEALTHCHECK \ 6 CMD curl -f http://localhost/ || exit 1
Construye:
1docker build -t nginx-health .
46. Ejecutar #
1docker run -d \ 2 --name nginx-salud \ 3 -p 8082:80 \ 4 nginx-health
Comprueba:
1docker ps
Espera a que aparezca:
1healthy
47. Inspeccionar el estado #
Ejecuta:
1docker inspect nginx-salud
Busca:
1Health
Después:
1docker inspect \ 2 --format='{{.State.Health.Status}}' \ 3 nginx-salud
48. Ejercicio práctico #
Crea un contenedor Nginx que cumpla:
1Nombre: 2web-controlada 3 4Puerto: 58085 → 80 6 7Memoria máxima: 8128 MB 9 10CPU máxima: 110.5 12 13Política de reinicio: 14unless-stopped
Después:
- Comprueba que funciona.
- Accede desde el navegador.
- Consulta sus estadísticas.
- Inspecciona su configuración.
- Cambia la memoria a 256 MB.
- Comprueba el nuevo límite.
- Reinicia el contenedor.
- Comprueba que sigue funcionando.
49. Ejercicio de ampliación #
Crea una imagen Nginx personalizada con un healthcheck.
Requisitos:
1interval: 215 segundos 3 4timeout: 53 segundos 6 7retries: 83
Después:
- Construye la imagen.
- Arranca un contenedor.
- Comprueba el estado con
docker ps. - Consulta el healthcheck mediante
docker inspect. - Consulta los logs.
- Detén y elimina el contenedor.
50. Preguntas de repaso #
-
¿Por qué puede ser interesante limitar los recursos de un contenedor?
-
¿Para qué sirve
--memory? -
¿Qué significa:
1--memory 256m
-
¿Para qué sirve
--cpus? -
¿Qué significa:
1--cpus 0.5
-
¿Para qué sirve
docker update? -
¿Qué es una política de reinicio?
-
¿Qué diferencia existe entre
alwaysyunless-stopped? -
¿Para qué sirve
on-failure? -
¿Un contenedor que aparece como
Uptiene necesariamente un servicio funcionando correctamente? -
¿Qué es un healthcheck?
-
¿Qué estados puede mostrar?
-
¿Para qué sirve
HEALTHCHECK? -
¿Qué significa
--interval? -
¿Qué significa
--timeout? -
¿Qué significa
--retries? -
¿Cómo podemos consultar el resultado de un healthcheck?
-
¿Por qué un healthcheck es especialmente útil con bases de datos?
51. Resumen de comandos #
Limitar memoria #
1docker run --memory 256m imagen
Limitar CPU #
1docker run --cpus 0.5 imagen
Ambos #
1docker run \ 2 --memory 256m \ 3 --cpus 0.5 \ 4 imagen
Modificar límites #
1docker update --memory 512m contenedor
1docker update --cpus 1 contenedor
Reinicio automático #
1docker run --restart always imagen
1docker run --restart unless-stopped imagen
1docker run --restart on-failure imagen
Cambiar política #
1docker update --restart unless-stopped contenedor
Consultar recursos #
1docker stats
Consultar configuración #
1docker inspect contenedor
52. Resumen de Dockerfile #
Ejemplo:
1FROM nginx 2 3RUN apt update && apt install -y curl 4 5HEALTHCHECK \ 6 78 \ 9 CMD curl -f http://localhost/ || exit 1
53. Esquema final #
1 CONTENEDOR 2 │ 3 ┌──────────┼──────────┐ 4 ↓ ↓ ↓ 5 CPU MEMORIA SERVICIO 6 │ │ │ 7 --cpus --memory HEALTHCHECK 8 │ 9 ┌─────────┼─────────┐ 10 ↓ ↓ ↓ 11 starting healthy unhealthy
Y para mantener el servicio disponible:
1CONTENEDOR 2 │ 3 ↓ 4--restart 5 │ 6 ├── always 7 ├── unless-stopped 8 └── on-failure
La idea fundamental de este bloque es pasar de:
1"el contenedor está arrancado"
a controlar también:
1cuántos recursos consume 2qué ocurre si falla 3si debe reiniciarse 4si el servicio está realmente sano
Esto acerca el uso de Docker a escenarios reales de servidores y aplicaciones.