Статьи

Пересылка журналов из всех контейнеров, работающих в любом месте внутри кластера Docker Swarm

В этой статье мы обсудим способ пересылки журналов из контейнеров, созданных в качестве сервисов Docker Swarm внутри наших кластеров. Мы будем использовать стек ELK . Они будут перенаправлены из контейнеров в LogStash, а оттуда в ElasticSearch. Попав в базу данных, они будут доступны через Kibana.

Настройка среды

Начнем с создания кластера Docker Swarm. Я предполагаю, что у вас уже есть хотя бы базовые знания о том, как работает Docker Swarm Mode и что вы знаете, как создавать сервисы Docker. Если вы этого не сделаете, я предлагаю вам прочитать статью « Введение в Docker Swarm» (тур по Docker 1.12) или получить Docker Swarm .

Некоторые из файлов будут разделены между файловой системой хоста и Docker Machines, которые мы скоро создадим. Docker Machine делает весь каталог, принадлежащий текущему пользователю, доступным внутри виртуальной машины. Поэтому убедитесь, что код клонирован внутри одной из подпапок пользователя.

Примечание для пользователей Windows

Рекомендуется запускать все примеры из Git Bash (устанавливается через Docker Toolbox, а также из Git ). Таким образом, команды, которые вы увидите в книге, будут такими же, как те, которые должны выполняться в OS X или любом дистрибутиве Linux .

1
2
3
4
5
git clone https://github.com/vfarcic/cloud-provisioning.git
 
cd cloud-provisioning
 
scripts/dm-swarm.sh

Мы клонировали cloud-provisioning хранилище и выполнили скрипт scripts / dm-swarm.sh, который создал производственный кластер.

Давайте подтвердим, что кластер действительно был создан правильно.

1
2
3
eval $(docker-machine env swarm-1)
 
docker node ls

Вывод команды node ls выглядит следующим образом (для краткости идентификаторы удалены).

1
2
3
4
HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS
swarm-2   Ready   Active        Reachable
swarm-1   Ready   Active        Leader
swarm-3   Ready   Active        Reachable

Теперь, когда производственный кластер запущен, мы можем создавать сервисы ELK.

1
scripts/dm-swarm-services-elk.sh

Вот и все. У нас должно быть несколько сервисов, работающих внутри кластера Swarm. Давайте дважды проверим это.

1
docker service ls

Вывод выглядит следующим образом (для краткости идентификаторы удалены).

1
2
3
4
5
6
NAME            REPLICAS  IMAGE                               COMMAND
swarm-listener  1/1       vfarcic/docker-flow-swarm-listener
logstash        1/1       logstash:2.4                        logstash -f /conf/logstash.conf
elasticsearch   1/1       elasticsearch:2.4
kibana          1/1       kibana:4.6
proxy           1/1       vfarcic/docker-flow-proxy

Наконец, мы готовы исследовать, как отправлять логи из наших сервисов Swarm в LogStash, а оттуда ElasticSearch.

Пересылка журналов в LogStash

Как мы можем пересылать логи из всех контейнеров, где бы они ни работали? Одним из возможных решений будет настройка драйверов ведения журналов . Мы могли бы использовать аргумент --log-driver чтобы указать драйвер для каждой службы. Драйвером может быть syslog или любой другой поддерживаемый параметр. Это решило бы нашу проблему доставки журналов. Однако использование аргумента для каждой службы утомительно, и, что более важно, мы можем легко забыть указать его для одной или двух служб и обнаружить упущение только после того, как мы столкнемся с проблемой и нуждаемся в журналах. Давайте посмотрим, есть ли другой вариант для достижения того же результата.

Мы могли бы указать драйвер журнала в качестве опции конфигурации демона Docker на каждом узле. Это, безусловно, облегчит настройку. В конце концов, вероятно, серверов меньше, чем сервисов. Если бы нам пришлось выбирать между установкой драйвера при создании службы или конфигурацией демона, я бы выбрал позже. Однако до сих пор нам не удалось изменить конфигурацию демона по умолчанию, и я бы предпочел, чтобы мы продолжали работать без привлечения каких-либо специальных инструментов обеспечения. К счастью, мы до сих пор не исчерпали всех наших вариантов.

Мы можем отправлять логи из всех наших контейнеров с проектом logspout .

LogSpout — это маршрутизатор журналов для контейнеров Docker, который работает внутри Docker. Он присоединяется ко всем контейнерам на хосте, а затем направляет их журналы туда, куда мы хотим. Он также имеет расширяемую систему модулей. Это в основном устройство регистрации без сохранения состояния. Он не предназначен для управления файлами журналов или просмотра истории. Это всего лишь инструмент, чтобы вывести ваши журналы, чтобы жить где-то еще, где они принадлежат.

Если вы изучите документацию проекта, то заметите, что нет инструкций по его запуску в качестве службы Docker. Это не должно иметь значения, поскольку к этому времени вы можете считать себя экспертом в создании сервисов.

Что нам нужно от службы, которая должна пересылать журналы со всех контейнеров, работающих внутри всех узлов, которые образуют кластер? Поскольку мы хотим перенаправить их в LogStash, который уже подключен к сети elk , мы должны также подключить LogSpout к нему. Нам это нужно для доставки журналов со всех узлов, поэтому сервис должен быть global . Необходимо знать, что пунктом назначения является служба с именем logstash и что она прослушивает порт 51415 . Наконец, одним из требований LogSpout является то, что сокет Docker от хоста монтируется внутри сервисных контейнеров. Он будет использовать его для мониторинга журналов.

Команда, которая создает службу, которая выполняет все эти цели и требования, выглядит следующим образом.

1
2
3
4
5
6
docker service create --name logspout \
    --network elk \
    --mode global \
    --mount "type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock" \
    -e SYSLOG_FORMAT=rfc3164 \
    gliderlabs/logspout syslog://logstash:51415

Мы создали службу с именем logspout , подключили ее к сети elk , установили ее как global и установили сокет Docker. Команда, которая будет выполнена после создания контейнеров: syslog://logstash:51415 . Он сообщает LogSpout, что мы хотим использовать протокол syslog для отправки журналов в logstash работающий через порт 51415 .

Этот проект является примером полезности Docker Remote API. Контейнеры logspout будут использовать его для получения списка всех работающих в данный момент контейнеров и потоковой передачи их журналов. Это уже второй продукт в нашем кластере, который использует API (первым является Docker Flow: Swarm Listener ).

Давайте посмотрим статус сервиса, который мы только что создали.

1
docker service ps logspout

Вывод выглядит следующим образом (для краткости идентификаторы удалены).

1
2
3
4
NAME          IMAGE                NODE     DESIRED STATE  CURRENT STATE          ERROR
logspout      gliderlabs/logspout  swarm-3  Running        Running 9 seconds ago
 \_ logspout  gliderlabs/logspout  swarm-2  Running        Running 9 seconds ago
 \_ logspout  gliderlabs/logspout  swarm-1  Running        Running 9 seconds ago

Служба работает в глобальном режиме, в результате чего создается экземпляр внутри каждого узла.

Давайте проверим, действительно ли служба logspout отправляет все журналы в LogStash. Все, что нам нужно сделать, — это создать сервис, который генерирует некоторые журналы и наблюдает их из вывода LogStash. Мы будем использовать registry для проверки настроек, которые мы сделали до сих пор.

1
2
3
4
5
docker service create --name registry \
    -p 5000:5000 \
    --mount "type=bind,source=$PWD,target=/var/lib/registry" \
    --reserve-memory 100m \
    registry

Прежде чем проверять журналы LogStash, мы должны подождать, пока registry не запустится.

1
docker service ps registry

Если текущее состояние все еще не запущено, подождите несколько минут.

Теперь мы можем взглянуть на журналы logstash и подтвердить, что logspout отправил ему записи журнала, сгенерированные registry .

1
2
3
4
5
6
7
LOGSTASH_NODE=$(docker service ps logstash | tail +2 | awk '{print $4}')
 
eval $(docker-machine env $LOGSTASH_NODE)
 
LOGSTASH_ID=$(docker ps -q --filter "ancestor=logstash:2.4")
 
docker logs $LOGSTASH_ID

Одна из записей из вывода выглядит следующим образом.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
{
           "message" => "time=\"2016-10-19T23:14:19Z\" level=info msg=\"listening on [::]:5000\" go.version=go1.6.3 instance.id=87c31e30-a747-4f70-b7c2-396dd80eb47b version=v2.5.1 \n",
          "@version" => "1",
        "@timestamp" => "2016-10-19T23:14:19.000Z",
              "host" => "10.0.0.7",
          "priority" => 14,
     "timestamp8601" => "2016-10-19T23:14:19Z",
         "logsource" => "c51c177bd308",
           "program" => "registry.1.abszmuwq8k3d7comu504lz2mc",
               "pid" => "4833",
          "severity" => 6,
          "facility" => 1,
         "timestamp" => "2016-10-19T23:14:19Z",
    "facility_label" => "user-level",
    "severity_label" => "Informational"
}

Как и раньше, когда мы тестировали ввод LogStash с помощью logger , у нас есть message , timestamp , host и несколько других полей syslog logger . Мы также получили logsource который содержит идентификатор контейнера, который создал журнал, а также program которая содержит имя контейнера. Оба будут полезны при отладке, какая служба и контейнер вызвали ошибку.

Если вы вернетесь к команде, которую мы использовали для создания службы logstash , вы заметите переменную среды LOGSPOUT=ignore . Он сообщает LogSpout, что сервис или, точнее, все контейнеры, которые формируют сервис, следует игнорировать. Если бы мы не определили его, LogSpout перенаправил бы все журналы logstash в logstash создавая таким образом бесконечный цикл. Как мы уже обсуждали, в производственном процессе мы не должны выводить записи LogStash в стандартный stdout . Мы сделали это только для того, чтобы лучше понять, как это работает. Если вывод stdout будет удален из конфигурации logstash , не будет необходимости в переменной среды LOGSPOUT=ignore . В результате журналы logstash также будут храниться в ElasticSearch.

Теперь, когда мы отправляем все журналы в LogStash, а оттуда в ElasticSearch, мы должны изучить способы их просмотра. Вы найдете их в службе kibana .

1
open http://$(docker-machine ip swarm-1)/app/kibana

Перед отъездом обязательно удалите созданные нами машины и освободите свои ресурсы для некоторых других задач.

1
docker-machine rm -f swarm-1 swarm-2 swarm-3

Статья, которую вы только что закончили, является выдержкой из главы « Определение стратегии ведения журнала» в книга Docker Swarm .

Если вам понравилась эта статья, вас может заинтересовать book. В отличие от предыдущего заголовка серии ( ), в котором подробно рассматриваются некоторые из последних практик и инструментов DevOps, эта книга полностью посвящена Docker Swarm, а также процессам и инструментам нам может понадобиться создавать, тестировать, развертывать и отслеживать службы, работающие внутри кластера.

Сокрытие книга-маленькая

Книга все еще находится в стадии разработки. Вы можете получить копию из LeanPub . Он также доступен в виде Если вы загрузите его сейчас, прежде чем он будет полностью завершен, вы будете получать частые обновления с новыми главами и исправлениями. Что еще более важно, вы сможете повлиять на направление книги, отправив мне свой отзыв.

Я выбираю бережливый подход к изданию книг, потому что считаю, что ранняя обратная связь — лучший способ создать отличный продукт. Пожалуйста, помогите мне сделать эту книгу справочной для всех, кто хочет принять Docker Swarm для кластерной оркестровки и планирования.