Регистрация с многопроцессорных докеров-контейнеров

Я использую метод 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 заключается в том, что вы используете единую службу для ведения журнала, которая может быть масштабирована (благодаря сети/контейнеризации) в соответствии с вашими потребностями.