Docker – это популярная платформа виртуализации на уровне операционной системы. С помощью этой платформы мы можем доставлять приложения в пакетах, которые также известны как контейнеры. Проще говоря, контейнеры – это изолированные среды со своим собственным программным обеспечением, библиотеками и файлами конфигурации.
Протоколирование событий и сообщений, например, предупреждений и ошибок, - неотъемлемая часть платформы Docker (как и любого другого современного программного обеспечения). Эта платформа позволяет вам отлаживать ваши приложения и решать проблемы с производительностью.
Мы пробежимся по нескольким простым способам управления и мониторинга журналов для ваших контейнеров. Итак, давайте начнем.
Команды журналов Docker
Вот так выглядит базовый синтаксис для извлечения журналов контейнера:
$ docker logs [OPTIONS] <CONTAINER-NAME OR ID>
ИЛИ
$ docker container logs [OPTIONS] <CONTAINER-NAME OR ID>
По сути это одно и тоже, так что в этой статье мы сделаем упор на остальных командах, касающихся журналов Docker.
Отмечу только, что команда, приведенная выше, работает только для контейнеров, которые были запущены с помощью программ протоколирования json-file или journald .
Параметр OPTIONS подразумевает, что вместе с командой docker logs должны использоваться доступные поддерживаемые флаги, которые перечислены ниже:
Наименование, сокращение |
По умолчанию |
Описание |
--details |
Показывает дополнительную сведения, которые есть в журналах. |
|
--follow, -f |
Следит за выводом записей журналов. |
|
--since |
Показывает журналы, которые были созданы, начиная с какой-то определенной метки времени (например, 2021-08-28T15:23:37Z) или относительной метки времени (например, 56m для 56 минут). |
|
--tail , -n |
all |
Количество строк, которое нужно отобразить с конца журнала. |
--timestamps, -t |
Показывает временные метки. |
|
--until |
API 1.35+ Показывает журналы, которые были созданы до какой-то определенной метки времени (например, 2021-08-28T15:23:37Z) или относительной метки времени (например, 56m для 56 минут). |
Пример:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS
28913415ed22 nginx "/docker-entrypoint.…" 2 seconds ago Up 1 second
PORTS NAMES
80/tcp gifted_edison
$ docker logs 28913415ed22
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2021/08/28 09:02:59 [notice] 1#1: using the "epoll" event method
2021/08/28 09:02:59 [notice] 1#1: nginx/1.21.1
2021/08/28 09:02:59 [notice] 1#1: built by gcc 8.3.0 (Debian 8.3.0-6)
2021/08/28 09:02:59 [notice] 1#1: OS: Linux 5.8.0-1039-azure
2021/08/28 09:02:59 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2021/08/28 09:02:59 [notice] 1#1: start worker processes
2021/08/28 09:02:59 [notice] 1#1: start worker process 31
2021/08/28 09:02:59 [notice] 1#1: start worker process 32
$
Расположение журналов Docker
Docker автоматически собирает данные стандартного потока вывода (и данные о стандартных ошибках) всех ваших контейнеров и записывает их в файлы в формате JSON. Это происходит с помощью драйвера ведения журналов JSON File или json-file. Эти журналы обычно хранятся в специально отведенных местах в файловой системе /var/lib/docker.
/var/lib/docker/containers/<container_id>/<container_id>-json.log
Приведу пример. Проверю файл журнала json для моего контейнера redis (ниже):
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED 551c9273bbea redis "docker-entrypoint.s…" 19 minutes ago
6cc871763df1 nginx "/docker-entrypoint.…" 7 hours ago
STATUS PORTS NAMES
Up 19 minutes 6379/tcp redis
Up 7 hours 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 Aug 28 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 Aug 2021 16:53:42.160 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo\n","stream":"stdout","time":"2021-08-28T16:53:42.16031257Z"}
{"log":"1:C 28 Aug 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 Aug 2021 16:53:42.160 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf\n","stream":"stdout","time":"2021-08-28T16:53:42.160342171Z"}
{"log":"1:M 28 Aug 2021 16:53:42.160 * monotonic clock: POSIX clock_gettime\n","stream":"stdout","time":"2021-08-28T16:53:42.160792578Z"}
{"log":"1:M 28 Aug 2021 16:53:42.161 * Running mode=standalone, port=6379.\n","stream":"stdout","time":"2021-08-28T16:53:42.161148683Z"}
{"log":"1:M 28 Aug 2021 16:53:42.161 # Server initialized\n","stream":"stdout","time":"2021-08-28T16:53:42.161170984Z"}
{"log":"1:M 28 Aug 2021 16:53:42.161 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.\n","stream":"stdout","time":"2021-08-28T16:53:42.161186984Z"}
{"log":"1:M 28 Aug 2021 16:53:42.161 * Ready to accept connections\n","stream":"stdout","time":"2021-08-28T16:53:42.161484389Z"}
$
Дополнительная информация
Для того, чтобы увидеть дополнительную информацию, которую может предоставить журнал, воспользуйтесь флагом --details.
Пример:
$ docker logs 6cc871763df1 --details
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2021/08/28 10:29:05 [notice] 1#1: using the "epoll" event method
2021/08/28 10:29:05 [notice] 1#1: nginx/1.21.1
2021/08/28 10:29:05 [notice] 1#1: built by gcc 8.3.0 (Debian 8.3.0-6)
2021/08/28 10:29:05 [notice] 1#1: OS: Linux 5.8.0-1039-azure
2021/08/28 10:29:05 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2021/08/28 10:29:05 [notice] 1#1: start worker processes
2021/08/28 10:29:05 [notice] 1#1: start worker process 33
2021/08/28 10:29:05 [notice] 1#1: start worker process 34
172.17.0.1 - - [28/Aug/2021:10:29:26 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
$
Отслеживание вывода записей журнала
Для того, чтобы отслеживать вывод записей журнала, вы можете использовать флаг --follow или -f. Таким образом, вы сможете постоянно отслеживать новые обновления в потоке вывода журнала STDOUT и STDERR.
Пример:
$ docker logs 6cc871763df1 -f
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2021/08/28 10:29:05 [notice] 1#1: using the "epoll" event method
2021/08/28 10:29:05 [notice] 1#1: nginx/1.21.1
2021/08/28 10:29:05 [notice] 1#1: built by gcc 8.3.0 (Debian 8.3.0-6)
2021/08/28 10:29:05 [notice] 1#1: OS: Linux 5.8.0-1039-azure
2021/08/28 10:29:05 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2021/08/28 10:29:05 [notice] 1#1: start worker processes
2021/08/28 10:29:05 [notice] 1#1: start worker process 33
2021/08/28 10:29:05 [notice] 1#1: start worker process 34
172.17.0.1 - - [28/Aug/2021:10:29:26 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
«Хвост» журнала
Журналы контейнера можно ограничить в плане количества выходных данных, которые могут отображаться на экране. Это можно сделать с помощью флага --tail или -n. По умолчанию этот флаг подразумевает, что в качестве аргумента передается параметр all, то есть он покажет полный поток вывода журнала. Для того, чтобы отобразить какое-то фиксированное количество строк с конца журнала, добавьте положительное целое число после флага --tail или -n.
Пример:
$ docker logs 6cc871763df1 -n 10
/docker-entrypoint.sh: Configuration complete; ready for start up
2021/08/28 10:29:05 [notice] 1#1: using the "epoll" event method
2021/08/28 10:29:05 [notice] 1#1: nginx/1.21.1
2021/08/28 10:29:05 [notice] 1#1: built by gcc 8.3.0 (Debian 8.3.0-6)
2021/08/28 10:29:05 [notice] 1#1: OS: Linux 5.8.0-1039-azure
2021/08/28 10:29:05 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2021/08/28 10:29:05 [notice] 1#1: start worker processes
2021/08/28 10:29:05 [notice] 1#1: start worker process 33
2021/08/28 10:29:05 [notice] 1#1: start worker process 34
172.17.0.1 - - [28/Aug/2021:10:29:26 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
$
Просмотр журналов, созданных, начиная с какого-то момента времени
Мы можем ограничить вывод записей журнала с помощью флага --since и отметки времени после него. Например, вы можете использовать абсолютное значение 2021-08-28T15:23:37Z или относительное 56m (для 56 минут).
Флаг --since позволяет просмотреть журналы контейнера, которые были созданы после даты, которую вы указали. Вы можете указать дату согласно стандарту RFC 3339, с помощью системы Unix-времени или строк времени Go (например, 1m30s, 3h). Если вы не укажите смещение часового пояса Z (или +-00:00) после метки времени, то на клиентской стороне будет использоваться местный часовой пояс. Вы можете использовать флаг --since вместе с флагом --follow или --tail (или и тем, и другим одновременно).
Пример:
$ docker logs --since=1m nostalgic_wescoff
172.17.0.1 - - [28/Aug/2021:15:19:24 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
172.17.0.1 - - [28/Aug/2021:15:19:25 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
$
В примере выше показаны журналы, которые были созданы за последние 2 минуты. Здесь nostalgic_wescoff - это автоматически сгенерированное имя, присвоенное контейнеру nginx.
Просмотр журналов, созданных до какого-то момента времени
Команда docker logs поддерживает не только флаг --since, но и флаг --until. Этот флаг дает возможность просмотреть журналы, которые были созданы до какой-то определенной метки времени. Запись этой метки времени аналогична – вы можете указать как абсолютное значение (2021-08-28T15:23:37Z), так и относительное (56m для 56 минут).
Пример:
$ docker logs --until=1h30m nostalgic_wescoff
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2021/08/28 10:29:05 [notice] 1#1: using the "epoll" event method
2021/08/28 10:29:05 [notice] 1#1: nginx/1.21.1
2021/08/28 10:29:05 [notice] 1#1: built by gcc 8.3.0 (Debian 8.3.0-6)
2021/08/28 10:29:05 [notice] 1#1: OS: Linux 5.8.0-1039-azure
2021/08/28 10:29:05 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2021/08/28 10:29:05 [notice] 1#1: start worker processes
2021/08/28 10:29:05 [notice] 1#1: start worker process 33
2021/08/28 10:29:05 [notice] 1#1: start worker process 34
172.17.0.1 - - [28/Aug/2021:10:29:26 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
$
В примере выше, показаны все журналы, которые были созданы не позднее, чем 1 час и 30 минут назад.
Просмотр меток времени
У многих контейнерных приложений есть временные метки, которые встроены непосредственно в вывод записей журнала, поэтому вы можете их просмотреть с помощью той же команды docker logs. Если вы хотите, чтобы Docker явно добавил в начале метку времени, то воспользуйтесь флагом --timestamps или -t.
Пример:
$ docker logs -t redis
2021-08-28T16:53:42.160312570Z 1:C 28 Aug 2021 16:53:42.160 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
2021-08-28T16:53:42.160337871Z 1:C 28 Aug 2021 16:53:42.160 # Redis version=6.2.5, bits=64, commit=00000000, modified=0, pid=1, just started
2021-08-28T16:53:42.160342171Z 1:C 28 Aug 2021 16:53:42.160 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
2021-08-28T16:53:42.160792578Z 1:M 28 Aug 2021 16:53:42.160 * monotonic clock: POSIX clock_gettime
2021-08-28T16:53:42.161148683Z 1:M 28 Aug 2021 16:53:42.161 * Running mode=standalone, port=6379.
2021-08-28T16:53:42.161170984Z 1:M 28 Aug 2021 16:53:42.161 # Server initialized
2021-08-28T16:53:42.161186984Z 1:M 28 Aug 2021 16:53:42.161 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
2021-08-28T16:53:42.161484389Z 1:M 28 Aug 2021 16:53:42.161 * Ready to accept connections
$
Объединение флагов
Вы можете комбинировать определенные флаги, чтобы вам не приходилось выводит на экран все содержимое журналов, а вывод был более отфильтрованным. Давайте приведем простой пример: объединим флаги --tail и --since, чтобы ограничить наш вывод.
Пример:
$ docker logs --since=2h -f nostalgic_wescoff
172.17.0.1 - - [28/Aug/2021:15:19:24 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
172.17.0.1 - - [28/Aug/2021:15:19:25 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
С другими флагами это тоже будет работать.
Фильтрация с помощью утилит командной оболочки
Чтобы сделать вывод записей журнала еще более гибким, можно воспользоваться утилитами оболочки Linux. Например, такие утилиты, как grep, head, tail и т.д., можно передать команде docker logs, чтобы выполнить более сложные операции.
Пример:
$ docker logs --since=7h nostalgic_wescoff 2>&1 | grep GET
172.17.0.1 - - [28/Aug/2021:10:29:26 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
172.17.0.1 - - [28/Aug/2021:15:19:24 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
172.17.0.1 - - [28/Aug/2021:15:19:25 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "-"
$
Обратите внимание, что для того, чтобы обеспечить одноканальный ввод для grep, нам нужно перенаправить потоки записей журналов с помощью 2>&1.
Заключение
Docker – это универсальная платформа. Она предлагает огромное количество функций, с помощью которых вы можете управлять своей средой. Каждый системный администратор должен обладать таким навыком, как управление системными журналами. Если вы знаете команды и флаги, которые можно с ними использовать, то сможете с легкостью управлять журналами в Docker в соответствии с вашими требованиями.