Запровадження
Останнім часом стрімко зростає популярність 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
Приступимо до базової установки. Незважаючи на простоту установки, я опишу її для цілісності статті: по суті вона була створена з чернеток і нотаток для швидкого доступу у разі потреби.
Перш, ніж приступити до практики, обговоримо теоретичну частину, тому що на даному етапі важливе розуміння майбутньої структури.
У нас існує дві ноди номада і ми хочемо об'єднати їх у кластер, також на майбутнє нам знадобиться автоматичний скейлінг кластера — для цього нам знадобиться 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"]
}
Розберемо окремо основні директиви та їх значення:
- завантажувач: true. Включаємо автоматичне додавання нових нод у разі їхнього підключення. Зазначу, що ми не вказуємо тут точну кількість очікуваних нід.
- сервер: true. Вмикаємо режим сервера. Consul на цій віртуальній машині виступатиме на даний момент єдиним сервером і майстром, ВМ Nomad'a буду клієнтами.
- центр обробки даних: DC1. Вказуємо назву датацентру для створення кластеру. Він має бути ідентичним і на клієнтах, і на серверах.
- шифрувати: 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 <all>
Наступний етап: встановлення 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 - A service mesh solution"
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
Запускаємо consul на сервері. Тепер, після запуску ми повинні у 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'a вагою 65 Мб - його необхідно перемістити в /usr/local/bin.
Створимо data директорію для Nomad'a і відредагуємо його service файл (його, швидше за все, не існуватиме на початку):
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. Список серверів у кластері Nomad
Обидва сервери успішно відображаються в панелі, теж ми побачимо у виведенні команди nomad node status:
Зображення 2. Виведення команди nomad node status
Що ж із боку Consul? Давайте подивимося. Переходимо в панель керування Consul, на сторінку nodes:
Зображення 3. Список нод у кластері Consul
Тепер у нас є підготовлений Nomad, який працює у зв'язці з Consul. У завершальному етапі ми приступимо до найцікавішого: налаштуємо доставку Docker контейнерів з Gitlab в Nomad, а також поговоримо про деякі інші його особливості.
Створення Gitlab Runner
Для деплою докер образів в Номад ми будемо використовувати окремий раннер з бінарним файлом Nomad'а всередині (тут, до речі, можна відзначити ще одну особливість додатків Hashicorp — окремо вони являють собою єдиний бінарний файл). Завантажте його в директорію раннера. Для нього створимо найпростіший 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}
У результаті буде доступний образ раннера Номада в Gitlab Registry, тепер ми можемо перейти безпосередньо в репозиторій проекту, створимо Pipeline і налаштуємо nomad job Nomad'a.
Налаштування проекту
Почнемо з job's файлу для 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}' < project.nomad > 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 ж складається з двох етапів: зі збирання образу та його деплою в номад. На першому етапі ми збираємо докер образ і пушимо його в наш Registry, на другому ж запускаємо нашу job в Nomad.
job "monitoring-status" {
datacenters = ["dc1"]
migrate {
max_parallel = 3
health_check = "checks"
min_healthy_time = "15s"
healthy_deadline = "5m"
}
group "zhadan.ltd" {
count = 1
update {
max_parallel = 1
min_healthy_time = "30s"
healthy_deadline = "5m"
progress_deadline = "10m"
auto_revert = true
}
task "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 і для успішного пулла докер-образу мені потрібно авторизуватися в ньому. Найкращим рішенням у разі є висновок логіна і пароля в Vault з наступною інтеграцією його з Nomad. Nomad нативно підтримує Vault. Але для початку в Vault встановимо необхідні policy для 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
Тепер, створивши необхідні policy, ми в блоці task у файлі job.nomad додамо інтеграцію з Vault:
vault {
enabled = true
address = "https://vault.domain.name:8200"
token = "token"
}
Я використовую авторизацію по токену та прописую його безпосередньо тут, також є варіант вказівки токена як змінної при запуску nomad agent:
$ VAULT_TOKEN=<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