
Установка Consul кластера в Unix/Linux
Consul — очередной продукт компании HashiCorp который имеет несколько компонентов, но в целом это распределенная, высокодоступная система обнаружения и конфигурирования служб в вашей инфраструктуре.
Консул предоставляет множество различных функций, которые используются для обеспечения согласованной и доступной информации о вашей инфраструктуре. Сюда входят механизмы обнаружения сервисов и узлов, система тегов, проверки работоспособности (хелзчеки) и многое другое.
Я описывал установку consul в моей статье:
А сейчас поговорим как можно собрать кластер из consul.
Установка Consul кластера
Consul кластер представляет собой сеть связанных узлов, на которых запущены сервисы, зарегистрированные в discovery. Consul гарантирует, что информация о кластере будет распространена по всем участникам кластера и доступна по запросу. Также реализована поддержка не только однорангового, но и многорангового, разделенного по зонам, кластера, которые в терминологии Consul называются датацентрами. При помощи Consul можно работать как с конкретным датацентром, так и выполнять действия над любым другим. Датацентры не изолированы друг от друга в рамках discovery. Агент в одном ДЦ может получить информацию из другого ДЦ, что может помочь в построении эффективного решения для распределенной системы.
Агенты Consul, запущенные в режиме server, помимо своей основной роли, получают еще и роль потенциального лидера кластера. Рекомендуется использовать в кластере не менее трех агентов в режиме server для обеспечения отказоустойчивости. Использования режима server не накладывает никаких ограничений на основную функциональность агента.
При вводе нового узла в кластер, нам необходимо знать адрес любого узла в кластере. Выполнив команду:
$ consul join node_ip_address
Тем самым, я регестрирую новый узел в консул-кластере, яерез некоторое время, информация о состоянии всего кластера будет доступна этому узлу. Соответственно, новый узел окажется доступным для запросов от остальных узлов.
Типы узлов: internal, external
В Consul мы можем зарегистрировать наш сервис двумя способами:
- Использовать HTTP API или конфигурационный файл агента, но только в том случае если ваш сервис может общаться с Consul самостоятельно.
- Зарегистрировать сервис как 3d-party компонент, в случае если сервис не может общаться с Consul.
Рассмотрим оба случая чуть подробнее.
При помощи HTTP API, предоставляемого Consul, есть возможность сделать корректную регистрацию компонента и удаление сервиса в discovery. Помимо этих двух состояний, можно использовать состояние maintenance. В этом режиме сервис помечается как недоступный и перестает отображаться в DNS и API-запросах.
Для установки consul, я написал скрипт:
# vim install_consul.sh
Который имеет следующий код:
#!/bin/bash -x # CREATED: # vitaliy.natarov@yahoo.com # # Unix/Linux blog: # http://linux-notes.org # Vitaliy Natarov # function install_consul () { # if [ -f /etc/centos-release ] || [ -f /etc/redhat-release ] ; then #update OS yum update &> /dev/null -y && yum upgrade &> /dev/null -y # if ! type -path "wget" > /dev/null 2>&1; then yum install wget &> /dev/null -y; fi if ! type -path "curl" > /dev/null 2>&1; then yum install curl &> /dev/null -y; fi if ! type -path "unzip" > /dev/null 2>&1; then yum install unzip &> /dev/null -y; fi if [ -z "`rpm -qa | grep redhat-lsb-core`" ]; then yum install redhat-lsb-core &> /dev/null -y fi OS=$(lsb_release -ds|cut -d '"' -f2|awk '{print $1}') OS_MAJOR_VERSION=$(sed -rn 's/.*([0-9]).[0-9].*/\1/p' /etc/redhat-release) OS_MINOR_VERSION=$(cat /etc/redhat-release | cut -d"." -f2| cut -d " " -f1) Bit_OS=$(uname -m | sed 's/x86_//;s/i[3-6]86/32/') echo "$OS-$OS_MAJOR_VERSION.$OS_MINOR_VERSION with $Bit_OS bit arch" # site="https://releases.hashicorp.com/consul/" Latest_consul_version=$(curl -s "$site" --list-only | grep -E "consul_" | head -n1| cut -d ">" -f2| cut -d "<" -f1| cut -c8-) URL_with_latest_consul_package=$site$Latest_consul_version # if [ "`uname -m`" == "x86_64" ]; then Latest_consul_package=$(curl -s "$URL_with_latest_consul_package/" --list-only |grep -E "consul_" | grep -E "linux_amd64"|cut -d ">" -f2| cut -d "<" -f1) Current_link_to_archive=$URL_with_latest_consul_package/$Latest_consul_package elif [ "`uname -m`" == "i386|i686" ]; then Latest_consul_package=$(curl -s "$URL_with_latest_consul_package/" --list-only |grep -E "consul_" | grep -Ev "(SHA256SUMS|windows)"| grep -E "linux_386"|cut -d ">" -f2| cut -d "<" -f1) Current_link_to_archive=$URL_with_latest_consul_package/$Latest_consul_package fi echo $Current_link_to_archive cd /usr/local/src/ && wget $Current_link_to_archive &> /dev/null unzip $Latest_consul_package rm -rf /usr/local/src/$Latest_consul_package* yes|mv -f /usr/local/src/consul /usr/local/bin/consul chmod +x /usr/local/bin/consul elif [ -f /etc/fedora_version ]; then if ! type -path "wget" > /dev/null 2>&1; then apt-get install wget &> /dev/null -y; fi if ! type -path "curl" > /dev/null 2>&1; then apt-get install curl &> /dev/null -y; fi if ! type -path "unzip" > /dev/null 2>&1; then apt-get install unzip &> /dev/null -y; fi echo "Fedora"; OS=$(lsb_release -ds|cut -d '"' -f2|awk '{print $1}') OS_MAJOR_VERSION=`sed -rn 's/.*([0-9])\.[0-9].*/\1/p' /etc/fedora_version` OS_MINOR_VERSION=`sed -rn 's/.*[0-9].([0-9]).*/\1/p' /etc/fedora_version` Bit_OS=$(uname -m | sed 's/x86_//;s/i[3-6]86/32/') echo "$OS-$OS_MAJOR_VERSION.$OS_MINOR_VERSION($CODENAME) with $Bit_OS bit arch" # site="https://releases.hashicorp.com/consul/" Latest_consul_version=$(curl -s "$site" --list-only | grep -E "consul_" | head -n1| cut -d ">" -f2| cut -d "<" -f1| cut -c8-) URL_with_latest_consul_package=$site$Latest_consul_version # if [ "`uname -m`" == "x86_64" ]; then Latest_consul_package=$(curl -s "$URL_with_latest_consul_package/" --list-only |grep -E "consul_" | grep -E "linux_amd64"|cut -d ">" -f2| cut -d "<" -f1) Current_link_to_archive=$URL_with_latest_consul_package/$Latest_consul_package elif [ "`uname -m`" == "i386|i686" ]; then Latest_consul_package=$(curl -s "$URL_with_latest_consul_package/" --list-only |grep -E "consul_" | grep -Ev "(SHA256SUMS|windows)"| grep -E "linux_386"|cut -d ">" -f2| cut -d "<" -f1) Current_link_to_archive=$URL_with_latest_consul_package/$Latest_consul_package fi echo $Current_link_to_archive cd /usr/local/src/ && wget $Current_link_to_archive &> /dev/null unzip $Latest_consul_package rm -rf /usr/local/src/$Latest_consul_package* yes|mv -f /usr/local/src/consul /usr/local/bin/consul chmod +x /usr/local/bin/consul # elif [ -f /etc/debian_version ]; then #update OS apt-get update &> /dev/null -y && apt-get upgrade &> /dev/null -y yes| apt-get install apt-transport-https &> /dev/null # if ! type -path "wget" > /dev/null 2>&1; then yes| apt-get install wget &> /dev/null; fi if ! type -path "curl" > /dev/null 2>&1; then yes| apt-get install curl &> /dev/null; fi if ! type -path "unzip" > /dev/null 2>&1; then yes| apt-get install unzip &> /dev/null; fi # echo "Debian/Ubuntu/Kali Linux"; OS=$(lsb_release -ds|cut -d '"' -f2|awk '{print $1}') OS_MAJOR_VERSION=`sed -rn 's/.*([0-9])\.[0-9].*/\1/p' /etc/debian_version` OS_MINOR_VERSION=`sed -rn 's/.*[0-9].([0-9]).*/\1/p' /etc/debian_version` Bit_OS=$(uname -m | sed 's/x86_//;s/i[3-6]86/32/') # CODENAME=`cat /etc/*-release | grep "VERSION="` CODENAME=${CODENAME##*\(} CODENAME=${CODENAME%%\)*} echo "$OS-$OS_MAJOR_VERSION.$OS_MINOR_VERSION($CODENAME) with $Bit_OS bit arch" # site="https://releases.hashicorp.com/consul/" Latest_consul_version=$(curl -s "$site" --list-only | grep -E "consul_" | head -n1| cut -d ">" -f2| cut -d "<" -f1| cut -c8-) URL_with_latest_consul_package=$site$Latest_consul_version # if [ "`uname -m`" == "x86_64" ]; then Latest_consul_package=$(curl -s "$URL_with_latest_consul_package/" --list-only |grep -E "consul_" | grep -E "linux_amd64"|cut -d ">" -f2| cut -d "<" -f1) Current_link_to_archive=$URL_with_latest_consul_package/$Latest_consul_package elif [ "`uname -m`" == "i386|i686" ]; then Latest_consul_package=$(curl -s "$URL_with_latest_consul_package/" --list-only |grep -E "consul_" | grep -Ev "(SHA256SUMS|windows)"| grep -E "linux_386"|cut -d ">" -f2| cut -d "<" -f1) Current_link_to_archive=$URL_with_latest_consul_package/$Latest_consul_package fi echo $Current_link_to_archive cd /usr/local/src/ && wget $Current_link_to_archive &> /dev/null unzip $Latest_consul_package rm -rf /usr/local/src/$Latest_consul_package* yes|mv -f /usr/local/src/consul /usr/local/bin/consul chmod +x /usr/local/bin/consul elif [ -f /usr/sbin/system_profiler ]; then OS=$(uname) Mac_Ver=$(sw_vers -productVersion | awk -F '.' '{print $1 "." $2}') Bit_OS=$(uname -m | sed 's/x86_//;s/i[3-6]86/32/') echo "MacOS: $OS-$Mac_Ver with $Bit_OS bit arch" which -s brew if [[ $? != 0 ]] ; then # Install Homebrew ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" else # update homebrew brew update && brew upgrade fi Latest_consul_package=$(curl -s "$URL_with_latest_consul_package/" --list-only |grep -E "consul_" | grep -E "darwin_amd64"|cut -d ">" -f2| cut -d "<" -f1) Current_link_to_archive=$URL_with_latest_consul_package/$Latest_consul_package echo $Current_link_to_archive cd /usr/local/src/ && wget $Current_link_to_archive &> /dev/null unzip $Latest_consul_package rm -rf /usr/local/src/$Latest_consul_package* yes|mv -f /usr/local/src/consul /usr/local/bin/consul chmod +x /usr/local/bin/consul else OS=$(uname -s) VER=$(uname -r) echo 'OS=' $OS 'VER=' $VER fi } install_consul echo "========================================================================================================"; echo "================================================FINISHED================================================"; echo "========================================================================================================";
Тестировался на нескольких ОС — MacOSX, Debian 8, CentOS 6-7. Он возьмет самую новую версию ПО (возможно SRC) и выполнит установку (хотя это сложно назвать установкой, но тем не менее — все автоматически).
И так, имеется:
- Debian 8 — Имеет 192.168.13.175 IP.
- CentOS 7 — Имеет 192.168.13.219 IP.
- CentOS 6 — Имеет 192.168.13.218 IP.
И так, для своих испытаний, возьму несколько машин и создам из них consul кластер.
На всех машинах, я создал скрипт (что выше) и выполнил установку:
# bash install_consul.sh
PS: Если не установлен PATH, то пропишите в ~/.bash_profile:
PATH=$PATH:$HOME/.local/bin:$HOME/bin:/usr/local/bin/ export PATH
Агент может работать как в режиме клиента, так и в режиме сервера. Серверные узлы отвечают за выполнение консенсусного протокола и сохранение состояния кластера. Узлы-клиенты в основном не имеют состояния и в значительной степени зависят от узлов сервера.
Прежде чем кластер Consul начнет обслуживать запросы, узел сервера должен быть избран лидером. Таким образом, первые запущенные узлы обычно являются узлами сервера. Загрузочный процесс — это процесс объединения этих начальных узлов сервера в кластер.
Рекомендуемый способ загрузки — использовать параметр конфигурации «-bootstrap-expect». Этот параметр информирует consul о ожидаемом количестве узлов сервера и автоматически загружается, когда доступно много серверов. Чтобы предотвратить несоответствия и ситуации с «раздвоенным мозгом» (то есть кластеры, в которых несколько серверов считают себя лидером), все серверы должны либо указать одно и то же значение для «-bootstrap-expect» или вообще не указывать значения. Только серверы, которые задают значение, будут пытаться загружать кластер.
На первой ноде выполняем (Debian 8):
debian# consul agent -server -bootstrap-expect=1 \ -data-dir=/tmp/consul -node=agent-one -bind=172.20.20.10 \ -enable-script-checks=true -config-dir=/etc/consul.d
ИЛИ:
debian# consul agent \ -data-dir=/tmp/consul \ -node=consul-agent-one \ -bind=192.168.13.175 \ -enable-script-checks=true \ -config-dir=/etc/consul.d \ -bootstrap-expect=3 \ -client=0.0.0.0 \ -data-dir=/var/lib/consul \ -server \ -ui
Я использую 2-й вариант и тем самым, создам 3 сервера с репликацией. Данная конфигурация не сильно юзабильна, т.к вывод (я за лог) будет сыпатся на экран и после выхода из терминала, узел(ы) будет недоступен(пны). Решение — использовать запуск consul-а в бэкграунде. Для этого служит символ «&» и его стоит разместить в самом конце.
На 2-й ноде выполняем:
centos6# consul agent \ -data-dir=/tmp/consul \ -node=consul-agent-two \ -bind=192.168.13.219 \ -enable-script-checks=true \ -config-dir=/etc/consul.d \ -bootstrap-expect=3 \ -client=0.0.0.0 \ -data-dir=/var/lib/consul \ -server \ -ui &
На 3-й ноде выполняем:
centos7# consul agent \ -data-dir=/tmp/consul \ -node=consul-agent-three \ -bind=192.168.13.218 \ -enable-script-checks=true \ -config-dir=/etc/consul.d \ -bootstrap-expect=3 \ -client=0.0.0.0 \ -data-dir=/var/lib/consul \ -server \ -ui &
Идем дальше…
Присоединение хостов к consul кластеру
Теперь мы присоединим агенты между собой, для этого, на одной из нод выполняем (у меня это 1-я нода с Debian 8):
debain8$ consul join 192.168.13.219 Successfully joined cluster by contacting 1 nodes. debain8$ consul join 192.168.13.218 Successfully joined cluster by contacting 1 nodes.
Можно на каждом сервере, запустить команду и посмотреть все ли ноды видны между собой:
debian8# consul members Node Address Status Type Build Protocol DC Segment consul-agent-one 192.168.13.175:8301 alive server 1.0.2 2 dc1 <all> consul-agent-three 192.168.13.218:8301 alive server 1.0.2 2 dc1 <all> consul-agent-two 192.168.13.219:8301 alive server 1.0.2 2 dc1 <all> #
Или:
[root@localhost captain]# consul members Node Address Status Type Build Protocol DC Segment consul-agent-one 192.168.13.175:8301 alive server 1.0.2 2 dc1 <all> consul-agent-three 192.168.13.218:8301 alive server 1.0.2 2 dc1 <all> consul-agent-two 192.168.13.219:8301 alive server 1.0.2 2 dc1 <all> [root@localhost captain]#
Или:
[root@puppet-agent captain]# consul members Node Address Status Type Build Protocol DC Segment consul-agent-one 192.168.13.175:8301 alive server 1.0.2 2 dc1 <all> consul-agent-three 192.168.13.218:8301 alive server 1.0.2 2 dc1 <all> consul-agent-two 192.168.13.219:8301 alive server 1.0.2 2 dc1 <all> [root@puppet-agent captain]#
Как видно, все отлично у меня и работает должным образом.
Автоматическое объединение нод в consul кластер при запуске
В идеале, всякий раз, когда новый узел подымается в вашем датацентере (DC), он должен автоматически присоединяться к consul кластеру без вмешательства человека. Консул облегчает автосоединение, позволяя автоматически обнаруживать экземпляры с заданным ключом/значением тега:
- AWS — Для этой службый служит ключ retry_join_ec2
- Google Cloud — Для этой службый служит ключretry_join_gce
- Azure — Для этой службый служит ключ retry_join_azure
Это позволит новому узлу присоединиться к кластеру без какой-либо жестко запрограммированной конфигурации. Кроме того, вы можете присоединиться к кластеру при запуске, используя флаг -join или start_join с жестко закодированными адресами других известных consul агентов.
Выполнение запрос в consul кластере
Подобно запросам служб, у consul есть API для непосредственного обращения к самим узлам. Вы можете сделать это через DNS или HTTP API.
Для DNS API, служит следующая структура имен:
NAME.node.consul NAME.node.DATACENTER.consul
Где:
- NAME — название ноды в consul кластере.
- DATACENTER — название датацентра.
Если центр данных опущен, консул будет искать только локальный центр данных.
Например, на первом сервере, выполним:
root@debian:~# dig @127.0.0.1 -p 8600 consul-agent-two.node.consul ; <<>> DiG 9.9.5-9+deb8u14-Debian <<>> @127.0.0.1 -p 8600 consul-agent-two.node.consul ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 38156 ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;consul-agent-two.node.consul. IN A ;; ANSWER SECTION: consul-agent-two.node.consul. 0 IN A 192.168.13.219 ;; Query time: 19 msec ;; SERVER: 127.0.0.1#8600(127.0.0.1) ;; WHEN: Thu Dec 21 18:16:33 EET 2017 ;; MSG SIZE rcvd: 73 root@debian:~# dig @127.0.0.1 -p 8600 consul-agent-three.node.consul ; <<>> DiG 9.9.5-9+deb8u14-Debian <<>> @127.0.0.1 -p 8600 consul-agent-three.node.consul ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 35277 ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;consul-agent-three.node.consul. IN A ;; ANSWER SECTION: consul-agent-three.node.consul. 0 IN A 192.168.13.218 ;; Query time: 1 msec ;; SERVER: 127.0.0.1#8600(127.0.0.1) ;; WHEN: Thu Dec 21 18:27:29 EET 2017 ;; MSG SIZE rcvd: 75 root@debian:~#
Таким образом можно проверить работу кластера на разных нодах соответственно, указав нужные узлы.
Выкидывание ноды из consul кластера (выход из кластера)
Чтобы покинуть кластер, вы можете выйти из агента (используя Ctrl-C), либо принудительно убить один из узлов.
Тестирование работы consul кластера
Можно установить утилиту jq и выполнить:
# curl -s localhost:8500/v1/catalog/nodes | jq . [ { "ID": "8b30fa13-382f-1a0c-e825-ab7eaa941b4f", "Node": "consul-agent-one", "Address": "192.168.13.175", "Datacenter": "dc1", "TaggedAddresses": null, "Meta": null, "CreateIndex": 6, "ModifyIndex": 6 }, { "ID": "56a303b3-1955-5f51-382c-041009c8f075", "Node": "consul-agent-three", "Address": "192.168.13.218", "Datacenter": "dc1", "TaggedAddresses": null, "Meta": null, "CreateIndex": 7, "ModifyIndex": 7 }, { "ID": "86b1f763-73a1-a613-4a08-13b2b7ccee46", "Node": "consul-agent-two", "Address": "192.168.13.219", "Datacenter": "dc1", "TaggedAddresses": { "lan": "192.168.13.219", "wan": "192.168.13.219" }, "Meta": { "consul-network-segment": "" }, "CreateIndex": 5, "ModifyIndex": 8 } ]
Как-то так.
Веб-интерфейс для consul
Как я описывал в статье про консул, можно выполнить туннель, например:
$ ssh -L 8500:192.168.13.219:8500 captain@192.168.13.219
И, можно открывать свой веб интерфейс с консулом:

consul кластер в Unix/Linux
Вот и все, статья «Установка Consul кластера в Unix/Linux» завершена.
а в режиме клиента когда стоит запускать консул-агенты?
Если ты хочешь использовать консул для своего приложения на сервере, тебе нужно настроить консул в режиме клиента, чтобы общаться с консул кластером.
Любой агент может работать в одном из двух режимов: клиент или сервер. Серверный узел берет на себя дополнительную ответственность за то, чтобы быть частью согласованного кворума. Эти узлы участвуют в работе Raft и обеспечивают надежную согласованность и доступность в случае сбоя. Более высокая нагрузка на узлы сервера означает, что обычно они должны выполняться на выделенных экземплярах — они более ресурсоемки, чем клиентский узел. Клиентские узлы составляют большую часть кластера, и они очень легкие, поскольку они взаимодействуют с узлами сервера для большинства операций и поддерживают очень небольшое собственное состояние.