Регистрация с многопроцессорных докеров-контейнеров
Я использую метод symlinking nginx для ссылки на /dev/stdout для любых файлов журналов, которые я хочу отображать в "журналах докеров", однако это не работает.
Я тестировал это с помощью простой cronjob в /etc/crontab, если присутствует симликс (указывающий на /dev/stdout ), он ничего не пишет (насколько я могу судить), но если я удалю symlink и записывает в файл.
Также, если я эхо в /dev/stdout, он возвращается обратно в командную строку, однако он не найден в "журналах докеров"...
Вопрос: Должна ли эта работа работать? (Кажется, работает с nginx). Else, как я могу получить журналы из "вторичных" процессов, чтобы появляться в журналах докеров.
Для ссылки:
Nginx Dockerfile, показывающий метод symlinking: https://github.com/nginxinc/docker-nginx/blob/a8b6da8425c4a41a5dedb1fb52e429232a55ad41/Dockerfile
Создал официальный отчет об ошибке: https://github.com/docker/docker/issues/19616
My Dockerfile:
FROM ubuntu:trusty
#FROM quay.io/letsencrypt/letsencrypt:latest # For testing
ENV v="Fri Jan 22 10:08:39 EST 2016"
# Setup the cronjob
ADD crontab /etc/crontab
RUN chmod 600 /etc/crontab
# Setup letsencrypt logs
RUN ln -sf /dev/stdout /var/log/letsencrypt.log
# Setup cron logs
RUN ln -sf /dev/stdout /var/log/cron.log
RUN ln -sf /dev/stdout /var/log/syslog
# Setup keepalive script
ADD keepalive.sh /usr/bin/keepalive.sh
RUN chmod +x /usr/bin/keepalive.sh
ENTRYPOINT /usr/bin/keepalive.sh
Файл crontab:
* * * * * root date >> /var/log/letsencrypt.log
keepalive.sh script
#!/bin/bash
# Start cron
rsyslogd
cron
echo "Keepalive script running!"
while true; do
echo 'Sleeping for an hour...'
sleep 10
done
Ответы
Ответ 1
Конечный результат состоит в том, что /dev/stdout для задания cron указывалось на другое устройство.
/proc/self/fd/1 и должен был быть /proc/ 1/fd/1, потому что, поскольку докер ожидает только один процесс, он является единственным стандартным монитором.
Итак, как только я изменил символические ссылки на точку /proc/ 1/fd/1, он должен был работать, однако apparmor (на хосте) фактически отклонял запросы (и получал ошибки разрешений при эхом в /proc/ 1/fd/1) из-за профиля докеры по умолчанию (который автоматически генерируется, но может быть изменен с помощью -security-opts).
Однажды над препятствием для аплодисментов все работает!
Это сказало, посмотрев, что требуется, чтобы изменить в apparmor, чтобы разрешить требуемый запрос, я решил использовать метод mkfifo, как показано ниже.
Dockerfile
FROM ubuntu:latest
ENV v="RAND-4123"
# Run the wrapper script (to keep the container alive)
ADD daemon.sh /usr/bin/daemon.sh
RUN chmod +x /usr/bin/daemon.sh
# Create the pseudo log file to point to stdout
RUN mkfifo /var/log/stdout
RUN mkfifo /var/log/stderr
# Create a cronjob to echo into the logfile just created
RUN echo '* * * * * root date 2>/var/log/stderr 1>/var/log/stdout' > /etc/crontab
CMD "/usr/bin/daemon.sh"
daemon.sh
#!/bin/bash
# Start cron
cron
tail -qf --follow=name --retry /var/log/stdout /var/log/stderr
Ответ 2
Ну, это было упомянуто в комментариях, но для справки - я нахожу лучшее решение для docker
журналирование, как правило, полагается на "стандартные" механизмы многосистемного каротажа - в особенности syslog
насколько это возможно.
Это связано с тем, что вы можете использовать встроенный syslogd на своем хосте или использовать logstash как syslogd. У этого есть встроенный фильтр, но на самом деле это немного страдает от того, чтобы не быть достаточно гибким, поэтому вместо этого я использую прослушиватель TCP/UDP и анализирую журналы явно - как указано в "Когда logstash и syslog идут не так"
input {
tcp {
port => 514
type => syslog
}
udp {
port => 514
type => syslog
}
}
И затем отфильтруйте журнал:
filter {
if [type] == "syslog" {
grok {
match => { "message" => "<%{POSINT:syslog_pri}>%{SYSLOGTIMESTAMP:syslog_timestamp} %{SYSLOGHOST:syslog_hostname} %{DATA:syslog_program}(?:\[%{POSINT:syslog_pid}\])?: %{GREEDYDATA:syslog_message}" }
}
syslog_pri { }
}
}
Затем вы можете передать этот логсташ в elasticsearch - либо на удаленный хост, либо локальный контейнер, либо то, что я делаю сейчас, это docker network
с экземпляром elasticsearch с несколькими экземплярами node. (Я загрузил свой собственный файл с загрузкой и докером, но я уверен, что существует автономный контейнер).
output {
elasticsearch {
hosts => [ "es-tgt" ]
}
}
Преимущество здесь - докер позволяет использовать --link
или --net
для указания имени вашего контейнера elasticsearch, поэтому вы можете просто добавить псевдоним конфигурации logstash, чтобы указать на нужное место. (например, docker run -d --link my_es_container_name:es-tgt -p 514:514 -p 514:514/udp mylogstash
или просто docker run --net es_net ....
)
Настройка docker network
немного сложнее, поскольку вам нужно настроить хранилище ключей (я использовал etcd
но доступны другие варианты). Или вы можете сделать что-то вроде Кубернете.
И затем используйте kibana
, чтобы визуализировать, снова разоблачая порт kibana, но перенаправляя в сеть elasticsearch, чтобы поговорить с кластером.
Но как только это будет настроено, вы можете настроить nginx
на log to syslog
и все, что вы хотите, чтобы вести журнал регистрации Результаты. Реальное преимущество IMO заключается в том, что вы используете единую службу для ведения журнала, которая может быть масштабирована (благодаря сети/контейнеризации) в соответствии с вашими потребностями.