Configuração de um cluster Nomad usando Consul e integração com Gitlab.

Introdução

Recentemente, a popularidade do Kubernetes cresceu rapidamente — cada vez mais projetos o estão adotando. Eu gostaria de abordar um orquestrador como o Nomad: ele é ideal para projetos que já utilizam outras soluções da HashiCorp, como Vault e Consul, e cuja infraestrutura não é complexa. Este material incluirá um guia para a instalação do Nomad, a união de dois nós em um cluster, e a integração do Nomad com o Gitlab.

Configuração de um cluster Nomad usando Consul e integração com Gitlab.

Bancada de Testes

Um pouco sobre o ambiente de teste: estamos utilizando três servidores virtuais com as características 2 CPU, 4 RAM, 50 Gb SSD, conectados em uma rede local comum. Seus nomes e endereços IP são:

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

Instalação do Nomad e Consul. Criação do cluster Nomad

Vamos começar com a instalação básica. Apesar da simplicidade do processo de instalação, vou descrevê-lo para a integridade do artigo: essencialmente, foi criado a partir de rascunhos e anotações para acesso rápido se necessário.

Antes de começarmos a prática, vamos discutir a parte teórica, pois neste estágio é importante compreender a estrutura futura.

Temos dois nós do Nomad e queremos uni-los em um cluster; no futuro, precisaremos de escalonamento automático do cluster — para isso, precisaremos do Consul. Com esta ferramenta, a clusterização e a adição de novos nós se tornam tarefas muito simples: o nó Nomad criado conecta-se ao agente do Consul, após o que se conecta ao cluster Nomad existente. Portanto, primeiro instalaremos o servidor Consul, configuraremos a autenticação http básica para o painel web (que, por padrão, não possui autenticação e pode ser acessível externamente), e também os agentes Consul nos servidores Nomad; só então daremos início ao Nomad.

A instalação das ferramentas da HashiCorp é muito simples: basicamente, apenas movemos o arquivo binário para o diretório bin, configuramos o arquivo de configuração da ferramenta e criamos seu arquivo de serviço.

Baixamos o arquivo binário do Consul e o descompactamos no diretório home do usuário:

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/

Agora temos o arquivo binário do consul pronto para configuração adicional.

Para trabalhar com o Consul, precisamos criar uma chave única usando o comando keygen:

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

Vamos configurar a configuração do Consul, criando o diretório /etc/consul.d/ com a seguinte estrutura:

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

No diretório bootstrap estará o arquivo de configuração config.json — é nele que definiremos as configurações do Consul. Seu conteúdo:

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

Vamos analisar individualmente as principais diretivas e seus valores:

  • bootstrap: true. Habilitamos a adição automática de novos nós quando se conectam. Vale ressaltar que não especificamos aqui o número exato de nós esperados.
  • servidor: true. Habilitamos o modo servidor. O Consul nesta máquina virtual será atualmente o único servidor e mestre, enquanto as VMs do Nomad atuarão como clientes.
  • datacenter: dc1. Especificamos o nome do data center para a criação do cluster. Ele deve ser idêntico tanto nos clientes quanto nos servidores.
  • encrypt: your-key. A chave, que também deve ser única e coincidir em todos os clientes e servidores. É gerada usando o comando consul keygen.
  • start_join. Nesta lista, especificamos os endereços IP aos quais a conexão será feita. Por enquanto, deixamos apenas o próprio endereço.

Neste ponto, podemos iniciar o Consul através da linha de comando:

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

Essa é uma boa forma de depuração agora, no entanto, não será possível usar esse método de forma permanente por razões óbvias. Vamos criar um arquivo de serviço para gerenciar o Consul através do systemd:

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

Conteúdo do arquivo consul.service:

[Unit]
Description=Processo de Inicialização do Consul
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

Iniciamos o Consul através do systemctl:

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

Verificamos: o nosso serviço deve estar em execução e, ao executar o comando consul members, devemos ver nosso servidor:

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

Próximo passo: instalação do Nginx e configuração de proxy, autenticação http. Instalamos o nginx através do gerenciador de pacotes e, no diretório /etc/nginx/sites-enabled, criamos o arquivo de configuração consul.conf com o seguinte conteúdo:

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 "Área Protegida por Senha";
    }
}

Não se esqueça de criar o arquivo .htpasswd e gerar um nome de usuário e senha para ele. Este passo é necessário para que o painel da web não fique acessível a todos que conhecem nosso domínio. No entanto, ao configurar o Gitlab, teremos que abrir mão disso — caso contrário, não conseguiremos fazer o deploy do nosso aplicativo no Nomad. No meu projeto, tanto o Gitlab quanto o Nomad estão apenas na rede interna, portanto, não há esse problema aqui.

Nos outros dois servidores, instalaremos os agentes do Consul seguindo a instrução a seguir. Repetimos as ações com o arquivo binário:

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/

De maneira análoga ao servidor anterior, criamos o diretório para os arquivos de configuração /etc/consul.d com a seguinte estrutura:

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

Conteúdo do arquivo 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", # endereço local da vm
    "start_join": ["172.30.0.15"], # endereço remoto do servidor Consul
    "ports": {
      "dns": 53
     }

Salvamos as alterações e passamos para a configuração do arquivo de serviço, cujo conteúdo é:

/etc/systemd/system/consul.service:

[Unit]
Description="HashiCorp Consul - Uma solução de service mesh"
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

Iniciamos o Consul no servidor. Agora, após a inicialização, devemos ver o serviço configurado no nsul members. Isso significará que ele se conectou com sucesso ao cluster como cliente. Repita o mesmo no segundo servidor e, após isso, poderemos começar a instalação e configuração do Nomad.

Uma instalação mais detalhada do Nomad está descrita em sua documentação oficial. Existem duas maneiras tradicionais de instalação: baixar o arquivo binário e compilar a partir do código-fonte. Eu escolherei a primeira opção.

Nota: o projeto está se desenvolvendo rapidamente, novas atualizações são frequentemente lançadas. É possível que, quando o artigo for concluído, uma nova versão já tenha sido publicada. Portanto, recomendo verificar a versão atual do Nomad no momento e baixá-la.

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

Após descompactar, obteremos um arquivo binário do Nomad com 65 MB - ele deve ser movido para /usr/local/bin.

Vamos criar um diretório de dados para o Nomad e editar seu arquivo de serviço (ele, provavelmente, não existirá no início):

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

Insira as seguintes linhas lá:

[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

No entanto, não se apresse em iniciar o nomad - ainda não criamos seu arquivo de configuração:

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

A estrutura final do diretório será a seguinte:

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

O arquivo nomad.hcl deve conter a seguinte configuração:

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

Conteúdo do arquivo 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
}

Não se esqueça de alterar o arquivo de configuração no segundo servidor - será necessário mudar o valor da diretiva http.

Por fim, nesta etapa, resta configurar o Nginx para proxy e instalar a autorização http. Conteúdo do arquivo 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 "Área Protegida por Senha";
        }
        
}

Agora podemos acessar o painel da web pela rede externa. Conecte-se e vá para a página de servidores:

Configuração de um cluster Nomad usando Consul e integração com Gitlab.
Imagem 1. Lista de servidores no cluster Nomad

Ambos os servidores estão sendo exibidos no painel, assim como veremos na saída do comando nomad node status:

Configuração de um cluster Nomad usando Consul e integração com Gitlab.
Imagem 2. Saída do comando nomad node status

E quanto ao lado do Consul? Vamos dar uma olhada. Acesse o painel de controle do Consul, na página de nós:
Configuração de um cluster Nomad usando Consul e integração com Gitlab.
Imagem 3. Lista de nós no cluster Consul

Agora temos um Nomad configurado, funcionando em conjunto com o Consul. Na etapa final, vamos para a parte mais interessante: configuraremos a entrega de contêineres Docker do Gitlab para o Nomad, além de discutir algumas de suas outras características marcantes.

Criando um Gitlab Runner

Para implantar imagens Docker no Nomad, usaremos um runner separado com o arquivo binário do Nomad dentro (é interessante notar aqui mais uma característica das aplicações Hashicorp — individualmente, elas representam um único arquivo binário). Carregue-o no diretório do runner. Para isso, criaremos um Dockerfile simples com o seguinte conteúdo:


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

Neste mesmo projeto, criamos o .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}

Como resultado, teremos uma imagem do runner do Nomad disponível no Gitlab Registry. Agora podemos ir diretamente ao repositório do projeto, criar um Pipeline e configurar o job do Nomad.

Configuração do projeto

Começaremos com o arquivo de job do Nomad. Meu projeto neste artigo será bastante simples: consistirá em uma única tarefa. O conteúdo do .gitlab-ci será o seguinte:

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

Aqui, a implantação ocorre em modo manual, mas você pode configurá-la para alterar o conteúdo do diretório do projeto. O Pipeline consiste em duas etapas: a construção da imagem e sua implantação no Nomad. Na primeira etapa, coletamos a imagem Docker e a enviamos para nosso Registry; na segunda, iniciamos nosso job no 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" {}
                }
            }
        }
    }
}

Observe que eu tenho um Registry privado e, para o pull bem-sucedido da imagem do Docker, preciso me autenticar. A melhor solução, neste caso, é armazenar o login e a senha no Vault e depois integrá-lo ao Nomad. O Nomad suporta nativamente o Vault. Mas, primeiro, vamos configurar as políticas necessárias para o Nomad no próprio Vault; elas podem ser carregadas:

# 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

Agora, após criar as políticas necessárias, vamos adicionar a integração com o Vault no bloco de task no arquivo job.nomad:

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

Estou usando autenticação por token e o especifico diretamente aqui; também há a opção de passar o token como uma variável ao iniciar o agente nomad:

$ VAULT_TOKEN= nomad agent -config /path/to/config

Agora podemos usar as chaves do Vault. O princípio de funcionamento é simples: criamos um arquivo na job do Nomad que armazenará os valores das variáveis, por exemplo:

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
}

Com essa abordagem simples, é possível configurar a entrega de contêineres no cluster Nomad e trabalhar com ele posteriormente. Dito isto, eu diria que, de certa forma, eu simpatizo com o Nomad — ele se adapta melhor a projetos menores, onde o Kubernetes pode trazer complexidades adicionais e não realizará seu potencial completamente. Além disso, o Nomad é ótimo para iniciantes — ele é fácil de instalar e configurar. No entanto, durante os testes em alguns projetos, enfrentei problemas com suas versões mais antigas — muitas funções básicas simplesmente não existem ou funcionam de maneira incorreta. Ainda assim, acredito que o Nomad irá evoluir e, no futuro, adquirirá as funções necessárias que todos precisam.

Autor: Ilya Andreyev, sob a edição de Alexei Zhadan e da equipe "Live Linux"


Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster