Introducción
Últimamente, la popularidad de Kubernetes ha crecido rápidamente: cada vez más proyectos lo están implementando. Sin embargo, me gustaría abordar un orquestador como Nomad: es ideal para proyectos que ya utilizan otras soluciones de HashiCorp, como Vault y Consul, y cuyas infraestructuras no son complejas. En este material, encontrarán una guía para la instalación de Nomad, la creación de un clúster con dos nodos y la integración de Nomad con Gitlab.

Comenzamos las pruebas del esquema de HA con el desarrollo de un
Un poco sobre el entorno de prueba: se utilizan tres servidores virtuales con las características de 2 CPU, 4 RAM, 50 Gb SSD, conectados en una red local común. Sus nombres y direcciones IP son:
- nomad-livelinux-01: 172.30.0.5
- nomad-livelinux-02: 172.30.0.10
- consul-livelinux-01: 172.30.0.15
Instalación de Nomad y Consul. Creación de un clúster de Nomad
Comencemos con la instalación básica. A pesar de la simplicidad del proceso, lo describiré para la integridad del artículo: en realidad, fue creado a partir de bocetos y notas para un acceso rápido en caso de necesidad.
Antes de pasar a la práctica, discutamos la parte teórica, porque en esta etapa es importante comprender la estructura futura.
Tenemos dos nodos de Nomad y queremos unirlos en un clúster; además, en el futuro necesitaremos escalado automático del clúster, por lo que necesitaremos Consul. Con esta herramienta, la agrupación y adición de nuevos nodos se convierte en una tarea muy sencilla: el nodo Nomad creado se conecta al agente Consul y luego se conecta al clúster existente de Nomad. Por lo tanto, primero instalaremos el servidor Consul, configuraremos la autorización HTTP básica para el panel web (que por defecto no tiene autorización y puede ser accesible desde una dirección externa), y luego los agentes de Consul en los servidores de Nomad, antes de comenzar con Nomad.
La instalación de las herramientas de HashiCorp es muy sencilla: en esencia, solo movemos el archivo binario a la carpeta bin, configuramos el archivo de configuración de la herramienta y creamos su archivo de servicio.
Descargamos el archivo binario de Consul y lo descomprimimos en el directorio personal del usuario:
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/Ahora tenemos el archivo binario de consul listo para la configuración posterior.
Para trabajar con Consul, necesitamos crear una clave única utilizando el comando keygen:
root@consul-livelinux-01:~# consul keygen
Pasemos a configurar Consul creando el directorio /etc/consul.d/ con la siguiente estructura:
/etc/consul.d/
├── bootstrap
│ └── config.jsonEn el directorio bootstrap se encontrará el archivo de configuración config.json, donde estableceremos las configuraciones de Consul. Su contenido es:
{
"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"]
}Analicemos individualmente las principales directivas y sus valores:
- bootstrap: true. Activamos la incorporación automática de nuevos nodos en caso de que se conecten. Cabe destacar que no especificamos aquí el número exacto de nodos esperados.
- servidor: true. Activamos el modo de servidor. Consul en esta máquina virtual actuará por el momento como el único servidor y maestro, mientras que la VM de Nomad será cliente.
- datacenter: dc1. Se especifica el nombre del centro de datos para la creación del clúster. Debe ser idéntico tanto en los clientes como en los servidores.
- encrypt: your-key. La clave, que también debe ser única y coincidir en todos los clientes y servidores. Se genera utilizando el comando consul keygen.
- start_join. En esta lista, especificamos las direcciones IP a las que se conectará. Por ahora, solo dejamos nuestra propia dirección.
En esta etapa, podemos iniciar Consul a través de la línea de comandos:
root@consul-livelinux-01:~# /usr/local/bin/consul agent -config-dir /etc/consul.d/bootstrap -uiEs una buena manera de depurar en este momento, sin embargo, no podemos usar este método de manera constante por razones obvias. Crearemos un archivo de servicio para administrar Consul a través de systemd:
root@consul-livelinux-01:~# nano /etc/systemd/system/consul.service
Contenido del archivo consul.service:
[Unit]
Description=Proceso de inicio de 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.targetIniciamos Consul a través de systemctl:
root@consul-livelinux-01:~# systemctl start consul
Verificamos: nuestro servicio debería estar en ejecución y al ejecutar el comando consul members deberíamos ver nuestro servidor:
root@consul-livelinux:/etc/consul.d# consul members
consul-livelinux 172.30.0.15:8301 alive server 1.5.0 2 dc1Siguiente etapa: instalación de Nginx y configuración del proxy, autenticación http. Instalamos nginx a través del gestor de paquetes y en el directorio /etc/nginx/sites-enabled creamos el archivo de configuración consul.conf con el siguiente contenido:
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 contraseña";
}
}No olvides crear el archivo .htpasswd y generar un nombre de usuario y una contraseña para él. Este paso es necesario para que el panel web no sea accesible a todos los que conocen nuestro dominio. Sin embargo, al configurar Gitlab, tendremos que renunciar a esto; de lo contrario, no podremos desplegar nuestra aplicación en Nomad. En mi proyecto, tanto Gitlab como Nomad se encuentran solo en la red interna, así que aquí no hay tal problema.
En los otros dos servidores, instalamos los agentes Consul siguiendo las siguientes instrucciones. Repetimos las acciones con el archivo 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/De manera similar al servidor anterior, creamos un directorio para los archivos de configuración /etc/consul.d con la siguiente estructura:
/etc/consul.d/
├── client
│ └── config.jsonContenido del archivo 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", # dirección local de la VM
"start_join": ["172.30.0.15"], # dirección remota del servidor Consul
"ports": {
"dns": 53
}Guardamos los cambios y pasamos a la configuración del archivo de servicio, su contenido es:
/etc/systemd/system/consul.service:
[Unit]
Description="HashiCorp Consul - Una solución de malla de servicios"
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.targetIniciamos Consul en el servidor. Ahora, después de iniciar, debemos ver el servicio configurado en nsul members. Esto indicará que se ha conectado correctamente al clúster como cliente. Repita lo mismo en el segundo servidor y después de eso podremos proceder a la instalación y configuración de Nomad.
La instalación de Nomad se describe con más detalle en su documentación oficial. Hay dos métodos tradicionales de instalación: descarga del archivo binario y compilación desde el código fuente. Yo elegiré el primer método.
Nota: el proyecto está avanzando muy rápido, a menudo se lanzan nuevas actualizaciones. Es posible que para cuando termine el artículo ya esté disponible una nueva versión. Por lo tanto, recomiendo verificar la versión actual de Nomad en ese momento y descargar específicamente esa.
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.dDespués de descomprimir, obtendremos el archivo binario de Nomad que pesa 65 MB, el cual debe ser movido a /usr/local/bin.
Crearemos un directorio de datos para Nomad y editaremos su archivo de servicio (es probable que no exista al principio):
root@nomad-livelinux-01:~# mkdir --parents /opt/nomad
root@nomad-livelinux-01:~# nano /etc/systemd/system/nomad.serviceInsertamos las siguientes líneas:
[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.targetSin embargo, no nos apresuremos a iniciar nomad; aún no hemos creado su archivo de configuración:
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 estructura final del directorio será la siguiente:
/etc/nomad.d/
├── nomad.hcl
└── server.hclEl archivo nomad.hcl debe contener la siguiente configuración:
datacenter = "dc1"
data_dir = "/opt/nomad"Contenido del archivo 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
}No olvides cambiar el archivo de configuración en el segundo servidor; allí se deberá cambiar el valor de la directiva http.
La última tarea en esta etapa es configurar Nginx para el proxy y establecer la autenticación HTTP. Contenido del archivo 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 contraseña";
}
}Ahora podemos acceder al panel web a través de la red externa. Nos conectamos y vamos a la página servers:

Imagen 1. Lista de servidores en el clúster Nomad
Ambos servidores se muestran correctamente en el panel; lo mismo veremos en la salida del comando nomad node status:

Imagen 2. Salida del comando nomad node status
¿Y qué tal desde el lado de Consul? Vamos a verlo. Vamos al panel de control de Consul, en la página de nodes:

Imagen 3. Lista de nodos en el clúster Consul
Ahora tenemos Nomad configurado, funcionando en conjunto con Consul. En esta etapa final, pasaremos a lo más interesante: configuraremos la entrega de contenedores Docker desde Gitlab a Nomad y también hablaremos sobre algunas de sus otras características distintivas.
Creación de Gitlab Runner
Para desplegar imágenes Docker en Nomad, utilizaremos un runner separado con el archivo binario de Nomad dentro (aquí, cabe destacar otra característica de las aplicaciones de Hashicorp: por separado, representan un único archivo binario). Descárgalo en el directorio del runner. Para él, crearemos un Dockerfile sencillo con el siguiente contenido:
FROM alpine:3.9
RUN apk add --update --no-cache libc6-compat gettext
COPY nomad /usr/local/bin/nomad
En este mismo proyecto, creamos .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, tendremos una imagen del runner de Nomad disponible en Gitlab Registry, ahora podemos ir directamente al repositorio del proyecto, crear un Pipeline y configurar el trabajo de Nomad.
Configuración del proyecto
Comenzaremos con el archivo job de Nomad. Mi proyecto en este artículo será bastante primitivo: consistirá en una sola tarea. El contenido de .gitlab-ci será el siguiente:
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: manualAquí la implementación se realiza en modo manual, pero puedes configurarlo para que cambie el contenido del directorio del proyecto. El Pipeline consta de dos etapas: la de construir la imagen y su despliegue en Nomad. En la primera etapa, construimos la imagen Docker y la empujamos a nuestro Registry, y en la segunda corremos nuestro trabajo en Nomad.
trabajo "monitoring-status" {
centros_de_datos = ["dc1"]
migrar {
maximo_paralelo = 3
chequeo_de_salud = "checks"
tiempo_minimo_saludable = "15s"
plazo_saludable = "5m"
}
grupo "zhadan.ltd" {
cuenta = 1
actualizar {
maximo_paralelo = 1
tiempo_minimo_saludable = "30s"
plazo_saludable = "5m"
plazo_progreso = "10m"
revertir_automaticamente = true
}
tarea "service-monitoring" {
controlador = "docker"
configuracion {
imagen = "registry.domain.name/example/project:${CI_COMMIT_SHORT_SHA}"
forzar_descarga = true
autenticar {
nombre_usuario = "gitlab_user"
contrasena = "gitlab_password"
}
mapa_de_puertos {
http = 8000
}
}
recursos {
red {
puerto "http" {}
}
}
}
}
}Tenga en cuenta que tengo un Registry cerrado y para realizar con éxito la descarga de la imagen de Docker necesito autenticarme en él. La mejor solución en este caso es almacenar el nombre de usuario y la contraseña en Vault, integrándolo posteriormente con Nomad. Nomad admite Vault de forma nativa. Pero primero, en Vault estableceremos las políticas necesarias para Nomad, que se pueden cargar:
# 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.jsonAhora, habiendo creado las políticas necesarias, en el bloque de tarea del archivo job.nomad agregaremos la integración con Vault:
vault {
habilitado = true
direccion = "https://vault.domain.name:8200"
token = "token"
}Utilizo la autorización por token y lo escribo directamente aquí; también hay una opción para especificar el token como variable al iniciar el agente de nomad:
$ VAULT_TOKEN= nomad agent -config /path/to/config
Ahora podemos utilizar las claves de Vault. El principio de funcionamiento es simple: creamos un archivo en el trabajo de Nomad que contendrá los valores de las variables, por ejemplo:
template {
data = <<EOH
{{with secret "secrets/pipeline-keys"}}
REGISTRY_LOGIN="{{ .Data.REGISTRY_LOGIN }}"
REGISTRY_PASSWORD="{{ .Data.REGISTRY_LOGIN }}{{ end }}"
EOH
destino = "secrets/service-name.env"
env = true
}Con este enfoque sencillo se puede configurar la entrega de contenedores en el clúster Nomad y trabajar con él posteriormente. En cuanto a mí, diré que en cierta medida me simpatiza Nomad, ya que es más adecuado para proyectos pequeños donde Kubernetes puede presentar complicaciones adicionales y no podrá realizar su potencial completamente. Además, Nomad es excelente para principiantes, ya que se instala y se configura fácilmente. Sin embargo, al probarlo en algunos proyectos, me he encontrado con problemas en sus versiones anteriores: faltan muchas funciones básicas o no funcionan correctamente. No obstante, creo que Nomad seguirá desarrollándose y en el futuro contará con las funciones necesarias para todos.
Autor: Ilya Andreyev, bajo la dirección de Alexei Zhadan y el equipo de «Live Linux»
Fuente: habr.com
