Установка Consul кластера в Unix/Linux

Установка Consul кластера в Unix/Linux

Consul — очередной продукт компании HashiCorp который имеет несколько компонентов, но в целом это распределенная, высокодоступная система обнаружения и конфигурирования служб в вашей инфраструктуре.

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

Я описывал установку consul в моей статье:

Установка Consul в Unix/Linux

А сейчас поговорим как можно собрать кластер из consul.

Установка Consul кластера

Consul кластер представляет собой сеть связанных узлов, на которых запущены сервисы, зарегистрированные в discovery. Consul гарантирует, что информация о кластере будет распространена по всем участникам кластера и доступна по запросу. Также реализована поддержка не только однорангового, но и многорангового, разделенного по зонам, кластера, которые в терминологии Consul называются датацентрами. При помощи Consul можно работать как с конкретным датацентром, так и выполнять действия над любым другим. Датацентры не изолированы друг от друга в рамках discovery. Агент в одном ДЦ может получить информацию из другого ДЦ, что может помочь в построении эффективного решения для распределенной системы.

Consul кластер в Unix/Linux

Агенты 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:
# https://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

Вот и все, статья «Установка Consul кластера в Unix/Linux» завершена.

2 thoughts on “Установка Consul кластера в Unix/Linux

    • Если ты хочешь использовать консул для своего приложения на сервере, тебе нужно настроить консул в режиме клиента, чтобы общаться с консул кластером.
      Любой агент может работать в одном из двух режимов: клиент или сервер. Серверный узел берет на себя дополнительную ответственность за то, чтобы быть частью согласованного кворума. Эти узлы участвуют в работе Raft и обеспечивают надежную согласованность и доступность в случае сбоя. Более высокая нагрузка на узлы сервера означает, что обычно они должны выполняться на выделенных экземплярах — они более ресурсоемки, чем клиентский узел. Клиентские узлы составляют большую часть кластера, и они очень легкие, поскольку они взаимодействуют с узлами сервера для большинства операций и поддерживают очень небольшое собственное состояние.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.