Настройка кластара Nomad з дапамогай Consul і інтэграцыя з Gitlab

Увядзенне

У апошні час імкліва расце папулярнасць Kubernetes – усё больш і больш праектаў ўкараняюць яго ў сябе. Я ж хацеў дакрануцца да такога аркестратара, як Nomad: ён выдатна падыдзе праектам, дзе ўжо выкарыстоўваюцца іншыя рашэнні ад кампаніі HashiCorp, напрыклад, Vault і Consul, а самі праекты не з'яўляюцца складанымі ў плане інфраструктуры. У дадзеным матэрыяле будзе інструкцыя па ўсталёўцы Nomad, аб'яднанні двух нод у кластар, а таксама інтэграцыі Nomad з Gitlab.

Настройка кластара Nomad з дапамогай Consul і інтэграцыя з Gitlab

Выпрабавальны стэнд

Трохі аб тэставым стэндзе: выкарыстоўваюцца тры віртуальных сервера з характарыстыкамі 2 CPU, 4 RAM, 50 Gb SSD, аб'яднаных у агульную лакальную сетку. Іх назвы і IP адрасы:

  1. nomad-livelinux-01: 172.30.0.5
  2. nomad-livelinux-02: 172.30.0.10
  3. 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:

Настройка кластара Nomad з дапамогай Consul і інтэграцыя з Gitlab
Выява 1. Спіс сервераў у кластары Nomad

Абодва сервера паспяхова адлюстроўваюцца ў панэлі, таксама самае мы ўбачым у выснове каманды nomad node status:

Настройка кластара Nomad з дапамогай Consul і інтэграцыя з Gitlab
Выява 2. Вывад каманды nomad node status

Што ж з боку Consul? Давайце паглядзім. Пераходзім у панэль кіравання Consul, на старонку nodes:
Настройка кластара Nomad з дапамогай Consul і інтэграцыя з Gitlab
Выява 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

Дадаць каментар