Въведение
В последно време популярността на Kubernetes рязко нараства - все повече проекти го внедряват. А аз искам да се спра на такъв оркестратор, като Nomad: той е отличен за проекти, в които вече се използват други решения от компанията HashiCorp, например Vault и Consul, а самите проекти не са сложни по отношение на инфраструктурата. В този материал ще има инструкции за инсталиране на Nomad, свързване на две ноди в кластер, както и интеграция на Nomad с Gitlab.

Тестов стенд
Няколко думи за тестовата среда: използват се три виртуални сървъра с характеристики 2 CPU, 4 RAM, 50 Gb SSD, свързани в обща локална мрежа. Имената им и IP адресите са:
- nomad-livelinux-01: 172.30.0.5
- nomad-livelinux-02: 172.30.0.10
- consul-livelinux-01: 172.30.0.15
Инсталиране на Nomad, Consul. Създаване на Nomad кластер
Да преминем към базовата инсталация. Въпреки че инсталацията е проста, ще я опиша за целостта на статията: по същество тя бе създадена от чернови и бележки за бърз достъп в случай на необходимост.
Преди да преминем към практиката, нека да обсъдим теоретичната част, защото на този етап е важно разбирането на бъдещата структура.
Имаме две ноди на Nomad и искаме да ги свържем в кластер. Освен това, в бъдеще ни е необходим автоматичен мащабиране на кластера – затова ще ни трябва Consul. С помощта на този инструмент кластерирането и добавянето на нови ноди става много лесна задача: създадената нода Nomad се свързва с Consul агента, след което се свързва с вече съществуващия Nomad кластер. Затова първо ще инсталираме Consul сървър, ще настроим базова http авторизация за уеб панела (по подразбиране е без авторизация и може да бъде достъпна по външен адрес), както и самите Consul агенти на Nomad сървърите, след което само ще преминем към Nomad.
Инсталирането на инструментите на компанията HashiCorp е много просто: всъщност просто преместваме бинарния файл в директорията bin, настройваме конфигурационния файл на инструмента и създаваме неговия сервисен файл.
Изтегляме бинарния файл на Consul и го разархивираме в домашната директория на потребителя:
root@consul-livelinux-01:~# wget https://releases.hashicorp.com/consul/1.5.0/consul_1.5.0_linux_amd64.zip
root@consul-livelinux-01:~# unzip consul_1.5.0_linux_amd64.zip
root@consul-livelinux-01:~# mv consul /usr/local/bin/Сега имаме готов бинарен файл consul за по-нататъшна настройка.
За работа с Consul ни е нужно да създадем уникален ключ с командата keygen:
root@consul-livelinux-01:~# consul keygen
Преминаваме към настройката на конфигурацията на Consul, създавайки директорията /etc/consul.d/ със следната структура:
/etc/consul.d/
├── bootstrap
│ └── config.jsonВ директорията bootstrap ще се намира конфигурационният файл config.json — в него ще зададем настройките на Consul. Неговото съдържание:
{
"bootstrap": true,
"server": true,
"datacenter": "dc1",
"data_dir": "/var/consul",
"encrypt": "your-key",
"log_level": "INFO",
"enable_syslog": true,
"start_join": ["172.30.0.15"]
}Нека разгледаме поотделно основните директиви и техните стойности:
- bootstrap: true. Включваме автоматичното добавяне на нови нодули при свързване. Подчертавам, че тук не посочваме точното число на очакваните нодули.
- server: true. Включваме режим на сървър. Consul на тази виртуална машина ще бъде единственият сървър и майстор в момента, а виртуалните машини на Nomad ще бъдат клиенти.
- datacenter: dc1. Посочваме името на датацентъра за създаване на клъстера. То трябва да бъде идентично и на клиентите, и на сървърите.
- encrypt: your-key. Ключът, който също трябва да бъде уникален и да съвпада на всички клиенти и сървъри. Генерира се с помощта на командата consul keygen.
- start_join. В този списък посочваме списък с IP адреси, към които ще бъде извършено свързване. В момента оставяме само собствения адрес.
На този етап можем да стартираме consul с помощта на командния ред:
root@consul-livelinux-01:~# /usr/local/bin/consul agent -config-dir /etc/consul.d/bootstrap -uiТова е добър начин за отстраняване на грешки в момента, но не може да се използва постоянно по очевидни причини. Ще създадем файл на услугата за управление на Consul през systemd:
root@consul-livelinux-01:~# nano /etc/systemd/system/consul.service
Съдържанието на файла consul.service:
[Unit]
Description=Consul Startup process
After=network.target
[Service]
Type=simple
ExecStart=/bin/bash -c '/usr/local/bin/consul agent -config-dir /etc/consul.d/bootstrap -ui'
TimeoutStartSec=0
[Install]
WantedBy=default.targetСтартираме Consul чрез systemctl:
root@consul-livelinux-01:~# systemctl start consul
Проверяваме: нашият сервис трябва да е стартиран, а при изпълнение на командата consul members трябва да видим нашия сървър:
root@consul-livelinux:/etc/consul.d# consul members
consul-livelinux 172.30.0.15:8301 alive server 1.5.0 2 dc1Следващият етап: инсталиране на Nginx и настройка на проксиране, http авторизация. Инсталираме nginx чрез пакетния мениджър и в директорията /etc/nginx/sites-enabled създаваме конфигурационния файл consul.conf със следното съдържание:
upstream consul-auth {
server localhost:8500;
}
server {
server_name consul.doman.name;
location / {
proxy_pass http://consul-auth;
proxy_set_header Host $host;
auth_basic_user_file /etc/nginx/.htpasswd;
auth_basic "Password-protected Area";
}
}Не забравяйте да създадете .htpasswd файл и да генерирате потребителско име и парола за него. Тази стъпка е необходима, за да се предотврати достъпът до уеб панели за всеки, който знае нашия домейн. Въпреки това, при настройката на Gitlab, ще трябва да се откажем от това — в противен случай не можем да деплойнем нашето приложение в Nomad. В проекта ми и Gitlab, и Nomad се намират само в сивата мрежа, така че тук нямаме такъв проблем.
На другите два сървъра инсталираме агенти на Consul по следващата инструкция. Повтаряме действията с бинарния файл:
root@nomad-livelinux-01:~# wget https://releases.hashicorp.com/consul/1.5.0/consul_1.5.0_linux_amd64.zip
root@nomad-livelinux-01:~# unzip consul_1.5.0_linux_amd64.zip
root@nomad-livelinux-01:~# mv consul /usr/local/bin/По аналогия с предходния сървър създаваме директория за конфигурационни файлове /etc/consul.d със следната структура:
/etc/consul.d/
├── client
│ └── config.jsonСъдържанието на файла config.json:
{
"datacenter": "dc1",
"data_dir": "/opt/consul",
"log_level": "DEBUG",
"node_name": "nomad-livelinux-01",
"server": false,
"encrypt": "your-private-key",
"domain": "livelinux",
"addresses": {
"dns": "127.0.0.1",
"https": "0.0.0.0",
"grpc": "127.0.0.1",
"http": "127.0.0.1"
},
"bind_addr": "172.30.0.5", # локален адрес на ВМ
"start_join": ["172.30.0.15"], # отдалечен адрес на консул сървър
"ports": {
"dns": 53
}Запазваме промените и преминаваме към настройката на сервис файла, неговото съдържание:
/etc/systemd/system/consul.service:
[Unit]
Description="HashiCorp Consul - решение за мрежа на услуги"
Documentation=https://www.consul.io/
Requires=network-online.target
After=network-online.target
[Service]
User=root
Group=root
ExecStart=/usr/local/bin/consul agent -config-dir=/etc/consul.d/client
ExecReload=/usr/local/bin/consul reload
KillMode=process
Restart=on-failure
[Install]
WantedBy=multi-user.targetСтартираме консул на сървъра. Сега, след стартиране, трябва да видим настроената услуга в nsul members. Това ще означава, че той успешно се е свързал с клъстера като клиент. Повторете същото на втория сървър и след това можем да преминем към инсталацията и настройката на Nomad.
По-подробната инсталация на Nomad е описана в официалната му документация. Има два традиционни метода за инсталация: изтегляне на бинарен файл и компилация от изходен код. Аз ще избера първия метод.
Забележка: проектът се развива много бързо, често излизат нови актуализации. Вероятно, до момента на завършване на статията ще излезе нова версия. Затова препоръчвам преди да прочетете да проверите актуалната версия на Nomad в момента и да изтеглите именно нея.
root@nomad-livelinux-01:~# wget https://releases.hashicorp.com/nomad/0.9.1/nomad_0.9.1_linux_amd64.zip
root@nomad-livelinux-01:~# unzip nomad_0.9.1_linux_amd64.zip
root@nomad-livelinux-01:~# mv nomad /usr/local/bin/
root@nomad-livelinux-01:~# nomad -autocomplete-install
root@nomad-livelinux-01:~# complete -C /usr/local/bin/nomad nomad
root@nomad-livelinux-01:~# mkdir /etc/nomad.dСлед разархивиране ще получим бинарен файл на Nomad с размер 65 Мб — необходимо е да го преместим в /usr/local/bin.
Нека създадем директория data за Nomad и редактираме файла за услугата му (вероятно в началото няма да съществува):
root@nomad-livelinux-01:~# mkdir --parents /opt/nomad
root@nomad-livelinux-01:~# nano /etc/systemd/system/nomad.serviceВмъкваме следните редове:
[Unit]
Description=Nomad
Documentation=https://nomadproject.io/docs/
Wants=network-online.target
After=network-online.target
[Service]
ExecReload=/bin/kill -HUP $MAINPID
ExecStart=/usr/local/bin/nomad agent -config /etc/nomad.d
KillMode=process
KillSignal=SIGINT
LimitNOFILE=infinity
LimitNPROC=infinity
Restart=on-failure
RestartSec=2
StartLimitBurst=3
StartLimitIntervalSec=10
TasksMax=infinity
[Install]
WantedBy=multi-user.targetНо не бързаме да стартираме nomad — все още не сме създали конфигурационният му файл:
root@nomad-livelinux-01:~# mkdir --parents /etc/nomad.d
root@nomad-livelinux-01:~# chmod 700 /etc/nomad.d
root@nomad-livelinux-01:~# nano /etc/nomad.d/nomad.hcl
root@nomad-livelinux-01:~# nano /etc/nomad.d/server.hcl
Структурата на директорията ще бъде следната:
/etc/nomad.d/
├── nomad.hcl
└── server.hclФайлът nomad.hcl трябва да съдържа следната конфигурация:
datacenter = "dc1"
data_dir = "/opt/nomad"Съдържанието на файла server.hcl:
server {
enabled = true
bootstrap_expect = 1
}
consul {
address = "127.0.0.1:8500"
server_service_name = "nomad"
client_service_name = "nomad-client"
auto_advertise = true
server_auto_join = true
client_auto_join = true
}
bind_addr = "127.0.0.1"
advertise {
http = "172.30.0.5"
}
client {
enabled = true
}Не забравяйте да промените конфигурационния файл на втория сървър — там ще се нуждаете от промяна на стойността на директивата http.
Последно на този етап остава настройката на Nginx за проксириране и установяване на http удостоверяване. Съдържанието на файла nomad.conf:
upstream nomad-auth {
server 172.30.0.5:4646;
}
server {
server_name nomad.domain.name;
location / {
proxy_pass http://nomad-auth;
proxy_set_header Host $host;
auth_basic_user_file /etc/nginx/.htpasswd;
auth_basic "Password-protected Area";
}
}Сега можем да получим достъп до уеб панела през външната мрежа. Свързваме се и отиваме на страницата servers:

Изображение 1. Списък на сървърите в кластерa Nomad
И двата сървъра успешно се показват в панела, същото можем да видим в изхода на команда nomad node status:

Изображение 2. Изход на командата nomad node status
Какво става от страната на Consul? Нека да погледнем. Преминаваме към контролния панел на Consul, на страницата nodes:

Изображение 3. Списък на нодовете в кластерa Consul
Сега имаме подготвен Nomad, работещ заедно с Consul. В последния етап ще преминем към най-интересното: ще настроим доставката на Docker контейнери от Gitlab в Nomad, а също така ще говорим за някои от другите му отличителни характеристики.
Създаване на Gitlab Runner
За деплой на Docker образи в Nomad ще използваме отделен runner с бинарния файл на Nomad вътре (тук, между другото, можем да отбележим още една особеност на приложенията на Hashicorp — индивидуално те представляват един единствен бинарен файл). Качете го в директорията на runner. За него ще създадем най-простия Dockerfile със следното съдържание:
FROM alpine:3.9
RUN apk add --update --no-cache libc6-compat gettext
COPY nomad \/usr\/local\/bin\/nomad
В този проект създаваме .gitlab-ci.yml:
variables:
DOCKER_IMAGE: nomad\/nomad-deploy
DOCKER_REGISTRY: registry.domain.name
stages:
- build
build:
stage: build
image: ${DOCKER_REGISTRY}\/nomad\/alpine:3
script:
- tag=${DOCKER_REGISTRY}\/${DOCKER_IMAGE}:latest
- docker build --pull -t ${tag} -f Dockerfile .
- docker push ${tag}В крайна сметка ще имаме наличен образ на runner-а на Nomad в Gitlab Registry, сега можем да преминем директно към репозитория на проекта, да създадем Pipeline и да настроим nomad job на Nomad.
Настройка на проекта
Нека започнем с файла на job-овете за Nomad. Моят проект в тази статия ще бъде доста примитивен: той ще се състои от една задача. Съдържанието на .gitlab-ci ще бъде следното:
variables:
NOMAD_ADDR: http:\/\/nomad.address.service:4646
DOCKER_REGISTRY: registry.domain.name
DOCKER_IMAGE: example\/project
stages:
- build
- deploy
build:
stage: build
image: ${DOCKER_REGISTRY}\/nomad-runner\/alpine:3
script:
- tag=${DOCKER_REGISTRY}\/${DOCKER_IMAGE}:${CI_COMMIT_SHORT_SHA}
- docker build --pull -t ${tag} -f Dockerfile .
- docker push ${tag}
deploy:
stage: deploy
image: registry.example.com\/nomad\/nomad-runner:latest
script:
- envsubst '${CI_COMMIT_SHORT_SHA}' job.nomad
- cat job.nomad
- nomad validate job.nomad
- nomad plan job.nomad || if [ $? -eq 255 ]; then exit 255; else echo "success"; fi
- nomad run job.nomad
environment:
name: production
allow_failure: false
when: manualТук деплойът се извършва в ръчен режим, но можете да го настроите да променя съдържанието на директорията на проекта. Pipeline-ът се състои от два етапа: сбор на образа и неговия деплой в Nomad. На първия етап събираме Docker образ и го пускаме в нашия Registry, а на втория стартираме нашата job в Nomad.
работа "monitoring-status" {
datacenters = ["dc1"]
migrate {
max_parallel = 3
health_check = "checks"
min_healthy_time = "15s"
healthy_deadline = "5m"
}
група "zhadan.ltd" {
count = 1
update {
max_parallel = 1
min_healthy_time = "30s"
healthy_deadline = "5m"
progress_deadline = "10m"
auto_revert = true
}
задача "service-monitoring" {
driver = "docker"
config {
image = "registry.domain.name/example/project:${CI_COMMIT_SHORT_SHA}"
force_pull = true
auth {
username = "gitlab_user"
password = "gitlab_password"
}
port_map {
http = 8000
}
}
resources {
network {
port "http" {}
}
}
}
}
}Обърнете внимание, че имам затворен Registry и за успешното изтегляне на Docker образа ми е необходимо да се авторизирам в него. Най-доброто решение в този случай е да запишете потребителското име и паролата в Vault с последваща интеграция с Nomad. Nomad поддържа Vault по подразбиране. Но първо, в самия Vault ще инсталираме необходимите политики за Nomad, които можете да заредите:
# Download the policy and token role
$ curl https://nomadproject.io/data/vault/nomad-server-policy.hcl -O -s -L
$ curl https://nomadproject.io/data/vault/nomad-cluster-role.json -O -s -L
# Write the policy to Vault
$ vault policy write nomad-server nomad-server-policy.hcl
# Create the token role with Vault
$ vault write /auth/token/roles/nomad-cluster @nomad-cluster-role.jsonСега, след като създадохме необходимите политики, ще добавим интеграция с Vault в блока task в файла job.nomad:
vault {
enabled = true
address = "https://vault.domain.name:8200"
token = "token"
}Използвам авторизация по токен и го въвеждам тук, също така има вариант да се зададе токен като променлива при стартиране на nomad agent:
$ VAULT_TOKEN= nomad agent -config /path/to/config
Сега можем да използваме ключовете с Vault. Принципът на работа е прост: създаваме файл в Nomad job, който ще съдържа стойности на променливите, например:
template {
data = <<EOH
{{with secret "secrets/pipeline-keys"}}
REGISTRY_LOGIN="{{ .Data.REGISTRY_LOGIN }}"
REGISTRY_PASSWORD="{{ .Data.REGISTRY_LOGIN }}{{ end }}"
EOH
destination = "secrets/service-name.env"
env = true
}С този прост подход можете да настроите разпространението на контейнери в клъстера Nomad и да работите с него по-нататък. Лично аз смятам, че в известен смисъл симпатизирам на Nomad — той е по-подходящ за малки проекти, където Kubernetes може да предизвика допълнителни затруднения и няма да реализира напълно потенциала си. Освен това, Nomad е отличен избор за начинаещи — лесно се инсталира и конфигурира. Въпреки това, при тестването на някои проекти се сблъсквам с проблемите на ранните му версии — много основни функции просто липсват или не работят коректно. Въпреки това, смятам, че Nomad ще продължи да се развива и в бъдеще ще придобие необходимите функции за всички.
Автор: Илия Андреев, под редакцията на Алексей Жадан и екипа на «Лайв Линукс»
Източник: habr.com
