Consul dinamički inventar sa Semaphore-om
Pregled
Ovaj vodič pokazuje kako da koristite HashiCorp Consul kao izvor dinamičkog inventara (Inventory) u Semaphore-u. Umesto ručnog navođenja hostova, Ansible će u vreme izvršavanja upitati Consul katalog da otkrije koje hostove treba da cilja.
Ovaj pristup koristi Python skriptu inventara sačuvanu u vašem git repozitorijumu (Repository). Semaphore automatski pokreće skriptu pri izvršavanju playbook-a.
Preduslovi
- Pokrenut Consul klaster sa registrovanim čvorovima
- Consul ACL token sa pravom čitanja kataloga (samo ako su ACL-ovi uključeni)
- Python 3 instaliran na Semaphore hostu (ili runner-u)
- Git repozitorijum za čuvanje vašeg playbook-a i skripte inventara
Korak 1 — Kreirajte skriptu inventara
Kreirajte fajl pod nazivom inventory/consul_inventory.py u svom repozitorijumu. Ova skripta šalje upite Consul HTTP API-ju i vraća informacije o hostovima u formatu koji Ansible očekuje.
#!/usr/bin/env python3
"""
Consul dynamic inventory for Ansible.
Groups nodes by node_meta values and filters out unhealthy nodes.
"""
import json
import os
import sys
import urllib.request
import ssl
CONSUL_ADDR = os.environ.get("CONSUL_HTTP_ADDR", "https://consul.example.com")
CONSUL_TOKEN = os.environ.get("CONSUL_HTTP_TOKEN", "")
def consul_get(path):
url = f"{CONSUL_ADDR}/v1/{path}"
req = urllib.request.Request(url)
if CONSUL_TOKEN:
req.add_header("X-Consul-Token", CONSUL_TOKEN)
ctx = ssl.create_default_context()
with urllib.request.urlopen(req, context=ctx) as resp:
return json.loads(resp.read())
def is_healthy(node_name):
"""Return True if the node has a passing serfHealth check."""
try:
checks = consul_get(f"health/node/{node_name}")
return any(
c["CheckID"] == "serfHealth" and c["Status"] == "passing"
for c in checks
)
except Exception:
return False
def build_inventory():
inventory = {"_meta": {"hostvars": {}}}
all_hosts = []
for node in consul_get("catalog/nodes"):
name = node["Node"]
if not is_healthy(name):
continue
all_hosts.append(name)
inventory["_meta"]["hostvars"][name] = {
"ansible_host": node["Address"],
"ansible_user": "your_ssh_user",
"ansible_python_interpreter": "/usr/bin/python3",
}
inventory["all"] = {"hosts": all_hosts}
return inventory
if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1] == "--host":
print(json.dumps({}))
else:
print(json.dumps(build_inventory(), indent=2))
Učinite skriptu izvršnom:
chmod +x inventory/consul_inventory.py
Ovu skriptu možete prilagoditi tako da grupiše hostove prema Consul metapodacima čvorova, tagovima servisa ili datacentrima. Gornji primer je minimalna polazna tačka.
Korak 2 — Podesite repozitorijum
Vaš repozitorijum bi trebalo da izgleda ovako:
my-project/
├── inventory/
│ └── consul_inventory.py
└── playbook.yml
Ovaj pristup koristi samo Python standardnu biblioteku za direktne upite Consul API-ju. Za rad skripte inventara nisu potrebne dodatne Ansible kolekcije.
Jednostavan testni playbook (playbook.yml):
- hosts: all
gather_facts: false
tasks:
- name: Hello World
ansible.builtin.debug:
msg: "Hello from {{ inventory_hostname }}"
Pošaljite (push) ovaj repozitorijum svom git provajderu.
Korak 3 — Podesite Semaphore
Dodajte grupu promenljivih
Skripta inventara čita Consul adresu i token iz promenljivih okruženja. Kreirajte grupu promenljivih (Variable Group) u Semaphore-u da biste prosledili ove vrednosti.
- Idite na svoj projekat (Project) i kliknite Grupe promenljivih (Variable Group)
- Kliknite Nova grupa promenljivih (New Variable Group)
- Dajte joj naziv (npr.
consul-inventory) - Pod Promenljive okruženja (Environment Variables) dodajte:
CONSUL_HTTP_ADDR=https://consul.example.comCONSUL_HTTP_TOKEN=your-consul-acl-token(potrebno samo ako su ACL-ovi uključeni na vašem Consul klasteru)
- Kliknite Kreiraj (Create)
Ako na vašem Consul klasteru ACL-ovi nisu uključeni, možete izostaviti promenljivu CONSUL_HTTP_TOKEN. Skripta inventara će i dalje raditi — jednostavno neće slati token za autentifikaciju u svojim API zahtevima.
Dodajte repozitorijum
- Idite na Repozitorijumi (Repositories) i kliknite Novi repozitorijum (New Repository)
- Unesite git URL svog repozitorijuma
- Izaberite pristupni ključ za svog git provajdera
- Kliknite Kreiraj (Create)
Dodajte inventar
- Idite na Inventar (Inventory) i kliknite Novi inventar (New Inventory)
- Dajte mu naziv (npr.
consul-dynamic-inventory) - Izaberite File kao tip
- Unesite putanju:
inventory/consul_inventory.py - Izaberite SSH ključ koji će Ansible koristiti za povezivanje na vaše hostove
- Kliknite Kreiraj (Create)
Putanja je relativna u odnosu na koren vašeg git repozitorijuma. Semaphore klonira repozitorijum i prosleđuje ovu putanju komandi ansible-playbook -i inventory/consul_inventory.py.
Kreirajte šablon zadatka
- Idite na Šabloni zadataka (Task Templates) i kliknite Novi šablon (New Template)
- Dajte mu naziv (npr.
Consul Hello World) - Podesite Playbook na
playbook.yml - Izaberite repozitorijum, inventar i grupu promenljivih koje ste kreirali iznad
- Kliknite Kreiraj (Create)
Korak 4 — Pokrenite
Kliknite Pokreni (Run) na svom šablonu zadatka. Semaphore će:
- Klonirati vaš repozitorijum
- Izvršiti playbook koristeći vašu Consul skriptu inventara
- Prikazati izlaz u logu zadatka
Trebalo bi da vidite izlaz sličan ovom:
TASK [Hello World] *************************************************************
ok: [node-01] => {
"msg": "Hello from node-01"
}
ok: [node-02] => {
"msg": "Hello from node-02"
}
Grupisanje hostova prema metapodacima
Consul podržava metapodatke čvorova — parove ključ-vrednost pridružene svakom čvoru. Možete ih koristiti za automatsko kreiranje Ansible grupa.
Dodajte ovo u funkciju build_inventory() u svojoj skripti, nakon postavljanja promenljivih hosta:
# Get node metadata
node_detail = consul_get(f"catalog/node/{name}")
meta = node_detail.get("Node", {}).get("Meta", {})
# Group by metadata keys
for key in ("role", "env", "os"):
val = meta.get(key)
if val:
group = f"{key}_{val}"
inventory.setdefault(group, {"hosts": []})
inventory[group]["hosts"].append(name)
Ovim se kreiraju grupe kao što su role_webserver, env_production ili os_ubuntu. Zatim ih možete ciljati u svojim playbook-ovima:
- hosts: role_webserver
tasks:
- name: Restart nginx
ansible.builtin.service:
name: nginx
state: restarted