Docker, una popular plataforma de virtualización a nivel de sistema operativo que nos permite entregar aplicaciones en paquetes conocidos como contenedores que, en términos sencillos, son entornos aislados con su propio software, bibliotecas y archivos de configuración.

Como cualquier otro software moderno, el registro de eventos y mensajes como advertencias y errores es una parte inherente de la plataforma Docker, que le permite depurar sus aplicaciones y problemas de producción.

Vamos a cubrir algunas formas sencillas en las que puede gestionar y supervisar los registros de sus contenedores. Así que vamos a empezar.

Comando Docker Logs

La sintaxis básica para obtener los registros de un contenedor es:

$ docker logs [OPCIONES] <NOMBRE O ID DE CONTENEDOR>

O

$ docker container logs [OPTIONS] <NOMBRE O ID DEL CONTENEDOR>

Ambas sintaxis son esencialmente iguales, por lo que nos centraremos en el resto de comandos de este artículo como docker logs.

Aunque tenga en cuenta aquí que el comando anterior sólo es funcional para los contenedores que se inician con el controlador de registro json-file o journald.

Aquí OPTIONS se refiere a las banderas disponibles compatibles con el comando docker logs, que se enumeran a continuación:

Nombre Por defecto Descripción
--detalles Muestra detalles adicionales proporcionados a los registros.
-seguir, -f Seguir la salida del registro
--since Muestra los registros desde la marca de tiempo (por ejemplo, 2021-08-28T15:23:37Z) o relativa (por ejemplo, 56m para 56 minutos)
--tail , -n todo Número de líneas a mostrar desde el final de los registros
--timestamps, -t Mostrar marcas de tiempo
--until API 1.35
Mostrar registros anteriores a una marca de tiempo (por ejemplo, 2021-08-28T15:23:37Z) o relativos (por ejemplo, 56m para 56 minutos)

Ejemplo:

$ docker ps
ID CONTENEDOR IMAGEN COMANDO CREADO ESTADO PUERTOS NOMBRES
28913415ed22 nginx "/docker-entrypoint...." hace 2 segundos Arriba 1 segundo 80/tcp gifted_edison
$ docker logs 28913415ed22
/docker-entrypoint.sh: /docker-entrypoint.d/ no está vacío, intentará realizar la configuración
/docker-entrypoint.sh: Buscando scripts de shell en /docker-entrypoint.d/
/docker-entrypoint.sh: Lanzando /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Obteniendo la suma de comprobación de /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Habilitada la escucha en IPv6 en /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Lanzando /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Lanzando /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuración completada; listo para el arranque
2021/08/28 09:02:59 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[notice]</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> 1#1: utilizando el método de evento "epoll
2021/08/28 09:02:59 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: nginx/1.21.1
2021/08/28 09:02:59 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: construido por gcc 8.3.0 (Debian 8.3.0-6)
2021/08/28 09:02:59 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: SO: Linux 5.8.0-1039-azure
2021/08/28 09:02:59 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2021/08/28 09:02:59 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[notice]</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> 1#1: iniciar procesos worker
2021/08/28 09:02:59 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: iniciar proceso trabajador 31
2021/08/28 09:02:59 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> aviso] 1#1: iniciar proceso worker 32
$

Ubicación de los registros de Docker

Docker, por defecto, captura la salida estándar (y el error estándar) de todos sus contenedores y los escribe en archivos utilizando el formato JSON. Esto se consigue utilizando el controlador de registro de archivos JSON o json-file. Estos registros se almacenan por defecto en ubicaciones específicas de cada contenedor bajo el sistema de archivos /var/lib/docker.

/var/lib/docker/containers/<container_id>/<container_id>-json.log

Como ejemplo, para mi contenedor redis listado a continuación, puedo comprobar su archivo de registro json como se muestra en el siguiente fragmento:

$ docker ps
CONTENEDOR ID IMAGEN COMANDO CREADO ESTADO PUERTOS NOMBRES
551c9273bbea redis "docker-entrypoint.s..." hace 19 minutos Arriba 19 minutos 6379/tcp redis
6cc871763df1 nginx "/docker-entrypoint...." hace 7 horas Arriba 7 horas 0.0.0.0:8080->80/tcp, :::8080->80/tcp nostalgic_wescoff
$ sudo ls -l /var/lib/docker/containers/551c9273bbea6eaf66523ed735866b9ebe6924c3b504dfeb44bef90e69d59c73/551c9273bbea6eaf66523ed735866b9ebe6924c3b504dfeb44bef90e69d59c73-json.log
-rw-r----- 1 root root 1437 28 ago 16:53 /var/lib/docker/containers/551c9273bbea6eaf66523ed735866b9ebe6924c3b504dfeb44bef90e69d59c73/551c9273bbea6eaf66523ed735866b9ebe6924c3b504dfeb44bef90e69d59c73-json.log
$ sudo tail -10 /var/lib/docker/containers/551c9273bbea6eaf66523ed735866b9ebe6924c3b504dfeb44bef90e69d59c73/551c9273bbea6eaf66523ed735866b9ebe6924c3b504dfeb44bef90e69d59c73-json.log
{"log": "1:C 28 Ago 2021 16:53:42.160 # oO0OOOOOOOOOo Redis is starting oO0OOOOOOOOo\n", "stream": "stdout", "time": "2021-08-28T16:53:42.16031257Z"}
{"log": "1:C 28 ago 2021 16:53:42.160 # Redis version=6.2.5, bits=64, commit=00000000, modified=0, pid=1, just started\n", "stream": "stdout", "time": "2021-08-28T16:53:42.160337871Z"}
{"log": "1:C 28 ago 2021 16:53:42.160 # Advertencia: no se ha especificado ningún archivo de configuración, se utiliza la configuración por defecto. Para especificar un archivo de configuración utilice redis-server /path/to/redis.conf\n", "stream": "stdout", "time": "2021-08-28T16:53:42.160342171Z"}
{"log": "1:M 28 ago 2021 16:53:42.160 * reloj monotónico: POSIX clock_gettime\n","stream":"stdout","time":"2021-08-28T16:53:42.160792578Z"}
{"log": "1:M 28 ago 2021 16:53:42.161 * Running mode=standalone, port=6379.\n", "stream": "stdout", "time": "2021-08-28T16:53:42.161148683Z"}
{"log": "1:M 28 Ago 2021 16:53:42.161 # Servidor inicializado\n", "stream": "stdout", "time": "2021-08-28T16:53:42.161170984Z"}
{"log": "1:M 28 Ago 2021 16:53:42.161 # ¡ATENCIÓN overcommit_memory está ajustado a 0! El guardado en segundo plano puede fallar en condiciones de poca memoria. Para solucionar este problema, añada 'vm.overcommit_memory = 1' a /etc/sysctl.conf y, a continuación, reinicie o ejecute el comando 'sysctl vm.overcommit_memory=1' para que surta efecto.\n", "stream": "stdout", "time": "2021-08-28T16:53:42.161186984Z"}
{"log": "1:M 28 Ago 2021 16:53:42.161 * Listo para aceptar conexiones\n", "stream": "stdout", "time": "2021-08-28T16:53:42.161484389Z"}
$

Mostrar detalles adicionales

Para mostrar detalles extra proporcionados a los logs, utilice la bandera --details.

Ejemplo:

$ docker logs 6cc871763df1 --details
 /docker-entrypoint.sh: /docker-entrypoint.d/ no está vacío, intentará realizar la configuración
 /docker-entrypoint.sh: Buscando scripts de shell en /docker-entrypoint.d/
 /docker-entrypoint.sh: Lanzando /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
 10-listen-on-ipv6-by-default.sh: info: Obteniendo la suma de comprobación de /etc/nginx/conf.d/default.conf
 10-listen-on-ipv6-by-default.sh: info: Habilitada la escucha en IPv6 en /etc/nginx/conf.d/default.conf
 /docker-entrypoint.sh: Lanzando /docker-entrypoint.d/20-envsubst-on-templates.sh
 /docker-entrypoint.sh: Lanzando /docker-entrypoint.d/30-tune-worker-processes.sh
 /docker-entrypoint.sh: Configuración completada; listo para el arranque
 2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[notice]</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> 1#1: utilizando el método de evento "epoll
 2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: nginx/1.21.1
 2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: construido por gcc 8.3.0 (Debian 8.3.0-6)
 2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: SO: Linux 5.8.0-1039-azure
 2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
 2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[notice]</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> 1#1: iniciar procesos worker
 2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: iniciar proceso trabajador 33
 2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> aviso] 1#1: iniciar proceso worker 34
 172.17.0.1 - - [28/Ago/2021:10:29:26 0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
$

Siga la salida del registro

Puede utilizar la bandera --follow o -f para seguir la salida del registro. Esto le permite seguir las nuevas actualizaciones en el flujo de registro desde STDOUT y STDERR de forma continua.

Ejemplo:

$ docker logs 6cc871763df1 -f
/docker-entrypoint.sh: /docker-entrypoint.d/ no está vacío, intentará realizar la configuración
/docker-entrypoint.sh: Buscando scripts de shell en /docker-entrypoint.d/
/docker-entrypoint.sh: Lanzando /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Obteniendo la suma de comprobación de /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Habilitada la escucha en IPv6 en /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Lanzando /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Lanzando /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuración completada; listo para el arranque
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[notice]</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> 1#1: utilizando el método de evento "epoll
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: nginx/1.21.1
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: construido por gcc 8.3.0 (Debian 8.3.0-6)
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: SO: Linux 5.8.0-1039-azure
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[notice]</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> 1#1: iniciar procesos worker
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: iniciar proceso trabajador 33
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> aviso] 1#1: iniciar proceso worker 34
172.17.0.1 - - [28/Ago/2021:10:29:26 0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"

Registros de cola

Los registros de los contenedores pueden ser «tailed» para limitar el número de salidas mostradas en pantalla con la bandera --tail o -n. Por defecto, esta bandera asume all como argumento que muestra el flujo de registro completo. Para mostrar un número fijo de líneas desde el final de los registros, especifique un número entero positivo a continuación de la bandera --tail o -n.

Ejemplo:

$ docker logs 6cc871763df1 -n 10
/docker-entrypoint.sh: Configuración completada; listo para el arranque
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: utilizando el método de eventos "epoll
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: nginx/1.21.1
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: construido por gcc 8.3.0 (Debian 8.3.0-6)
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: SO: Linux 5.8.0-1039-azure
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[notice]</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> 1#1: iniciar procesos worker
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: iniciar proceso trabajador 33
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> aviso] 1#1: iniciar proceso worker 34
172.17.0.1 - - [28/Ago/2021:10:29:26 0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
$

Mostrar registros desde

Podemos limitar la salida de registros utilizando la bandera --since y dando una marca de tiempo como un valor absoluto con la sintaxis 2021-08-28T15:23:37Z o uno relativo como 56m para 56 minutos.

La opción --since muestra sólo los registros del contenedor generados después de una fecha determinada. Puede especificar la fecha como una fecha RFC 3339, una marca de tiempo UNIX o una cadena de duración Go (por ejemplo, 1m30s, 3h). Se utilizará la zona horaria local del cliente si no proporciona una Z o un desplazamiento de zona horaria -00:00 al final de la marca de tiempo. Puede combinar la opción --since con una o ambas opciones --follow o --tail.

Ejemplo:

$ docker logs --since=1m nostalgic_wescoff
172.17.0.1 - - [28/Ago/2021:15:19:24 0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
172.17.0.1 - - [28/Ago/2021:15:19:25 0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
$

En el ejemplo anterior, se muestran los registros desde sólo 2 minutos donde nostalgic_wescoff es el nombre autogenerado asignado para el contenedor nginx.

Mostrar registros hasta

Al igual que la bandera --since, docker logs también soporta la bandera --until, que muestra los registros anteriores a la marca de tiempo dada. Del mismo modo, la marca de tiempo sigue una convención similar a la anterior y puede especificarse como un valor absoluto con la sintaxis 2021-08-28T15:23:37Z o uno relativo como 56m para 56 minutos.

Ejemplo:

$ docker logs --until=1h30m nostalgic_wescoff
/docker-entrypoint.sh: /docker-entrypoint.d/ no está vacío, intentará realizar la configuración
/docker-entrypoint.sh: Buscando scripts de shell en /docker-entrypoint.d/
/docker-entrypoint.sh: Lanzando /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Obteniendo la suma de comprobación de /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Habilitada la escucha en IPv6 en /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Lanzando /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Lanzando /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuración completada; listo para el arranque
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[notice]</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> 1#1: utilizando el método de evento "epoll
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: nginx/1.21.1
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: construido por gcc 8.3.0 (Debian 8.3.0-6)
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: SO: Linux 5.8.0-1039-azure
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[notice]</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> 1#1: iniciar procesos worker
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> notice] 1#1: iniciar proceso trabajador 33
2021/08/28 10:29:05 <x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x><x>[</x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x></x> aviso] 1#1: iniciar proceso worker 34
172.17.0.1 - - [28/Ago/2021:10:29:26 0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
$

En el ejemplo anterior, se muestran todos los registros anteriores a 1 hora y 30 minutos.

Mostrar marcas de tiempo

Muchas aplicaciones de contenedores ofrecen marcas de tiempo incorporadas en su salida de registro, por lo que Docker también las muestra con el comando docker logs. Si necesita que Docker anteponga explícitamente sus marcas de tiempo en la salida, utilice la bandera --timestamps o -t.

Ejemplo:

$ docker logs -t redis
2021-08-28T16:53:42.160312570Z 1:C 28 Aug 2021 16:53:42.160 # oO0OoO0OoOoOo Redis se está iniciando oO0OoOoOoOoOoo
2021-08-28T16:53:42.160337871Z 1:C 28 ago 2021 16:53:42.160 # Redis version=6.2.5, bits=64, commit=00000000, modified=0, pid=1, acaba de iniciarse
2021-08-28T16:53:42.160342171Z 1:C 28 ago 2021 16:53:42.160 # Advertencia: no se ha especificado ningún archivo de configuración, se utiliza la configuración predeterminada. Para especificar un archivo de configuración utilice redis-server /ruta/a/redis.conf
2021-08-28T16:53:42.160792578Z 1:M 28 ago 2021 16:53:42.160 * reloj monotónico: POSIX clock_gettime
2021-08-28T16:53:42.161148683Z 1:M 28 ago 2021 16:53:42.161 * Ejecutando mode=standalone, port=6379.
2021-08-28T16:53:42.161170984Z 1:M 28 ago 2021 16:53:42.161 # Servidor inicializado
2021-08-28T16:53:42.161186984Z 1:M 28 ago 2021 16:53:42.161 # ¡ATENCIÓN overcommit_memory está a 0! El guardado en segundo plano puede fallar en condiciones de poca memoria. Para solucionar este problema, añada 'vm.overcommit_memory = 1' a /etc/sysctl.conf y, a continuación, reinicie o ejecute el comando 'sysctl vm.overcommit_memory=1' para que surta efecto.
2021-08-28T16:53:42.161484389Z 1:M 28 ago 2021 16:53:42.161 * Listo para aceptar conexiones
$

Banderas de fusión

Docker ofrece combinar ciertas banderas para obtener una salida más filtrada en lugar de imprimir todo el contenido del registro en la pantalla. Como ejemplo sencillo, podemos combinar la bandera --tail con --since para obtener una salida más restringida.

Ejemplo:

$ docker logs --since=2h -f nostalgic_wescoff
172.17.0.1 - - [28/Ago/2021:15:19:24 0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
172.17.0.1 - - [28/Ago/2021:15:19:25 0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"

Esto también puede funcionar con otras banderas.

Filtrar con utilidades de Shell

Las utilidades del shell de Linux también se pueden utilizar para obtener más destreza en la salida del registro. Utilidades como grep, head, tail, etc. pueden ser canalizadas a la salida de los registros de Docker para operaciones más avanzadas.

Ejemplo:

$ docker logs --since=7h nostalgic_wescoff 2>&1 | grep GET
172.17.0.1 - - [28/Ago/2021:10:29:26 0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
172.17.0.1 - - [28/Ago/2021:15:19:24 0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
172.17.0.1 - - [28/Ago/2021:15:19:25 0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
$

Tenga en cuenta aquí que necesitamos redirigir los flujos de registro para proporcionar una única entrada canalizada para grep utilizando 2>&1.

Resumen 👩‍💻

Docker es una plataforma versátil que ofrece numerosas características para administrar su entorno. Gestionar los logs de un sistema es una de las habilidades esenciales que todo administrador de sistemas debe conocer. La gestión de registros en Docker es fácil una vez que conozca el comando disponible y las posibles banderas según sus necesidades.

Para más información sobre Docker y sus funcionalidades, consulte la documentación de Docker.