HashiCorp Nomad Kurulumu: Cluster Yapisi ve Job Yonetimi
Ölçek küçüldüğünde Kubernetes bir külfete dönüşüyor. CRD'ler, admission webhook'lar, controller'lar, bir de üstüne ingress sınıfı tartışmaları... Docker Swarm'ın terk edilmesinden sonra elinde kalan boşluğu doldurmak isteyen ekiplerin bir kısmı HashiCorp'un Nomad'ine geçti. Tek bir Go binary'si. Harici bir coordination servisi, harici bir storage sistemi istemiyor. Kurulumu dakikalar, kavram seti bir öğleden sonrada öğreniliyor.
Nomad'ın iddiası şu: konteyner (docker, podman), konteyner olmayan uygulama (native executable, Java jar), hatta sanal makine (qemu) hepsini tek orkestratörle yönet. Task driver eklentisiyle yeni bir çalıştırma tipi eklemek mümkün. Batarya dahil değil yaklaşımı da önemli: servis keşfi için Consul, secret yönetimi için Vault ayrı ürünler. Nomad çekirdek olarak sadece scheduling ve resource management yapıyor. Kubernetes'in her şeyi içinde barındırmasından farklı bir felsefe bu.
Agent mimarisi ve Raft
Nomad iki rolde çalışır: server ve client. İkisi de aynı binary, agent konfigürasyonuyla rol belirleniyor. Server'lar cluster durumunu yönetir, job kabul eder, hangi task'ın hangi client'a yerleşeceğine karar verir. Client'lar kendilerini server'a kaydeder, kendilerine tahsis edilen task'ları çalıştırır. Agent aynı anda hem server hem client olabilir, küçük ortamlarda tek düğüm böyle kurulur.
Consensus için Raft kullanılıyor. Leader seçimi çoğunlukla yapılır ve server sayısı quorum'u karşılamazsa cluster operasyonel olmaktan çıkar. Resmi dokümantasyon production için 3 ya da 5 server öneriyor. Üç server'dan biri çöktüğünde iki ile devam edilir, beş server iki çökmeyi tolere eder. Server sayısını çift tutmak anlamsızdır, fazladan düğüm quorum'u zorlaştırır.
Server'lar kendi aralarında gossip protokolüyle (serf) konuşur. Bu trafik nomad operator keygen ile üretilen anahtarla şifrelenebilir, production kurulumlarında encrypt parametresi mutlaka dolu olmalı. Cluster yapısını görmek için nomad server members, düğüm durumunu görmek için nomad node status komutları kullanılır. Swarm'daki gibi yalnızca manager üzerinde çalıştırma zorunluluğu yoktur, herhangi bir agent üzerinden sorgulanabilir.
Kurulum
HashiCorp apt reposu eklendiğinde kurulum tek paket. Debian tabanlı sistemlerde repoyu elle eklemek isterseniz:
echo "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update
sudo apt install nomad RHEL tarafında yum-config-manager ile hashicorp.repo eklenip yum install nomad yapılıyor, resmi kurulum sayfasında ikisi de belgelenmiş. Binary elle de kurulabilir: releases.hashicorp.com adresinden zip indirilir, /usr/local/bin altına açılır. Versiyon kontrolü nomad version ile.
Paket kurulduğunda /etc/nomad.d/nomad.hcl içinde tek düğümlük varsayılan bir konfigürasyon gelir. systemd servisi olarak ayağa kaldırmak için resmi unit dosyası kullanılabilir: ExecStart satırı /usr/bin/nomad agent -config=/etc/nomad.d şeklinde, KillSignal SIGINT, Restart on-failure. Sonrasında systemctl enable nomad ve systemctl restart nomad.
Kümeyi büyütmek
Çok düğümlü yapıda roller ayrılır. Üç server üstünde /etc/nomad.d/altında server konfigürasyonu:
datacenter = "dc1"
data_dir = "/opt/nomad/data"
bind_addr = "0.0.0.0"
server {
enabled = true
bootstrap_expect = 3
} bootstrap_expect = 3, cluster'ın üç server gördükten sonra leader seçimine gideceğini söyler. İki server daha kurana kadar cluster oluşmaz, bu normaldir. Client tarafında ise server adresleri listelenir:
client {
enabled = true
servers = ["10.0.0.11:4647", "10.0.0.12:4647", "10.0.0.13:4647"]
} Her agent üç port açar: 4646 HTTP API ve web arayüzü, 4647 RPC, 4648 serf gossip. Firewall kurallarında bu üçünün cluster içi trafiğe açık olması gerekir. HTTP arayüzü 4646 üzerinden /ui path'inde çalışır, job ve allocation durumunu görsel olarak takip etmek için yeterli.
Job, group, task, allocation
Nomad'ın tarif hiyerarşisi job -> group -> task -> allocation. Job, HCL ile yazılan declaratif tanım. Group, aynı client üzerinde birlikte çalışan task koleksiyonu; bir grubun task'ları tek allocation birimi olarak aynı düğüme yerleşir, aralarında port ve volume paylaşımı yapılabilir. Task en küçük çalıştırma birimi ve çalıştırma şekli driver ile belirlenir: docker, podman, exec, raw_exec, java, qemu. Bir grup içinde farklı driver'ları karıştırmak mümkün, Java jar'ı ile Redis konteynerini aynı grupta çalıştırabilirsiniz.
Allocation, task group ile client düğümü arasındaki eşleşmenin adı. Job submit edildiğinde scheduler uygun düğümleri bulur, her group için bir allocation oluşturur. Kubernetes diliyle konuşursak task Pod'a, group Pod içindeki konteynerler kümesine, allocation da schedule edilmiş Pod instance'ına benzer.
Basit bir example job dosyası üretmek için nomad job init -short komutu çalıştırılır, example.nomad.hcl dosyası oluşur. İçindeki cache group'ında docker driver ile redis:7 imajı çalıştırılır, 500 MHz CPU ve 256 MB bellek talebi belirtilmiştir. Bu değerleri karşılayamayan düğümlere job yerleşmez.
Dört scheduler
Job tanımındaki type alanı scheduler davranışını belirler ve dört seçenek vardır. service uzun ömürlü, kapatılana kadar çalışması beklenen servisler içindir; task çıkışı failure sayılır ve restart ile reschedule politikalarına göre davranılır. Service scheduler kısıtlamaları karşılayan düğümlerin büyük bölümünü skorlar, Google'ın Borg çalışmasından esinlenen best fit algoritmasıyla optimal yerleşimi arar.
batch birkaç dakika ile birkaç gün arasında koşup başarıyla çıkması beklenen kısa görevlerdir. Berkeley'nin Sparrow scheduler'ında tarif edilen power of two choices yöntemiyle aday düğüm sayısı kısıtlanır, service'e göre daha hızlı karar verir. system tipi, kısıtlamaları karşılayan tüm client'larda çalışacak job'lardır; cluster'a sonradan katılan düğümde bile otomatik başlatılır, monitoring agent'ı ve log shipper gibi şeyler için biçilmiş kaftan. sysbatch ise her düğümde bir kez koşup çıkacak tek seferlik komutlar için system ile batch'in birleşimi.
Batch işleri periodic bloğuyla cron benzeri zamanlanabilir, parameterized bloğuyla runtime'da parametre alır hale getirilebilir; parametrelendirilmiş job nomad job dispatch ile tetiklenir. Nomad cron job kavramı periodic batch job'a karşılık gelir.
Ağ tarafı
Job'lar önceden hangi düğüme düşeceğini bilemeyeceği için port tahsisini Nomad yapar. Group içindeki network bloğunda port "http" {} yazarsanız dinamik port atanır, static = 8080 yazarsanız o port reserve edilir. Statik port çakışması yerleşmeyi engeller, dinamik port ise esnekliği artırır. Task süreci atanan porta ${NOMAD_PORT_http} environment değişkeniyle ulaşır.
Network mode seçenekleri: host, bridge, none ve cni/ önekiyle özel CNI konfigürasyonları. Bridge mode'da task grubu izole bir network namespace'e alınır ve Consul service mesh'in ön koşuludur; reference CNI plugin'lerin client'taki cni_path'de kurulu olması gerekir. Bridge sadece Linux client'larda desteklenir, diğer işletim sistemleri host mode'da çalışır. Sürüm 0.12 ile gelen CNI desteği ve multi-interface networking sayesinde ön yüz ve veritabanı ağlarını ayrı arabirimlere bölmek mümkün.
Kubernetes'in aksine Nomad'ın içinde yerleşik bir ingress ya da load balancer primitive'i yok. Fabio, Traefik ya da HAProxy ayrı bir system job olarak cluster'ın her düğümüne kurulur ve Consul servis kayıtlarından yola çıkarak trafiği dağıtır. HAProxy kurulumunda Consul DNS SRV kayıtlarını tüketen bir template mekanizması kullanılıyor, Nomad bir servis ayağa kalktığında template yeni portu config'e işler ve reload tetiklenir.
Günlük işler
Değişikliği deploy etmeden önce nomad job plan çalıştırın. Job dosyasında count'u 1'den 3'e çıkarıp plan çektiğinizde Nomad neyin değişeceğini diff olarak gösterir. Onayladıktan sonra nomad job run ile uygulanır. nomad job status job'ın durumunu ve ona bağlı allocation ID'lerini listeler, nomad alloc status tek allocation'ın detayına iner, nomad alloc logs stdout'u basar. Allocation ID ile nomad alloc fs altındaki dosya sistemine erişilir; dizinlerde ls, dosyalarda cat davranışı gösterir, -tail ve -stat seçenekleri vardır.
Düğüm bakımı için nomad node drain komutu vardır. Drain moduna alınan düğüm ineligible işaretlenir, üzerindeki workload'lar diğer düğümlere taşınır, yeni task kabul edilmez. Bakım bitince eligible ile geri açılır. Job sürüm geçmişini nomad job history gösterir, geri almak için nomad job revert kullanılır. Canary rollout'larda yeni sürümü yaygınlaştırmak nomad job promote ile yapılır. Agent loglarını izlemek istediğinizde nomad monitor devreye girer, -node-id ve -server-id ile filtrelenebilir.
Job'ı silmek nomad job stop. Dev modunda (nomad agent -dev) cluster durumu diske yazılmaz, her başlatmada temiz state ile açılır; test ve öğrenme için tasarlanmış moddur, production'da yeri yoktur.
Consul entegrasyonu ve detaylar
Nomad tek başına scheduling yapar ama Consul yanındayken güçlenir. Consul çalışan bir cluster'ın olduğu ortamda Nomad agent'ı başlatırsanız ayrıca bir şey yapmanıza gerek kalmaz, agent Consul ile konuşup cluster'a kendiliğinden katılır. Servis keşfi, sağlık kontrolü ve service mesh Consul tarafında yürür. Consul ACL token'ı varsa Nomad konfigürasyonundaki consul bloğuna address, auth ve token yazılır. Bir püf noktası: checks_use_advertise = true ayarı, sağlık kontrolünün servisin advertise adresine bağlanmasını sağlar. Varsayılan davranış ilk HTTP servisine gitmek, o yoksa bind_addr'e dönmektir; bind 0.0.0.0 yapıldığında kontrol hata verir, servis kaydı görünür ama sağlıksız düşer.
Docker driver'ın istemci tarafı gereksinimleri: Docker kurulu ve çalışır durumda olacak, Nomad root değilse docker grubuna üye olmalı (sudo usermod -G docker -a nomad). Nomad her task için cpuset cgroup yönetir ve Docker'ın kendi cgroup yönetimiyle uyumlu olması için root gerekebilir. İmaj çekme varsayılan timeout'u 5 dakikadır, image_pull_timeout ile ayarlanır.
Bellek ve CPU değerleri resources bloğunda MHz ve MB cinsinden verilir. Client konfigürasyonunda reserved bloğuyla işletim sistemine ayrılacak CPU, bellek ve disk miktarı belirlenebilir, bu kaynaklar scheduling havuzuna girmez. Düğümlere meta anahtar değerleri (role, env gibi) eklenip job'larda constraint olarak kullanılırsa yerleşim politikası granüler hale gelir.
Docker Swarm'dan göç senaryosu da meşhur. Nomad tarafında job Swarm'daki stack'e, task service'e, allocation konteyner instance'ına denk gelir. Swarm'da group kavramının karşılığı yoktur; Nomad'daki group, task'ların aynı client üzerinde birlikte yerleşmesini garantiler ve bu, veritabanı ile ön yüzün aynı düğüme düşmesi gereken yapılar için belirleyici farktır.
Nomad gerçek production cluster'larında 10 bin düğümün üstüne ölçeklendiğini, çok bölge ve çok bulut federation'ı kutudan çıktığı gibi desteklediğini belirtiyor. Kubernetes'in bütünsel dünyası karşısındaki tercihi sade tutmaktan yana olan ekipler için denemesi ucuz, öğrenmesi hızlı bir yol.