Configurazione di un cluster Nomad utilizzando Consul e integrazione con Gitlab

Introduzione

Recentemente, la popolarità di Kubernetes è cresciuta rapidamente: sempre più progetti lo stanno implementando. Volevo soffermarmi su un orchestratore come Nomad: è perfetto per progetti che già utilizzano altre soluzioni di HashiCorp, ad esempio Vault e Consul, e i progetti stessi non sono complessi in termini di infrastruttura. Questo materiale conterrà le istruzioni per installare Nomad, combinare due nodi in un cluster e integrare Nomad con Gitlab.

Configurazione di un cluster Nomad utilizzando Consul e integrazione con Gitlab

banco di prova

Un po' del banco di prova: vengono utilizzati tre server virtuali con le caratteristiche di 2 CPU, 4 RAM, 50 Gb SSD, uniti in una rete locale comune. I loro nomi e indirizzi IP:

  1. nomad-livelinux-01: 172.30.0.5
  2. nomad-livelinux-02: 172.30.0.10
  3. console-livelinux-01: 172.30.0.15

Installazione di Nomad, Console. Creazione di un cluster Nomad

Cominciamo con l'installazione di base. Sebbene la configurazione fosse semplice, la descriverò per il bene dell'integrità dell'articolo: è stato creato essenzialmente da bozze e note per un rapido accesso quando necessario.

Prima di iniziare la pratica, discuteremo la parte teorica, perché in questa fase è importante comprendere la struttura futura.

Abbiamo due nodi nomadi e vogliamo combinarli in un cluster, e in futuro avremo anche bisogno del ridimensionamento automatico del cluster: per questo avremo bisogno di Console. Con questo strumento, il clustering e l'aggiunta di nuovi nodi diventa un compito molto semplice: il nodo Nomad creato si connette all'agente Consul, quindi si connette al cluster Nomad esistente. Pertanto, all'inizio installeremo il server Consul, configureremo l'autorizzazione http di base per il pannello web (è senza autorizzazione per impostazione predefinita ed è accessibile da un indirizzo esterno), così come gli stessi agenti Consul sui server Nomad, dopodiché procederemo solo verso Nomad.

Installare gli strumenti di HashiCorp è molto semplice: essenzialmente, basta spostare il file binario nella directory bin, impostare il file di configurazione dello strumento e creare il suo file di servizio.

Scarica il file binario di Consul e decomprimilo nella directory home dell'utente:

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/

Ora abbiamo un binario della console già pronto per un'ulteriore configurazione.

Per lavorare con Consul, dobbiamo creare una chiave univoca utilizzando il comando keygen:

root@consul-livelinux-01:~# consul keygen

Passiamo all'impostazione della configurazione di Console, creando una directory /etc/consul.d/ con la seguente struttura:

/etc/consul.d/
├── bootstrap
│   └── config.json

La directory bootstrap conterrà un file di configurazione config.json - in esso imposteremo le impostazioni di Console. Il suo contenuto:

{
"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"]
}

Vediamo separatamente le principali direttive e il loro significato:

  • bootstrap: VERO. Abilitiamo l'aggiunta automatica di nuovi nodi se sono connessi. Prendo atto che non indichiamo qui il numero esatto di nodi attesi.
  • server: VERO. Abilita la modalità server. Consul su questa macchina virtuale fungerà da unico server e master al momento, la VM di Nomad sarà i client.
  • datacenter: dc1. Specificare il nome del data center per creare il cluster. Deve essere identico sia sui client che sui server.
  • cifrare: la tua chiave. La chiave, che deve anch'essa essere univoca e corrispondere su tutti i client e server. Generato utilizzando il comando console keygen.
  • start_join. In questo elenco indichiamo un elenco di indirizzi IP a cui verrà effettuata la connessione. Per il momento lasciamo solo il nostro indirizzo.

A questo punto possiamo eseguire console utilizzando la riga di comando:

root@consul-livelinux-01:~# /usr/local/bin/consul agent -config-dir /etc/consul.d/bootstrap -ui

Questo è un buon modo per eseguire il debug adesso, tuttavia, non potrai utilizzare questo metodo su base continuativa per ovvi motivi. Creiamo un file di servizio per gestire Consul tramite systemd:

root@consul-livelinux-01:~# nano /etc/systemd/system/consul.service

Contenuto del file 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

Avvia Console tramite systemctl:

root@consul-livelinux-01:~# systemctl start consul

Controlliamo: il nostro servizio deve essere in esecuzione, ed eseguendo il comando consul members dovremmo vedere il nostro server:

root@consul-livelinux:/etc/consul.d# consul members
consul-livelinux    172.30.0.15:8301  alive   server  1.5.0  2         dc1  <all>

Fase successiva: installazione di Nginx e configurazione del proxy e dell'autorizzazione http. Installiamo nginx tramite il gestore pacchetti e nella directory /etc/nginx/sites-enabled creiamo un file di configurazione consul.conf con il seguente contenuto:

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";
    }
}

Non dimenticare di creare un file .htpasswd e generare un nome utente e una password per esso. Questo elemento è necessario affinché il pannello web non sia disponibile a tutti coloro che conoscono il nostro dominio. Tuttavia, durante la configurazione di Gitlab, dovremo abbandonarlo, altrimenti non saremo in grado di distribuire la nostra applicazione su Nomad. Nel mio progetto, sia Gitlab che Nomad si trovano solo sul web grigio, quindi qui non ci sono problemi del genere.

Sui restanti due server installiamo gli agenti Consul secondo le seguenti istruzioni. Ripetiamo i passaggi con il file binario:

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/

Per analogia con il server precedente, creiamo una directory per i file di configurazione /etc/consul.d con la seguente struttura:

/etc/consul.d/
├── client
│   └── config.json

Contenuto del file 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
     }

Salva le modifiche e passa alla configurazione del file di servizio, del suo contenuto:

/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

Lanciamo console sul server. Ora, dopo il lancio, dovremmo vedere il servizio configurato in nsul members. Ciò significherà che si è connesso correttamente al cluster come client. Ripeti lo stesso sul secondo server e successivamente possiamo iniziare a installare e configurare Nomad.

Un'installazione più dettagliata di Nomad è descritta nella sua documentazione ufficiale. Esistono due metodi di installazione tradizionali: scaricare un file binario e compilare dal sorgente. Sceglierò il primo metodo.

Nota: Il progetto si sta sviluppando molto rapidamente, spesso vengono rilasciati nuovi aggiornamenti. Forse una nuova versione verrà rilasciata quando questo articolo sarà completato. Pertanto, prima di leggere, ti consiglio di controllare la versione attuale di Nomad al momento e di scaricarla.

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

Dopo la decompressione, riceveremo un file binario Nomad del peso di 65 MB: deve essere spostato in /usr/local/bin.

Creiamo una directory di dati per Nomad e modifichiamo il suo file di servizio (molto probabilmente non esisterà all'inizio):

root@nomad-livelinux-01:~# mkdir --parents /opt/nomad
root@nomad-livelinux-01:~# nano /etc/systemd/system/nomad.service

Incolla lì le seguenti righe:

[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

Tuttavia, non abbiamo fretta di lanciare nomad: non abbiamo ancora creato il suo file di configurazione:

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

La struttura finale della directory sarà la seguente:

/etc/nomad.d/
├── nomad.hcl
└── server.hcl

Il file nomad.hcl dovrebbe contenere la seguente configurazione:

datacenter = "dc1"
data_dir = "/opt/nomad"

Contenuto del file 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
}

Non dimenticare di modificare il file di configurazione sul secondo server: lì dovrai modificare il valore della direttiva http.

L'ultima cosa in questa fase è configurare Nginx per il proxy e impostare l'autorizzazione http. Contenuto del file 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";
        }
        
}

Ora possiamo accedere al pannello web tramite una rete esterna. Connettiti e vai alla pagina dei server:

Configurazione di un cluster Nomad utilizzando Consul e integrazione con Gitlab
Immagine 1. Elenco dei server nel cluster Nomad

Entrambi i server vengono visualizzati correttamente nel pannello, vedremo la stessa cosa nell'output del comando nomad node status:

Configurazione di un cluster Nomad utilizzando Consul e integrazione con Gitlab
Immagine 2. Output del comando di stato del nodo nomade

E il Console? Diamo un'occhiata. Vai al pannello di controllo del Console, alla pagina dei nodi:
Configurazione di un cluster Nomad utilizzando Consul e integrazione con Gitlab
Immagine 3. Elenco dei nodi nel cluster Consul

Ora abbiamo un Nomade preparato che lavora insieme al Console. Nella fase finale arriveremo alla parte divertente: impostare la consegna dei container Docker da Gitlab a Nomad e parlare anche di alcune delle sue altre caratteristiche distintive.

Creazione di Gitlab Runner

Per distribuire le immagini docker su Nomad, utilizzeremo un runner separato con il file binario Nomad all'interno (qui, a proposito, possiamo notare un'altra caratteristica delle applicazioni Hashicorp: individualmente sono un singolo file binario). Caricalo nella directory del corridore. Creiamo un semplice Dockerfile con il seguente contenuto:


FROM alpine:3.9
RUN apk add --update --no-cache libc6-compat gettext
COPY nomad /usr/local/bin/nomad

Nello stesso progetto creiamo .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}

Di conseguenza, avremo un’immagine disponibile del runner Nomad nel registro Gitlab, ora possiamo andare direttamente al repository del progetto, creare una pipeline e configurare il lavoro nomad di Nomad.

Impostazione del progetto

Cominciamo con il file del lavoro per Nomad. Il mio progetto in questo articolo sarà piuttosto primitivo: consisterà in un compito. Il contenuto di .gitlab-ci sarà il seguente:

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

In questo caso la distribuzione avviene manualmente, ma è possibile configurarla per modificare il contenuto della directory del progetto. La pipeline è composta da due fasi: assemblaggio dell'immagine e sua distribuzione su nomad. Nella prima fase assembliamo un'immagine docker e la inseriamo nel nostro registro, nella seconda lanciamo il nostro lavoro in 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" {}
                }
            }
        }
    }
}

Tieni presente che ho un registro privato e per estrarre correttamente un'immagine docker devo accedervi. La soluzione migliore in questo caso è inserire login e password in Vault e quindi integrarli con Nomad. Nomad supporta nativamente Vault. Ma prima installiamo le policy necessarie per Nomad nel Vault stesso; possono essere scaricate:

# 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

Ora, dopo aver creato le policy necessarie, aggiungeremo l'integrazione con Vault nel blocco attività nel file job.nomad:

vault {
  enabled = true
  address = "https://vault.domain.name:8200"
  token = "token"
}

Utilizzo l'autorizzazione tramite token e la registro direttamente qui, c'è anche la possibilità di specificare il token come variabile all'avvio dell'agente nomad:

$ VAULT_TOKEN=<token> nomad agent -config /path/to/config

Ora possiamo usare le chiavi con Vault. Il principio di funzionamento è semplice: creiamo un file in Nomad job che memorizzerà i valori delle variabili, ad esempio:

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
}

Con questo semplice approccio, puoi configurare la consegna dei contenitori al cluster Nomad e lavorarci in futuro. Dirò che in una certa misura simpatizzo con Nomad: è più adatto a piccoli progetti in cui Kubernetes può causare ulteriore complessità e non realizzare il suo pieno potenziale. Inoltre, Nomad è perfetto per i principianti: è facile da installare e configurare. Tuttavia, durante i test su alcuni progetti, riscontro un problema con le prime versioni: molte funzioni di base semplicemente non sono presenti o non funzionano correttamente. Tuttavia, credo che Nomad continuerà a svilupparsi e in futuro acquisirà le funzioni di cui tutti hanno bisogno.

Autore: Ilya Andreev, a cura di Alexey Zhadan e del team di Live Linux


Fonte: habr.com

Aggiungi un commento