Skip to content

Consul

Consul je aplikace distribuovana jako jedina binarka, ktera umi plnit mnoho funkci a roli, ale vsechny tyto funkce se toci kolem:

  • centralizovany registr sluzeb
  • rozlicne konfigurovatelne health checky (tcp, udp, http, https, L7, …)
  • KV uloziste
  • snadno pouzitelne API a DNS interface pro cteni dat
  • mTLS komunikace
  • snadny clustering a rychle sireni dat mezi uzly (diky gRPC protokolu)

Dashboard

Prijemne prostredi urcene pro prehled nad spravovanymi daty (konfigurace probiha po API, CLI, atp)

CLI

Aktivace autocomplete

consul -install-autocomplete

Instalace / Pridani node

Consul

Cela konfigurace probiha prez ansible, po pridani noveho serveru staci jen pridat server do ./env/${ENV}/hosts do sekce metrics-only a nasledne pustit playbook consul.yml, viz priklad nize

ansible-playbook -i env/prod/hosts consul.yml --limit "JMENO_NOVEHO_STROJE"

Konfigurace DNS resolvingu

Jedine co je potreba nastavit je /etc/resolv.conf a to napriklad takto

# na prvnim miste musi byt localhost
nameserver 127.0.0.1
nameserver 1.1.1.1
nameserver 8.8.8.8
...

Nasledne se o resolving stara dnsmasq, ktery routuje pozadavky dle domeny do consula, nebo na nejaky s verejnych DNS serveru.

Pokud by se cokoli rozbilo, staci v /etc/resolv.conf odebrat nameserver 127.0.0.1 a dnsmasq i s consulem bude preskakovan

Pouziti

Consul nam púoskytuje moznost hledat sluzby v infrastrukture pomoci API i DNS.

Prostrednictvim API jsou videt vzdy vsechny servisy v libovolnem stavu a je tedy nutne, kontrolovat jejich stav pred pouzitim ve vasem kodu. Pokud se doptavame na sluzbu prez DNS, je nam vracena vzdy jen dostupna sluzba, v pripade, ze je u ni definovan i health check.

Hledani pomoci DNS

# zakladni dotaz, ktery mi vrati IP na ktere sluzbu najdu
dig @localhost JMENO_SLUZBY.service.internal

# pokud chci nejake doplnkove informace, lze se zeptat jeste takto
# vystup casto obsahuje napriklad port, na kterem sluzbu najdu atp.
dig @localhost JMENO_SLUZBY.service.internal SRV

Pokud mam nastaven v resolv.conf nameserver na localhost v prvnim miste, nemusim uvadet @localhost pri resolvu.

Hledani pomoci API

curl http://localhost:8500/v1/catalog/service/JMENO_SLUZBY?pretty

Priklad querry vcetne vystupu

@~ $  curl http://localhost:8500/v1/catalog/service/consul-ui?pretty
[
    {
        "ID": "1481fe46-b91b-5229-eafd-91febe6a9e98",
        "Node": "node-1",
        "Address": "10.0.6.11",
        "Datacenter": "prod",
        "TaggedAddresses": {
            "lan": "10.0.6.11",
            "lan_ipv4": "10.0.6.11",
            "wan": "10.0.6.11",
            "wan_ipv4": "10.0.6.11"
        },
        "NodeMeta": {
            "consul-network-segment": ""
        },
        "ServiceKind": "",
        "ServiceID": "consul-ui",
        "ServiceName": "consul-ui",
        "ServiceTags": [
            "http",
            "ui",
            "consul"
        ],
        "ServiceAddress": "",
        "ServiceWeights": {
            "Passing": 1,
            "Warning": 1
        },
        "ServiceMeta": {},
        "ServicePort": 8500,
        "ServiceSocketPath": "",
        "ServiceEnableTagOverride": false,
        "ServiceProxy": {
            "Mode": "",
            "MeshGateway": {},
            "Expose": {}
        },
        "ServiceConnect": {},
        "CreateIndex": 133,
        "ModifyIndex": 214
    }
]

Jak pridat sluzbu

Vzorova definice servisy s dvema checky. Nize uvedenou definici ulozime jako node-1-svcs.json

{
  "service": {
    "name": "api",
    "tags": [
      "prometheus",
      "metrics",
      "mysqld_exporter"
    ],
    "port": 80,
    "checks": [
      {
        "name": "Check http",
        "http": "http://localhost/",
        "header": {
            "Host": ["node-1"]
        },
        "interval": "15s",
        "timeout": "5s",
        "failures_before_critical": 3
      },
      {
        "name":  "Graphql check",
        "args": [
            "/usr/local/bin/curl_stats_graphql", 
            "http://localhost/graphql",
            "api",
            "version"
        ],
        "interval": "30s",
        "timeout": "5s",
        "failures_before_critical": 3
      }
    ]
  }
}

V prikladu je nadefinovana graphql sluzba na serveru node-1, sluzba je kazdych 30s kontrolovana jak pomoci skriptu, tak primym dotazem po http. Pokud by check 3x za sebou selhal, bude sluzba oznacena za nefunkcni a bude odebrana z DNS. Pokud bychom tedy pouzivali napriklad v nginxu jako backend adresu api.service.internal, nginx by po 90s vypadku, server vyradil a neposilal na nej requesty.

Takto vytvorenou sluzbu nasledne mohu nasadit nasledujicimi zpusoby:

Po API curlem

curl -X PUT — data-binary @node-1-svcs.json http://<consul-server-ip:8500>/v1/agent/service/register

Pomoci cli nastroje

consul services register node-1-svcs.json

Pridanim staticke konfigurace do adresare na consul serveru

cat > /etc/consul/conf.d/node-1-svcs.json
consul reload

Jak pridat health check

Postup je stejny jako pro servisu, jednoduchy priklad je opet nize

{
  "check": {
    "id": "consul-ui",
    "name": "Check consul-ui health",
    "http": "http://localhost:8500/ui/",
    "method": "GET",
    "service_id": "consul-ui",
    "interval": "10s",
    "timeout": "2s"
  }
}

Pokud chci check navazat primo na konkretni sluzbu a ne cely node, pak je nutne parametr service_id jako je v prikladu nize. Pokud bych tento parametr nepridal, check se navaze na cely server a negativni vysledek jednoho testu pak muze oznacit cely node za nedostupny, pokud to navazu na konkretni sluzbu, je oznacena jen sluzba samotna a to je to co vetsinou chceme.

Tutorial

Zde prikladam odkaz na pekny tutorial v oficialni dokumentaci. Za prohlednuti, ale stoji jiste i dalsi tutorialy, ktere lze najit v menu.

Zalohovani a restore consul databaze

Pokud je consul centrem pravdy a pridavame do nej sluzby skrz API, je zalohovani vic nez zadouci, v pripade, kdy slouzi jen pro sdileni informaci mezi sluzbami a registrace sluzeb tak probiha skrz soubory, nebo externi sluzby (nomad, kubernetes, …), zalohovani neni nutne.

 # Create a snapshot:
consul snapshot save backup.snap

# Restore a snapshot:
consul snapshot restore backup.snap

# Inspect a snapshot:
consul snapshot inspect backup.snap