Как использовать Confd и Etcd для динамической перенастройки сервисов в CoreOS

Вступление

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

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

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

Предпосылки и цели

Для работы с этим руководством у вас должно быть базовое понимание CoreOS и его составных частей. В предыдущих руководствах мы настраивали кластер CoreOS и знакомились с некоторыми инструментами, которые используются для управления вашими кластерами.

Ниже приведены руководства, которые вы должны прочитать, прежде чем приступить к этой статье. Мы будем изменять поведение некоторых служб, описанных в этих руководствах, поэтому, хотя важно понимать материал, вы должны начать все сначала, используя это руководство:

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

Руководство «Как создать гибкие сервисы» особенно важно для этого руководства, поскольку шаблонные сервисы main + sidekick послужат основой для интерфейсного сервиса, который мы будем настраивать в этом руководстве. Как мы заявляли ранее, хотя в приведенных выше руководствах обсуждается создание служб Apache и дополнительных сервисов, в этом руководстве есть некоторые изменения конфигурации, которые облегчают запуск с нуля. В этом руководстве мы создадим модифицированные версии этих сервисов.

В этом уроке мы сосредоточимся на создании нового контейнера приложения с помощью Nginx. Это будет служить обратным прокси-сервером для различных экземпляров Apache, которые мы можем порождать из наших файлов шаблонов. Контейнер Nginx будет настроен сconfd для наблюдения за регистрацией службы, за которую отвечают наши вспомогательные службы.

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

  • coreos-1

  • coreos-2

  • coreos-3

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

Конфигурирование серверных служб Apache

Мы начнем с настройки наших серверных служб Apache. В основном это будет отражать последнюю часть предыдущего руководства, но мы пройдем всю процедуру здесь из-за некоторых тонких различий.

Войдите в один из ваших компьютеров с CoreOS, чтобы начать:

ssh -A core@ip_address

Настройка контейнера Apache

Начнем с создания основного контейнера Apache. Это фактически идентично последнему руководству, поэтому вам не придется делать это снова, если у вас уже есть это изображение в вашей учетной записи Docker Hub. Мы создадим этот контейнер из образа контейнера Ubuntu 14.04.

Мы можем снять базовое изображение и запустить экземпляр контейнера, набрав:

docker run -i -t ubuntu:14.04 /bin/bash

После запуска контейнера вы попадете в сеансbash. Отсюда мы обновим локальный индекс пакетаapt и установимapache2:

apt-get update
apt-get install apache2 -y

Мы также установим страницу по умолчанию:

echo "

Running from Docker on CoreOS

" > /var/www/html/index.html

Мы можем выйти из контейнера сейчас, так как он находится в нужном нам состоянии:

exit

Войдите или создайте свой аккаунт в Docker Hub, введя:

docker login

Вам нужно будет указать свое имя пользователя, пароль и адрес электронной почты для учетной записи Docker Hub.

Затем получите идентификатор контейнера только что оставленного экземпляра:

docker ps -l
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
1db0c9a40c0d        ubuntu:14.04        "/bin/bash"         2 minutes ago       Exited (0) 4 seconds ago                       jolly_pare

Выделенное поле выше - это идентификатор контейнера. Скопируйте вывод, который вы видите на свой компьютер.

Теперь выполните фиксацию с использованием этого идентификатора контейнера, вашего имени пользователя в Docker Hub и имени для изображения. Мы будем использовать «apache» здесь:

docker commit 1db0c9a40c0d user_name/apache

Вставьте ваше новое изображение в Docker Hub:

docker push user_name/apache

Теперь можете использовать это изображение в ваших служебных файлах.

Создание файла модуля шаблона службы Apache

Теперь, когда у вас есть контейнер, вы можете создать файл модуля шаблона, чтобыfleet иsystemd могли правильно управлять службой.

Прежде чем мы начнем, давайте настроим структуру каталогов, чтобы мы могли оставаться организованными:

cd ~
mkdir static templates instances

Теперь мы можем разместить наш файл шаблона в каталогеtemplates:

vim templates/[email protected]

Вставьте следующую информацию в файл. Вы можете получить подробную информацию о каждой из используемых нами опций, следуя предыдущему руководству поcreating flexible fleet unit files:

[Unit]
Description=Apache web server service on port %i

# Requirements
Requires=etcd.service
Requires=docker.service
Requires=apache-discovery@%i.service

# Dependency ordering
After=etcd.service
After=docker.service
Before=apache-discovery@%i.service

[Service]
# Let processes take awhile to start up (for first run Docker containers)
TimeoutStartSec=0

# Change killmode from "control-group" to "none" to let Docker remove
# work correctly.
KillMode=none

# Get CoreOS environmental variables
EnvironmentFile=/etc/environment

# Pre-start and Start
## Directives with "=-" are allowed to fail without consequence
ExecStartPre=-/usr/bin/docker kill apache.%i
ExecStartPre=-/usr/bin/docker rm apache.%i
ExecStartPre=/usr/bin/docker pull user_name/apache
ExecStart=/usr/bin/docker run --name apache.%i -p ${COREOS_PRIVATE_IPV4}:%i:80 \
user_name/apache /usr/sbin/apache2ctl -D FOREGROUND

# Stop
ExecStop=/usr/bin/docker stop apache.%i

[X-Fleet]
# Don't schedule on the same machine as other Apache instances
Conflicts=apache@*.service

Одна из модификаций, которую мы здесь сделали, - это использование закрытого интерфейса вместо открытого интерфейса. Поскольку всем нашим экземплярам Apache будет передаваться трафикthrough через обратный прокси-сервер Nginx вместо обработки соединений из открытого Интернета, это хорошая идея. Помните, что если вы используете частный интерфейс в DigitalOcean, то на сервере, который вы запускали, должен быть установлен флаг «частной сети» при создании.

Также не забудьте изменитьuser_name для ссылки на ваше имя пользователя Docker Hub, чтобы правильно загрузить файл Docker.

Создание файла модуля шаблона Sidekick

Теперь мы сделаем то же самое для сервиса sidekick. Эту мы немного изменим в ожидании информации, которая нам понадобится позже.

Откройте файл шаблона в вашем редакторе:

vim templates/[email protected]

Мы будем использовать следующую информацию в этом файле:

[Unit]
Description=Apache web server on port %i etcd registration

# Requirements
Requires=etcd.service
Requires=apache@%i.service

# Dependency ordering and binding
After=etcd.service
After=apache@%i.service
BindsTo=apache@%i.service

[Service]

# Get CoreOS environmental variables
EnvironmentFile=/etc/environment

# Start
## Test whether service is accessible and then register useful information
ExecStart=/bin/bash -c '\
  while true; do \
    curl -f ${COREOS_PRIVATE_IPV4}:%i; \
    if [ $? -eq 0 ]; then \
      etcdctl set /services/apache/${COREOS_PRIVATE_IPV4} \'${COREOS_PRIVATE_IPV4}:%i\' --ttl 30; \
    else \
      etcdctl rm /services/apache/${COREOS_PRIVATE_IPV4}; \
    fi; \
    sleep 20; \
  done'

# Stop
ExecStop=/usr/bin/etcdctl rm /services/apache/${COREOS_PRIVATE_IPV4}

[X-Fleet]
# Schedule on the same machine as the associated Apache service
MachineOf=apache@%i.service

Вышеуказанная конфигурация несколько отличается от конфигурации, приведенной в предыдущем руководстве. Мы скорректировали значение, установленное командойetcdctl set. Вместо передачи объекта JSON мы устанавливаем простую комбинацию IP-адрес + порт. Таким образом, мы можем прочитать это значение напрямую, чтобы найти информацию о соединении, необходимую для доступа к этой услуге.

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

Создайте свои услуги

Теперь давайте создадим два экземпляра этих сервисов.

Во-первых, давайте создадим символические ссылки. Перейдите в созданный вами каталог~/instances и укажите ссылку, чтобы определить порты, на которых они будут работать. Мы хотим запустить один сервис на порту 7777, а другой на порту 8888:

cd ~/instances
ln -s ../templates/[email protected] [email protected]
ln -s ../templates/[email protected] [email protected]
ln -s ../templates/[email protected] [email protected]
ln -s ../templates/[email protected] [email protected]

Теперь мы можем запустить эти службы, передав каталог~/instances вfleet:

fleetctl start ~/instances/*

После запуска ваших экземпляров (это может занять несколько минут) вы должны увидеть записиetcd, сделанные вашими помощниками:

etcdctl ls --recursive /
/coreos.com
/coreos.com/updateengine
/coreos.com/updateengine/rebootlock
/coreos.com/updateengine/rebootlock/semaphore
/services
/services/apache
/services/apache/10.132.249.206
/services/apache/10.132.249.212

Если вы спросите значение одной из этих записей, вы увидите, что вы получаете IP-адрес и номер порта:

etcdctl get /services/apache/10.132.249.206
10.132.249.206:8888

Вы можете использоватьcurl, чтобы получить страницу и убедиться, что она работает правильно. Это будет работать только на вашем компьютере, если вы настроили службу для использования частных сетей:

curl 10.132.249.206:8888

Running from Docker on CoreOS

Теперь у нас есть настроенная бэкэнд-инфраструктура. Наш следующий шаг - познакомиться сconfd, чтобы мы могли отслеживать местоположение/services/apache вetcd на предмет изменений и каждый раз перенастраивать Nginx.

Создание контейнера Nginx

Мы запустим контейнер Nginx из той же базы Ubuntu 14.04, которую мы использовали для сервисов Apache.

Установка программного обеспечения

Запустите новый контейнер, набрав:

docker run -i -t ubuntu:14.04 /bin/bash

Обновите локальный кеш пакетовapt и установите Nginx. Нам также необходимо установитьcurl, так как базовый образ не включает его, и он нам нужен, чтобы получить стабильный пакетconfd с GitHub на мгновение:

apt-get update
apt-get install nginx curl -y

Теперь мы можем перейти кreleases page дляconfd на GitHub в наших браузерах. Нам нужно найти ссылку на последнюю стабильную версию. На момент написания этоv0.5.0, но это могло измениться. Щелкните правой кнопкой мыши ссылку для версии инструмента для Linux и выберите «скопировать адрес ссылки» или любой другой доступный вариант.

Теперь, вернувшись в свой контейнер Docker, используйте скопированный URL для загрузки приложения. Мы поместим это в каталог/usr/local/bin. Нам нужно выбратьconfd в качестве выходного файла:

cd /usr/local/bin
curl -L https://github.com/kelseyhightower/confd/releases/download/v0.5.0/confd-0.5.0<^>-linux-amd64 -o confd

Теперь сделайте файл исполняемым, чтобы мы могли использовать его в нашем контейнере:

chmod +x confd

Мы также должны воспользоваться этой возможностью, чтобы создать структуру конфигурации, которую ожидаетconfd. Это будет в каталоге/etc:

mkdir -p /etc/confd/{conf.d,templates}

Создайте конфигурационный файл Confd для чтения значений Etcd

Теперь, когда у нас установлены наши приложения, мы должны приступить к настройкеconfd. Мы начнем с создания файла конфигурации или файла ресурсов шаблона.

Файлы конфигурации вconfd используются для настройки службы для проверки определенных значенийetcd и инициирования действий при обнаружении изменений. Они используют формат файлаTOML, который прост в использовании и довольно интуитивно понятен.

Начнем с создания файла в каталоге конфигурации с именемnginx.toml:

vi /etc/confd/conf.d/nginx.toml

Мы создадим наш конфигурационный файл здесь. Добавьте следующую информацию:

[template]

# The name of the template that will be used to render the application's configuration file
# Confd will look in `/etc/conf.d/templates` for these files by default
src = "nginx.tmpl"

# The location to place the rendered configuration file
dest = "/etc/nginx/sites-enabled/app.conf"

# The etcd keys or directory to watch.  This is where the information to fill in
# the template will come from.
keys = [ "/services/apache" ]

# File ownership and mode information
owner = "root"
mode = "0644"

# These are the commands that will be used to check whether the rendered config is
# valid and to reload the actual service once the new config is in place
check_cmd = "/usr/sbin/nginx -t"
reload_cmd = "/usr/sbin/service nginx reload"

Приведенный выше файл содержит комментарии, поясняющие некоторые основные идеи, но мы можем рассмотреть варианты, которые у вас есть ниже:

директива Необходимые? Type Описание

src

Yes

строка

Имя шаблона, который будет использоваться для отображения информации. Если он находится за пределами/etc/confd/templates, следует использовать весь путь.

dest

Yes

строка

Местоположение файла, в котором должен быть помещен отрисованный файл конфигурации.

keys

Yes

Массив строк

Ключиetcd, необходимые для правильного отображения шаблона. Это может быть каталог, если шаблон настроен для обработки дочерних ключей.

владелец

No

строка

Имя пользователя, которому будет предоставлен владелец визуализированного файла конфигурации.

группа

No

строка

Группа, которой будет предоставлено групповое владение созданным файлом конфигурации.

mode

No

строка

Восьмеричный режим разрешений, который должен быть установлен для визуализированного файла.

check_cmd

No

строка

Команда, которую следует использовать для проверки синтаксиса визуализированного файла конфигурации.

reload_cmd

No

строка

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

префикс

No

строка

Часть иерархииetcd, которая предшествует ключам в директивеkeys. Это можно использовать, чтобы сделать файл.toml более гибким.

Созданный нами файл сообщает нам несколько важных вещей о том, как будет работать наш экземплярconfd. Наш контейнер Nginx будет использовать шаблон, хранящийся в/etc/confd/templates/nginx.conf.tmpl, для рендеринга файла конфигурации, который будет помещен в/etc/nginx/sites-enabled/app.conf. Для файла будет предоставлен набор разрешений0644, а право собственности будет передано пользователю root.

Приложениеconfd будет искать изменения в узле/services/apache. Когда будет замечено изменение,confd запросит новую информацию в этом узле. Затем он отобразит новую конфигурацию для Nginx. Он проверит файл конфигурации на наличие синтаксических ошибок и перезагрузит службу Nginx после того, как файл будет на месте.

Теперь у нас есть созданный файл ресурсов шаблона. Мы должны поработать с самим файлом шаблона, который будет использоваться для рендеринга нашего файла конфигурации Nginx.

Создать файл шаблона Confd

Для нашего файла шаблона мы будем использовать пример изGitHub documentation проектаconfd, чтобы начать работу.

Создайте файл, на который мы ссылались в нашем файле конфигурации выше. Поместите этот файл в наш каталогtemplates:

vi /etc/confd/templates/nginx.tmpl

В этом файле мы просто воссоздаем стандартный файл конфигурации обратного прокси-сервера Nginx. Однако мы будем использовать некоторый синтаксис шаблонов Go, чтобы заменить некоторую информацию, которуюconfd получает отetcd.

Сначала мы настраиваем блок с «восходящими» серверами. Этот раздел используется для определения пула серверов, на которые Nginx может отправлять запросы. Формат обычно такой:

upstream pool_name {
    server server_1_IP:port_num;
    server server_2_IP:port_num;
    server server_3_IP:port_num;
}

Это позволяет нам передавать запросыpool_name, и Nginx выберет один из определенных серверов для передачи запроса.

Идея нашего файла шаблона состоит в том, чтобы проанализироватьetcd на предмет IP-адресов и номеров портов наших веб-серверов Apache. Поэтому вместо статического определения наших вышестоящих серверов мы должны динамически заполнять эту информацию при рендеринге файла. Мы можем сделать это, используяGo templates для динамического содержимого.

Для этого мы вместо этого будем использовать это как наш блок:

upstream apache_pool {
{{ range getvs "/services/apache/*" }}
    server {{ . }};
{{ end }}
}

Давайте на мгновение объясним, что происходит. Мы открыли блок для определения восходящего пула серверов под названиемapache_pool. Внутри мы указываем, что начинаем некоторый код языка Go, используя двойные скобки.

В этих скобках мы указываем конечную точкуetcd, в которой хранятся интересующие нас значения. Мы используемrange, чтобы сделать список повторяемым.

Мы используем это, чтобы передать все записи, полученные из-под местоположения/services/apache вetcd, в блокrange. Затем мы можем получить значение ключа в текущей итерации, используя одну точку внутри «\ {\ {» и «}}», которые указывают на вставленное значение. Мы используем это в цикле диапазона для заполнения пула серверов. Наконец, мы завершаем цикл директивой{{ end }}.

Note: не забудьте добавить точку с запятой после директивыserver внутри цикла. Забывание этого приведет к нерабочей конфигурации.

После настройки пула серверов мы можем просто использовать прокси-проход для направления всех соединений в этот пул. Это будет просто стандартный блок сервера в качестве обратного прокси. Единственное, что следует отметить, этоaccess_log, который использует настраиваемый формат, который мы сейчас создадим:

upstream apache_pool {
{{ range getvs "/services/apache/*" }}
    server {{ . }};
{{ end }}
}

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    access_log /var/log/nginx/access.log upstreamlog;

    location / {
        proxy_pass http://apache_pool;
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Это будет отвечать на все подключения на порту 80 и передавать их пулу серверов вapache_pool, который создается при просмотре записейetcd.

Пока мы имеем дело с этим аспектом службы, нам следует удалить файл конфигурации Nginx по умолчанию, чтобы впоследствии мы не столкнулись с конфликтами. Мы просто удалим символическую ссылку, включив конфигурацию по умолчанию:

rm /etc/nginx/sites-enabled/default

Сейчас также самое время настроить формат журнала, на который мы ссылаемся в нашем файле шаблона. Это должно быть в блокеhttp конфигурации, который доступен в основном файле конфигурации. Откройте это сейчас:

vi /etc/nginx/nginx.conf

Мы добавим директивуlog_format для определения информации, которую мы хотим регистрировать. Он будет регистрировать клиента, который посещает, а также внутренний сервер, на который передается запрос. Мы запишем некоторые данные о времени, которое занимают эти процедуры:

. . .
http {
    ##
    # Basic Settings
    ##
    log_format upstreamlog '[$time_local] $remote_addr passed to: $upstream_addr: $request Upstream Response Time: $upstream_response_time Request time: $request_time';

    sendfile on;
    . . .

Сохраните и закройте файл, когда вы закончите.

Создание скрипта для запуска Confd

Нам нужно создать файл сценария, который будет вызыватьconfd с нашим файлом ресурсов шаблона и нашим файлом шаблона в подходящее время.

Сценарий должен сделать две вещи, чтобы наш сервис работал правильно:

  • Он должен запускаться при запуске контейнера для настройки начальных настроек Nginx на основе текущего состояния серверной инфраструктуры.

  • Он должен продолжать следить за изменениями в регистрацииetcd для серверов Apache, чтобы он мог перенастроить Nginx на основе доступных внутренних серверов.

Мы получим наш скрипт изMarcel de Graaf’s GitHub page. Это красивый и простой скрипт, который выполняетexactly то, что нам нужно. Мы внесем лишь несколько незначительных изменений в наш сценарий.

Разместим этот скрипт рядом с исполняемым файломconfd. Назовем этоconfd-watch:

vi /usr/local/bin/confd-watch

Мы начнем с обычного заголовкаbash, чтобы определить нужный нам интерпретатор. Затем мы установим некоторые параметрыbash, чтобы сценарий сразу же отказывался, если что-то пойдет не так. Он вернет значение последней команды, которая потерпит неудачу или запустится.

#!/bin/bash

set -eo pipefail

Далее мы хотим установить некоторые переменные. Используя подстановку параметраbash, мы установим значения по умолчанию, но добавим некоторую гибкость, позволяющую нам переопределить жестко запрограммированные значения при вызове скрипта. Это в основном просто настроит каждый компонент адреса подключения независимо, а затем сгруппирует их вместе, чтобы получить полный требуемый адрес.

Подстановка параметра создается с использованием этого синтаксиса:${var_name:-default_value}. Он имеет свойство использовать значениеvar_name, если оно задано, а не null, в противном случае по умолчанию используетсяdefault_value.

По умолчанию мы используем значения, которыеetcd ожидает по умолчанию. Это позволит нашему сценарию нормально функционировать без дополнительной информации, но мы можем при необходимости настроить его при вызове сценария:

#!/bin/bash

set -eo pipefail

export ETCD_PORT=${ETCD_PORT:-4001}
export HOST_IP=${HOST_IP:-172.17.42.1}
export ETCD=$HOST_IP:$ETCD_PORT

Теперь мы будем использоватьconfd для рендеринга начальной версии файла конфигурации Nginx, читая значения изetcd, которые доступны при вызове этого скрипта. Мы будем использовать циклuntil, чтобы постоянно пытаться построить начальную конфигурацию.

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

Фактическая командаconfd, которую мы вызываем, выполняется один раз и затем завершается. Это значит, что мы можем подождать 5 секунд до следующего запуска, чтобы наши серверы могли зарегистрироваться. Мы подключаемся к полной переменнойETCD, которую мы создали с использованием значений по умолчанию или переданных в параметрах, и мы используем файл ресурсов шаблона для определения поведения того, что мы хотим сделать:

#!/bin/bash

set -eo pipefail

export ETCD_PORT=${ETCD_PORT:-4001}
export HOST_IP=${HOST_IP:-172.17.42.1}
export ETCD=$HOST_IP:$ETCD_PORT

echo "[nginx] booting container. ETCD: $ETCD"

# Try to make initial configuration every 5 seconds until successful
until confd -onetime -node $ETCD -config-file /etc/confd/conf.d/nginx.toml; do
    echo "[nginx] waiting for confd to create initial nginx configuration"
    sleep 5
done

После того, как начальная конфигурация была установлена, следующая задача нашего сценария должна заключаться в создании механизма для непрерывного опроса. Мы хотим убедиться, что любые будущие изменения будут обнаружены, чтобы Nginx был обновлен.

Для этого мы можем еще раз вызватьconfd. На этот раз мы хотим установить непрерывный интервал опроса и поместить процесс в фоновом режиме, чтобы он работал бесконечно. Мы передадим ту же информацию о соединенииetcd и тот же файл ресурсов шаблона, поскольку наша цель остается той же.

После перевода процессаconfd в фоновый режим мы можем безопасно запустить Nginx, используя созданный файл конфигурации. Так как этот скрипт будет называться нашей командой Docker «выполнить», нам нужно держать его запущенным на переднем плане, чтобы контейнер не выходил из этой точки. Мы можем сделать это, просто следя за журналами, предоставляя нам доступ ко всей информации, которую мы регистрировали:

#!/bin/bash

set -eo pipefail

export ETCD_PORT=${ETCD_PORT:-4001}
export HOST_IP=${HOST_IP:-172.17.42.1}
export ETCD=$HOST_IP:$ETCD_PORT

echo "[nginx] booting container. ETCD: $ETCD."

# Try to make initial configuration every 5 seconds until successful
until confd -onetime -node $ETCD -config-file /etc/confd/conf.d/nginx.toml; do
    echo "[nginx] waiting for confd to create initial nginx configuration."
    sleep 5
done

# Put a continual polling `confd` process into the background to watch
# for changes every 10 seconds
confd -interval 10 -node $ETCD -config-file /etc/confd/conf.d/nginx.toml &
echo "[nginx] confd is now monitoring etcd for changes..."

# Start the Nginx service using the generated config
echo "[nginx] starting nginx service..."
service nginx start

# Follow the logs to allow the script to continue running
tail -f /var/log/nginx/*.log

Когда вы закончите с этим, сохраните и закройте файл.

Последнее, что нам нужно сделать, это сделать скрипт исполняемым:

chmod +x /usr/local/bin/confd-watch

Выйдите из контейнера сейчас, чтобы вернуться к хост-системе:

exit

Зафиксируйте и отправьте контейнер

Теперь мы можем зафиксировать контейнер и перенести его в Docker Hub, чтобы наши машины могли его разгрузить.

Узнайте идентификатор контейнера:

docker ps -l
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                          PORTS               NAMES
de4f30617499        ubuntu:14.04        "/bin/bash"         22 hours ago        Exited (0) About a minute ago                       stupefied_albattani

Выделенная строка - это ID контейнера, который нам нужен. Зафиксируйте контейнер, используя этот идентификатор вместе с вашим именем пользователя Docker Hub и именем, которое вы хотели бы использовать для этого образа. Мы собираемся использовать имя «nginx_lb» в этом руководстве:

docker commit de4f30617499 user_name/nginx_lb

При необходимости войдите в свою учетную запись Docker Hub:

docker login

Теперь вам нужно подтолкнуть ваш зафиксированный образ, чтобы другие хосты могли его снять при необходимости:

docker push user_name/nginx_lb

Создайте файл статического модуля Nginx

Следующим шагом является создание файла модуля, который запустит только что созданный контейнер. Это позволит нам использоватьfleet для управления процессом.

Поскольку это не будет шаблон, мы поместим его в каталог~/static, который мы создали в начале этого каталога:

vim static/nginx_lb.service

Мы начнем со стандартного раздела[Unit], чтобы описать сервис и определить зависимости и порядок:

[Unit]
Description=Nginx load balancer for web server backends

# Requirements
Requires=etcd.service
Requires=docker.service

# Dependency ordering
After=etcd.service
After=docker.service

Затем нам нужно определить часть файла[Service]. Мы установим тайм-аут на ноль и снова изменим killmode, как мы делали с сервисными файлами Apache. Мы снова извлечем файл среды, чтобы получить доступ к общедоступным и частным IP-адресам хоста, на котором работает этот контейнер.

Затем мы очистим нашу среду, чтобы убедиться, что все предыдущие версии этого контейнера уничтожены и удалены. Мы раскрываем только что созданный контейнер, чтобы всегда иметь самую последнюю версию.

Наконец, мы запустим контейнер. Это включает в себя запуск контейнера, присвоение ему имени, на которое мы ссылались в командах remove и kill, и передачу ему публичного IP-адреса хоста, на котором он запущен, для сопоставления с портом 80. Мы вызываем сценарийconfd-watch, который мы написали, как команду запуска.

[Unit]
Description=Nginx load balancer for web server backends

# Requirements
Requires=etcd.service
Requires=docker.service

# Dependency ordering
After=etcd.service
After=docker.service

[Service]
# Let the process take awhile to start up (for first run Docker containers)
TimeoutStartSec=0

# Change killmode from "control-group" to "none" to let Docker remove
# work correctly.
KillMode=none

# Get CoreOS environmental variables
EnvironmentFile=/etc/environment

# Pre-start and Start
## Directives with "=-" are allowed to fail without consequence
ExecStartPre=-/usr/bin/docker kill nginx_lb
ExecStartPre=-/usr/bin/docker rm nginx_lb
ExecStartPre=/usr/bin/docker pull user_name/nginx_lb
ExecStart=/usr/bin/docker run --name nginx_lb -p ${COREOS_PUBLIC_IPV4}:80:80 \
user_name/nginx_lb /usr/local/bin/confd-watch

Теперь все, что нам нужно разобраться, это команда остановки и направления планированияfleet. Мы хотим, чтобы этот контейнер запускался только на хостах, на которых не запущены другие экземпляры балансировки нагрузки или серверы Apache. Это позволит нашему сервису эффективно распределить нагрузку:

[Unit]
Description=Nginx load balancer for web server backends

# Requirements
Requires=etcd.service
Requires=docker.service

# Dependency ordering
After=etcd.service
After=docker.service

[Service]
# Let the process take awhile to start up (for first run Docker containers)
TimeoutStartSec=0

# Change killmode from "control-group" to "none" to let Docker remove
# work correctly.
KillMode=none

# Get CoreOS environmental variables
EnvironmentFile=/etc/environment

# Pre-start and Start
## Directives with "=-" are allowed to fail without consequence
ExecStartPre=-/usr/bin/docker kill nginx_lb
ExecStartPre=-/usr/bin/docker rm nginx_lb
ExecStartPre=/usr/bin/docker pull user_name/nginx_lb
ExecStart=/usr/bin/docker run --name nginx_lb -p ${COREOS_PUBLIC_IPV4}:80:80 \
user_name/nginx_lb /usr/local/bin/confd-watch

# Stop
ExecStop=/usr/bin/docker stop nginx_lb

[X-Fleet]
Conflicts=nginx.service
Conflicts=apache@*.service

Сохраните и закройте файл, когда вы закончите.

Запуск балансировщика нагрузки Nginx

У вас уже должно быть два экземпляра Apache, запущенных ранее в этом руководстве. Вы можете проверить, набрав:

fleetctl list-units
UNIT                MACHINE             ACTIVE  SUB
[email protected]   197a1662.../10.132.249.206  active  running
[email protected]   04856ec4.../10.132.249.212  active  running
[email protected]     197a1662.../10.132.249.206  active  running
[email protected]     04856ec4.../10.132.249.212  active  running

Вы также можете дважды проверить, правильно ли они регистрируются вetcd, набрав:

etcdctl ls --recursive /services/apache
/services/apache/10.132.249.206
/services/apache/10.132.249.212

Теперь мы можем попытаться запустить наш сервис Nginx:

fleetctl start ~/static/nginx_lb.service
Unit nginx_lb.service launched on 96ec72cf.../10.132.248.177

Запуск службы может занять около минуты, в зависимости от того, сколько времени потребуется, чтобы изображение было снято. После запуска, если вы проверите журналы с помощью командыfleetctl journal, вы сможете увидеть некоторую информацию журнала изconfd. Это должно выглядеть примерно так:

fleetctl journal nginx_lb.service
-- Logs begin at Mon 2014-09-15 14:54:05 UTC, end at Tue 2014-09-16 17:13:58 UTC. --
Sep 16 17:13:48 lala1 docker[15379]: 2014-09-16T17:13:48Z d7974a70e976 confd[14]: INFO Target config /etc/nginx/sites-enabled/app.conf out of sync
Sep 16 17:13:48 lala1 docker[15379]: 2014-09-16T17:13:48Z d7974a70e976 confd[14]: INFO Target config /etc/nginx/sites-enabled/app.conf has been updated
Sep 16 17:13:48 lala1 docker[15379]: [nginx] confd is monitoring etcd for changes...
Sep 16 17:13:48 lala1 docker[15379]: [nginx] starting nginx service...
Sep 16 17:13:48 lala1 docker[15379]: 2014-09-16T17:13:48Z d7974a70e976 confd[33]: INFO Target config /etc/nginx/sites-enabled/app.conf in sync
Sep 16 17:13:48 lala1 docker[15379]: ==> /var/log/nginx/access.log <==
Sep 16 17:13:48 lala1 docker[15379]: ==> /var/log/nginx/error.log <==
Sep 16 17:13:58 lala1 docker[15379]: 2014-09-16T17:13:58Z d7974a70e976 confd[33]: INFO /etc/nginx/sites-enabled/app.conf has md5sum a8517bfe0348e9215aa694f0b4b36c9b should be 33f42e3b7cc418f504237bea36c8a03e
Sep 16 17:13:58 lala1 docker[15379]: 2014-09-16T17:13:58Z d7974a70e976 confd[33]: INFO Target config /etc/nginx/sites-enabled/app.conf out of sync
Sep 16 17:13:58 lala1 docker[15379]: 2014-09-16T17:13:58Z d7974a70e976 confd[33]: INFO Target config /etc/nginx/sites-enabled/app.conf has been updated

Как видите,confd смотрел наetcd для своей начальной конфигурации. Затем он запустилnginx. После этого мы можем увидеть строки, в которых записиetcd были повторно оценены и был создан новый файл конфигурации. Если вновь созданный файл не соответствуетmd5sum файла на месте, файл отключается и служба перезагружается.

Это позволяет нашей службе балансировки нагрузки в конечном итоге отслеживать наши серверы Apache. Если кажется, чтоconfd постоянно обновляется, это может быть связано с тем, что ваши экземпляры Apache слишком часто обновляют свой TTL. Чтобы избежать этого, вы можете увеличить значения sleep и TTL в шаблоне сообщника.

Чтобы увидеть балансировщик нагрузки в действии, вы можете запросить файл/etc/environments у хоста, на котором запущена служба Nginx. Он содержит публичный IP-адрес хоста. Если вы хотите улучшить эту конфигурацию, рассмотрите возможность запуска вспомогательной службы, которая регистрирует эту информацию с помощьюetcd, как мы это сделали для экземпляров Apache:

fleetctl ssh nginx_lb cat /etc/environment
COREOS_PRIVATE_IPV4=10.132.248.177
COREOS_PUBLIC_IPV4=104.131.16.222

Теперь, если мы перейдем к общедоступному IPv4-адресу в нашем браузере, мы должны увидеть страницу, которую мы настроили в наших экземплярах Apache:

Apache index page

Теперь, если вы посмотрите на свои журналы снова, вы сможете увидеть информацию, указывающую, какой бэкэнд-сервер действительно передал запрос:

fleetctl journal nginx_lb
. . .
Sep 16 18:04:38 lala1 docker[18079]: 2014-09-16T18:04:38Z 51c74658196c confd[28]: INFO Target config /etc/nginx/sites-enabled/app.conf in sync
Sep 16 18:04:48 lala1 docker[18079]: 2014-09-16T18:04:48Z 51c74658196c confd[28]: INFO Target config /etc/nginx/sites-enabled/app.conf in sync
Sep 16 18:04:48 lala1 docker[18079]: [16/Sep/2014:18:04:48 +0000] 108.29.37.206 passed to: 10.132.249.212:8888: GET / HTTP/1.1 Upstream Response Time: 0.003 Request time: 0.003

Заключение

Как видите, можно настроить свои службы так, чтобы проверятьetcd для получения сведений о конфигурации. Такие инструменты, какconfd, могут сделать этот процесс относительно простым, позволяя непрерывно опрашивать важные записи.

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

Related