Consul - это проект с открытым исходным кодом от HashiCorp . Обеспечивает обнаружение сервисов, проверку работоспособности, балансировку нагрузки, граф сервисов, принудительное использование идентификационных данных с помощью TLS и управление конфигурацией распределенных сервисов. В сети достаточно много описаний этого проекта, на пример на xakep.ru .

Service Discovery

Клиенты Consul могут зарегистрировать сервис, такой как api или mysql и остальные клиенты могут использовать Consul для обнаружения поставщиков данного сервиса. Используя DNS или HTTP, приложения могут легко находить службы, от которых они зависят.

Health Checking

Клиенты Consul могут предоставлять любое количество проверок работоспособности, связанных либо с данной службой («вернул ли веб-сервер 200 OK»), либо с локальным узлом («использование памяти ниже 90%»). Эта информация может использоваться для отслеживания работоспособности кластера, а также компонентами обнаружения служб для маршрутизации трафика от неисправных узлов.

Для примера работы с Consul агентом на Go нам понадобится пакет для работы с API:

go get -u github.com/hashicorp/consul/api

Ниже код простого веб сервиса

package main

import (
    "fmt"
    "net/http"
    "time"

    "github.com/hashicorp/consul/api"
)

func main() {
    // Get a new client
    client, err := api.NewClient(api.DefaultConfig())
    if err != nil {
        panic(err)
    }

    // Register a service
    err = client.Agent().ServiceRegister(&api.AgentServiceRegistration{
        Name: "api",
        Address: "127.0.0.1",
        ID:      "api",
        Check:   &api.AgentServiceCheck{
            HTTP:     "http://127.0.0.1:8080/healthz",
            Interval: "5s",
            Timeout:  "1s",
        },
        Connect: &api.AgentServiceConnect{
            Native: true,
        },
    })
    if err != nil {
        panic(err)
    }

    // Deregister service
    defer func() {
        client.Agent().ServiceDeregister("api")
    }()

    // Make a simple HTTP server
    http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
        now := time.Now()
        fmt.Fprintf(w, "%s", now.String())
    })
    if err := http.ListenAndServe(":8080", nil); err != nil {
        panic(err)
    }
}

Запустим Consul агент и наш веб сервис

consul agent -dev
go run main.go

и проверим

$ dig +noall +answer @127.0.0.1 -p 8600 api.service.dc1.consul
api.service.dc1.consul.	0	IN	A	127.0.0.1

$ curl -s http://127.0.0.1:8500/v1/health/service/api?passing
[
    {
        "Node": {
            "ID": "a4ebf14c-6ab0-cc51-66fc-60a08607a81b",
            "Node": "mira.home",
            "Address": "127.0.0.1",
            "Datacenter": "dc1",
            "TaggedAddresses": {
                "lan": "127.0.0.1",
                "lan_ipv4": "127.0.0.1",
                "wan": "127.0.0.1",
                "wan_ipv4": "127.0.0.1"
            },
            "Meta": {
                "consul-network-segment": ""
            },
            "CreateIndex": 10,
            "ModifyIndex": 11
        },
        "Service": {
            "ID": "api",
            "Service": "api",
            "Tags": [],
            "Address": "127.0.0.1",
            "TaggedAddresses": {
                "lan_ipv4": {
                    "Address": "127.0.0.1",
                    "Port": 0
                },
                "wan_ipv4": {
                    "Address": "127.0.0.1",
                    "Port": 0
                }
            },
            "Meta": null,
            "Port": 0,
            "Weights": {
                "Passing": 1,
                "Warning": 1
            },
            "EnableTagOverride": false,
            "Proxy": {
                "MeshGateway": {},
                "Expose": {}
            },
            "Connect": {
                "Native": true
            },
            "CreateIndex": 40,
            "ModifyIndex": 40
        },
        "Checks": [
            {
                "Node": "mira.home",
                "CheckID": "serfHealth",
                "Name": "Serf Health Status",
                "Status": "passing",
                "Notes": "",
                "Output": "Agent alive and reachable",
                "ServiceID": "",
                "ServiceName": "",
                "ServiceTags": [],
                "Type": "",
                "Definition": {},
                "CreateIndex": 10,
                "ModifyIndex": 10
            },
            {
                "Node": "mira.home",
                "CheckID": "service:api",
                "Name": "Service 'api' check",
                "Status": "passing",
                "Notes": "",
                "Output": "HTTP GET http://127.0.0.1:8080/healthz: 200 OK Output: 2021-01-04 17:51:47.126471 +0300 MSK m=+2.001362645",
                "ServiceID": "api",
                "ServiceName": "api",
                "ServiceTags": [],
                "Type": "http",
                "Definition": {},
                "CreateIndex": 40,
                "ModifyIndex": 41
            }
        ]
    }
]