Skip to content

Consul

Consul est une solution qui permet aux équipes de gérer de manière sécurisée les connexions réseau entre les services dans des environnements préinstallés et multicloud. Il offre une série de fonctionnalités telles que la découverte de services, le maillage de services, la gestion du trafic et la mise à jour automatique de l'infrastructure réseau.

Documentation officielle : Consul by HashiCorp

Dépôt open source : hashicorp/consul

Consul est un outil de découverte et d'enregistrement de services open source de l'entreprise HashiCorp, utilisant l'algorithme d'élection Raft. L'outil lui-même est développé en langage Go, ce qui le rend très léger à déployer. Consul a les caractéristiques suivantes :

  • Découverte de services
  • Enregistrement de services
  • Contrôle de santé
  • Stockage clé-valeur
  • Centres de données multiples

En réalité, Consul peut faire plus que de la découverte de services, il peut aussi servir de centre de configuration distribué. Il existe de nombreux autres outils open source similaires comme Zookeeper, Nacos, nous ne les présenterons pas davantage ici.

Installation

Pour Ubuntu, exécutez les commandes suivantes pour installer avec apt

sh
$ wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
$ echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
$ sudo apt update && sudo apt install consul

Vous pouvez aussi télécharger le package d'installation correspondant sur le site officiel Install Consul. Comme Consul est développé en Go, le package d'installation ne contient qu'un seul fichier exécutable binaire, ce qui rend l'installation très pratique. Après une installation réussie, exécutez la commande suivante pour vérifier la version.

sh
$ consul version

Une sortie normale signifie qu'il n'y a pas de problème

Consul v1.16.1
Revision e0ab4d29
Build Date 2023-08-05T21:56:29Z
Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)

Démarrage rapide

Voici comment construire rapidement un nœud Consul unique. Généralement, un nœud unique est utilisé pour les tests pendant le développement. Si l'utilisation d'un nœud unique ne pose pas de problème, il y a de fortes chances qu'un cluster multi-nœuds fonctionne également correctement. La construction d'un nœud unique est très simple, il suffit d'une seule commande

sh
$ consul agent -dev -bind=192.168.48.141 -data-dir=/tmp/consul -ui -node=dev01

La sortie sera généralement la suivante

==> Starting Consul agent...
               Version: '1.16.1'
            Build Date: '2023-08-05 21:56:29 +0000 UTC'
               Node ID: 'be6f6b8d-9668-f7ff-8709-ed57c72ffdec'
             Node name: 'dev01'
            Datacenter: 'dc1' (Segment: '<all>')
                Server: true (Bootstrap: false)
           Client Addr: [127.0.0.1] (HTTP: 8500, HTTPS: -1, gRPC: 8502, gRPC-TLS: 8503, DNS: 8600)
          Cluster Addr: 192.168.48.141 (LAN: 8301, WAN: 8302)
     Gossip Encryption: false
      Auto-Encrypt-TLS: false
           ACL Enabled: false
     Reporting Enabled: false
    ACL Default Policy: allow
             HTTPS TLS: Verify Incoming: false, Verify Outgoing: false, Min Version: TLSv1_2
              gRPC TLS: Verify Incoming: false, Min Version: TLSv1_2
      Internal RPC TLS: Verify Incoming: false, Verify Outgoing: false (Verify Hostname: false), Min Version: TLSv1_2
==> Log data will now stream in as it occurs:
2023-08-25T17:23:33.763+0800 [DEBUG] agent.grpc.balancer: switching server: target=consul://dc1.be6f6b8d-9668-f7ff-8709-ed57c72ffdec/server.dc1 from=<none> to=<none>
2023-08-25T17:23:33.767+0800 [INFO]  agent.server.raft: initial configuration: index=1 servers="[{Suffrage:Voter ID:be6f6b8d-9668-f7ff-8709-ed57c72ffdec Address:192.168.48.141:8300}]"

Expliquons brièvement la signification

  • agent est une sous-commande, c'est la commande principale de Consul. consul agent lance un nouvel agent Consul, chaque nœud est un agent.

  • dev, est le mode de fonctionnement de l'agent, il y a trois modes au total : dev, client, server

  • bind, adresse de communication LAN, le port par défaut est 8301, généralement cette valeur est l'adresse IP interne du serveur

  • advertise, adresse de communication WAN, le port par défaut est 8302, généralement cette valeur est l'adresse IP externe du serveur

  • data-dir, répertoire de stockage des données

  • config-dir, répertoire de stockage de la configuration, Consul lit tous les fichiers JSON du répertoire

  • bootstrap, indique que le serveur actuel entre en mode bootstrap, il se donnera un vote lors de l'élection Raft. Il ne peut pas y avoir plus d'un serveur dans ce mode dans le cluster

  • bootstrap-expect, nombre attendu de serveurs dans le cluster. Avant d'atteindre ce nombre, le cluster ne commencera pas l'élection. Ne peut pas être utilisé avec bootstrap.

  • retry-join, après le démarrage de l'agent, il essaiera continuellement de rejoindre le nœud spécifié. Supporte également les méthodes de découverte des fournisseurs suivants

    aliyun aws azure digitalocean gce hcp k8s linode mdns os packet scaleway softlayer tencentcloud triton vsphere
  • ui, lance l'interface Web

  • node, nom du nœud, doit être unique dans le cluster.

TIP

Pour plus d'informations sur les paramètres de l'agent, consultez Agents - CLI Reference | Consul | HashiCorp Developer. Notez que certains paramètres ne sont disponibles que dans la version entreprise.

Une fois lancé avec succès, accédez à 127.0.0.1:8500 pour voir l'interface Web.

L'icône de dev01 est une étoile, ce qui indique qu'il s'agit du nœud leader.

Pour quitter, afin que les autres nœuds puissent percevoir la sortie du nœud actuel, il n'est pas recommandé de tuer le processus de force. Utilisez plutôt la commande

sh
consul leave

ou

sh
consul force-leave

Vous pouvez aussi utiliser ctrl+c pour laisser l'agent Consul quitter proprement.

Concepts

Ceci est un schéma d'un cluster Consul. L'image est divisée en deux parties : le plan de contrôle et le plan de données. Consul ne gère que le plan de contrôle, divisé en cluster de serveurs et clients. Le cluster de serveurs est lui-même divisé en followers et leader. Dans l'ensemble, le cluster Consul de l'image constitue un centre de données. Voici l'explication de quelques termes :

  • Agent (Agent) : Ou plus appropriément appelé nœud. Chaque agent est un processus démon de longue durée qui expose des interfaces HTTP et DNS, responsable des contrôles de santé et de la synchronisation des services.

  • Server (Serveur) : En tant que serveur Consul, ses responsabilités principales sont : participer aux élections Raft, maintenir l'état du cluster, répondre aux requêtes, échanger des données avec d'autres centres de données, et transmettre les requêtes au leader et aux autres centres de données.

  • Client (Client) : Le client est sans état par rapport au serveur. Il ne participe pas aux élections Raft. Son seul travail est de transmettre toutes les requêtes au serveur. La seule chose liée au backend à laquelle il participe est le pool de gossip LAN.

  • Leader (Leader) : Le leader est le chef de tous les serveurs, et il ne peut y en avoir qu'un seul. Le leader est élu via l'algorithme Raft. Chaque leader a son propre mandat. Pendant son mandat, tout autre serveur qui reçoit une requête doit en informer le leader, donc les données du leader sont les plus à jour.

  • Gossip (Rumeur) : Consul est construit sur Serf (un autre produit de la même entreprise). Il utilise le protocole gossip, un protocole dédié à la communication aléatoire entre nœuds, similaire à UDP. Consul utilise ce protocole pour la notification mutuelle entre les clusters de services.

  • Data Center (Centre de données) : Un cluster Consul dans un réseau local est appelé un centre de données. Consul supporte les centres de données multiples. Le mode de communication entre centres de données multiples est le gossip WAN.

TIP

Plus de vocabulaire et termes peuvent être consultés sur Glossary | Consul | HashiCorp Developer.

Dans un cluster Consul, le nombre de serveurs doit être strictement contrôlé car ils participent directement au gossip LAN et WAN, aux élections Raft, et doivent stocker des données. Plus il y a de serveurs, plus les coûts de communication sont élevés. En revanche, le nombre de clients peut être plus important sans problème. Ils ne font que transmettre les requêtes, ne participent pas aux élections et consomment très peu de ressources. Dans le cluster de l'image, les différents services s'enregistrent auprès du serveur via les clients. Si un serveur tombe en panne, le client recherche automatiquement un autre serveur disponible.

Exemple de construction de cluster

Construisons un exemple simple de cluster Consul multi-nœuds. Préparons d'abord quatre machines virtuelles

Parmi les quatre machines virtuelles, trois serveurs et un client. La recommandation officielle est que le nombre de serveurs soit impair et idéalement supérieur ou égal à trois. Ici, vm00-vm02 seront des serveurs, vm03 sera un client.

Pour les serveurs, exécutez la commande suivante pour créer un agent serveur

sh
consul agent -server -bind=vm_address -client=0.0.0.0 -data-dir=/tmp/consul/ -node=agent_name -ui

Pour les clients, exécutez la commande suivante pour créer un agent client

sh
consul agent -client=0.0.0.0  -bind=vm_address -data-dir=/tmp/consul/ -node=agent_name -ui

Les commandes exécutées sont respectivement

sh
# vm00
consul agent -server -bind=192.168.48.138 -client=0.0.0.0 -data-dir=/tmp/consul/ -node=agent01 -ui -bootstrap

# vm01
consul agent -server -bind=192.168.48.139 -client=0.0.0.0 -data-dir=/tmp/consul/ -node=agent02 -ui -retry-join=192.168.48.138

# vm02
consul agent -server -bind=192.168.48.140 -client=0.0.0.0 -data-dir=/tmp/consul/ -node=agent03 -ui -retry-join=192.168.48.138

# vm03
consul agent -bind=192.168.48.140 -client=0.0.0.0 -data-dir=/tmp/consul/ -node=agent03 -ui -retry-join=192.168.48.138

Explication de certains paramètres

  • client, 0.0.0.0 signifie accepter toutes les requêtes de toutes les sources. S'il n'y a que le paramètre client sans le paramètre server, cela signifie que l'agent fonctionnera en mode client.

Une fois tous les agents lancés, le rôle de retry-join équivaut à exécuter automatiquement la commande join. En cas d'échec, il continuera à essayer, avec un temps de réessai par défaut de 30s

sh
$ consul join 192.168.48.138

Une fois le join terminé, chaque nœud connaît l'existence des autres. Puisque vm00 a spécifié le mode bootstrap, il est le leader par défaut. Si aucun mode bootstrap n'est spécifié, le nœud spécifié lors du join devient le leader par défaut. Avant que le leader ne soit élu, le cluster ne peut pas fonctionner normalement, l'accès à l'interface Web renverra 500, et certaines commandes ne fonctionneront pas non plus. Si un nœud du cluster a spécifié le mode bootstrap, aucun autre nœud ne devrait spécifier ce mode, et les autres nœuds ne devraient pas utiliser le paramètre bootstrap-expect. S'ils l'utilisent, il sera automatiquement désactivé.

À ce moment, sur le nœud leader (en fait, n'importe quel nœud peut voir), exécutez la commande pour voir les informations des membres du centre de données

sh
$ consul members
Node      Address              Status  Type    Build   Protocol  DC   Partition  Segment
agent01   192.168.48.138:8301  alive   server  1.16.1  2         dc1  default    <all>
agent02   192.168.48.139:8301  alive   server  1.16.1  2         dc1  default    <all>
agent03   192.168.48.140:8301  alive   server  1.16.1  2         dc1  default    <all>
client01  192.168.48.141:8301  alive   client  1.16.1  2         dc1  default    <default>
  • Node, nom du nœud
  • Address, adresse de communication
  • Status, alive signifie en vie, left signifie hors ligne
  • Type, type d'agent, modes serveur et client
  • Build, version Consul utilisée par ce nœud. Consul peut être compatible dans une certaine mesure avec des nœuds de versions différentes
  • Protocol, version du protocole Raft utilisée, ce protocole doit être identique pour tous les nœuds
  • DC, Data Center, centre de données. Tous les nœuds de la sortie appartiennent au centre de données dc1
  • Partition, partition à laquelle appartient le nœud, fonctionnalité de la version entreprise. Chaque nœud ne peut communiquer qu'avec les nœuds de la même partition
  • Segment, segment réseau auquel appartient le nœud, fonctionnalité de la version entreprise

De même, si vous souhaitez qu'un nœud quitte, vous devriez utiliser consul leave pour permettre au nœud de quitter proprement et informer les autres nœuds de son départ. Pour un cluster multi-nœuds, la sortie propre des nœuds est particulièrement importante car elle affecte la cohérence des données.

TIP

Les pare-feu ont été désactivés sur les machines virtuelles pour la démonstration. Dans un environnement de production réel, par sécurité, ils devraient être activés. Pour cela, consultez tous les ports utilisés par Consul : Required Ports | Consul | HashiCorp Developer.

Testons ensuite la cohérence des données. Sur la machine virtuelle vm00, ajoutons les données suivantes

sh
$ consul kv put sys_confg {"name":"consul"}
Success! Data written to: sys_confg

Après enregistrement, via l'API HTTP, accédez aux autres nœuds et vous verrez que les données existent également (la valeur est encodée en base64)

sh
$ curl http://192.168.48.138:8500/v1/kv/sys_confg
[{"LockIndex":0,"Key":"sys_confg","Flags":0,"Value":"ewogICJuYW1lIjoiY29uc3VsIgp9","CreateIndex":2518,"ModifyIndex":2518}]
$ curl http://192.168.48.139:8500/v1/kv/sys_confg
[{"LockIndex":0,"Key":"sys_confg","Flags":0,"Value":"ewogICJuYW1lIjoiY29uc3VsIgp9","CreateIndex":2518,"ModifyIndex":2518}]
$ curl http://192.168.48.140:8500/v1/kv/sys_confg
[{"LockIndex":0,"Key":"sys_confg","Flags":0,"Value":"ewogICJuYW1lIjoiY29uc3VsIgp9","CreateIndex":2518,"ModifyIndex":2518}]

En fait, la fonction de découverte et d'enregistrement de services fournie par Consul diffuse aux autres nœuds via le protocole gossip, et lorsque n'importe quel nœud rejoint le centre de données actuel, tous les nœuds perçoivent ce changement.

Exemple de construction multi-centres de données

Préparez cinq machines virtuelles. vm00-vm02 est le cluster de l'exemple précédent, appartenant au centre de données dc1, qu'on laisse tel quel. vm03-vm04 appartiennent au centre de données dc2. Le centre de données par défaut au démarrage de l'agent est dc1.

TIP

Pour cette démonstration, seuls les serveurs sont construits, sans clients.

D'abord, démarrez vm03 comme leader par défaut

sh
$ consul agent -server -datacenter=dc2 -bind=192.168.48.141 -client=0.0.0.0 -data-dir=/tmp/consul/ -node=agent04 -ui -bootstrap

Démarrez vm04 pour qu'il rejoigne automatiquement le nœud vm03

sh
$ consul agent -server -datacenter=dc2 -bind=192.168.48.142 -client=0.0.0.0 -data-dir=/tmp/consul/ -node=agent05 -ui -retry-join=192.168.48.141

Maintenant, regardez les members sur vm00 et vm03 respectivement

sh
# vm00-vm02
$ consul members
Node      Address              Status  Type    Build   Protocol  DC   Partition  Segment
agent01   192.168.48.138:8301  alive   server  1.16.1  2         dc1  default    <all>
agent02   192.168.48.139:8301  alive   server  1.16.1  2         dc1  default    <all>
agent03   192.168.48.140:8301  alive   server  1.16.1  2         dc1  default    <all>

# vm03-vm04
$ consul members
Node     Address              Status  Type    Build   Protocol  DC   Partition  Segment
agent04  192.168.48.141:8301  alive   server  1.16.1  2         dc2  default    <all>
agent05  192.168.48.142:8301  alive   server  1.16.1  2         dc2  default    <all>

On peut voir que le champ DC est différent. Comme c'est une démonstration sur machines virtuelles, tout est dans le même segment réseau. En réalité, deux centres de données pourraient être des clusters de serveurs dans des lieux différents. Ensuite, faites rejoindre n'importe quel nœud de dc1 à n'importe quel nœud de dc2. Ici, faisons rejoindre vm01 à vm03

sh
$ consul join -wan 192.168.48.141
Successfully joined cluster by contacting 1 nodes.

Après le join réussi, exécutez la commande pour voir les members WAN

sh
$ consul members -wan
Node         Address              Status  Type    Build   Protocol  DC   Partition  Segment
agent01.dc1  192.168.48.138:8302  alive   server  1.16.1  2         dc1  default    <all>
agent02.dc1  192.168.48.139:8302  alive   server  1.16.1  2         dc1  default    <all>
agent03.dc1  192.168.48.140:8302  alive   server  1.16.1  2         dc1  default    <all>
agent04.dc2  192.168.48.141:8302  alive   server  1.16.1  2         dc2  default    <all>
agent05.dc2  192.168.48.142:8302  alive   server  1.16.1  2         dc2  default    <all>

$ consul catalog datacenters
dc2
dc1

Il suffit qu'un nœud de dc1 rejoigne n'importe quel nœud de dc2 pour que tous les nœuds des deux centres de données perçoivent ce changement. Vous pouvez aussi voir les nœuds des deux centres de données en consultant les members.

Ensuite, essayons d'ajouter une donnée KV sur le nœud vm00

sh
$ consul kv put name consul
Success! Data written to: name

Sur le nœud vm01, essayons de lire les données. On peut voir que les données du même centre de données sont synchronisées

sh
$ consul kv get name
consul

Puis allons sur vm03 d'un centre de données différent pour essayer de lire les données. On constate que les données des différents centres de données ne sont pas synchronisées.

sh
$ consul kv get name
Error! No key exists at: name

Si vous souhaitez synchroniser les données entre plusieurs centres de données, vous pouvez consulter hashicorp/consul-replicate: Consul cross-DC KV replication daemon.

Enregistrement et découverte de services

Il y a deux façons d'enregistrer des services Consul : l'enregistrement par fichier de configuration et l'enregistrement par API. Pour faciliter les tests, nous avons préparé un service Hello World (l'exemple de l'article gRPC), déployé en deux exemplaires à des endroits différents. Pour l'enregistrement par fichier de configuration, consultez Register external services with Consul service discovery | Consul | HashiCorp Developer. Ici, nous présentons uniquement l'enregistrement via l'API HTTP.

TIP

Pour les services locaux (co-localisés avec le client Consul), vous pouvez utiliser directement agent service pour l'enregistrement. Sinon, vous devriez utiliser catalog register.

Consul fournit un SDK pour l'API HTTP. Pour les SDK dans d'autres langages, consultez Libraries and SDKs - HTTP API | Consul | HashiCorp Developer. Ici, téléchargez la dépendance Go

sh
go get github.com/hashicorp/consul/api

Au démarrage du service, enregistrez-le activement auprès de Consul. À l'arrêt du service, désenregistrez-le auprès de Consul. Voici un exemple.

go
package main

import (
  consulapi "github.com/hashicorp/consul/api"
  "google.golang.org/grpc"
  "google.golang.org/grpc/credentials/insecure"
  pb "grpc_learn/helloworld/hello"
  "log"
  "net"
)

var (
  server01 = &consulapi.AgentService{
        // Doit rester unique
    ID:      "hello-service1",
    Service: "hello-service",
        // Déployé en deux exemplaires, un sur le port 8080, un sur le port 8081
    Port:    8080,
  }
)

// Enregistrer le service
func Register() {
  client, _ := consulapi.NewClient(&consulapi.Config{Address: "192.168.48.138:8500"})
  _, _ = client.Catalog().Register(&consulapi.CatalogRegistration{
    Node:    "hello-server",
    Address: "192.168.2.10",
    Service: server01,
  }, nil)
}

// Désenregistrer le service
func DeRegister() {
  client, _ := consulapi.NewClient(&consulapi.Config{Address: "192.168.48.138:8500"})
  _, _ = client.Catalog().Deregister(&consulapi.CatalogDeregistration{
    Node:      "hello-server",
    Address:   "192.168.2.10",
    ServiceID: server01.ID,
  }, nil)
}

func main() {
  Register()
  defer DeRegister()

  // Écouter le port
  listen, err := net.Listen("tcp", ":8080")
  if err != nil {
    panic(err)
  }
  // Créer le serveur gRPC
  server := grpc.NewServer(
    grpc.Creds(insecure.NewCredentials()),
  )
  // Enregistrer le service
  pb.RegisterSayHelloServer(server, &HelloRpc{})
  log.Println("server running...")
  // Exécuter
  err = server.Serve(listen)
  if err != nil {
    panic(err)
  }
}

Le code client utilise un résolveur personnalisé Consul pour interroger le service correspondant auprès du registre et le résoudre en adresse réelle.

go
package myresolver

import (
    "fmt"
    consulapi "github.com/hashicorp/consul/api"
    "google.golang.org/grpc/resolver"
)

func NewConsulResolverBuilder(address string) ConsulResolverBuilder {
    return ConsulResolverBuilder{consulAddress: address}
}

type ConsulResolverBuilder struct {
    consulAddress string
}

func (c ConsulResolverBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {
    consulResolver, err := newConsulResolver(c.consulAddress, target, cc)
    if err != nil {
       return nil, err
    }
    consulResolver.resolve()
    return consulResolver, nil
}

func (c ConsulResolverBuilder) Scheme() string {
    return "consul"
}

func newConsulResolver(address string, target resolver.Target, cc resolver.ClientConn) (ConsulResolver, error) {
    var reso ConsulResolver
    client, err := consulapi.NewClient(&consulapi.Config{Address: address})
    if err != nil {
       return reso, err
    }
    return ConsulResolver{
       target: target,
       cc:     cc,
       client: client,
    }, nil
}

type ConsulResolver struct {
    target resolver.Target
    cc     resolver.ClientConn
    client *consulapi.Client
}

func (c ConsulResolver) resolve() {
    service := c.target.URL.Opaque
    services, _, err := c.client.Catalog().Service(service, "", nil)
    if err != nil {
       c.cc.ReportError(err)
       return
    }
    var adds []resolver.Address
    for _, catalogService := range services {
       adds = append(adds, resolver.Address{Addr: fmt.Sprintf(fmt.Sprintf("%s:%d", catalogService.Address, catalogService.ServicePort))})
    }

    c.cc.UpdateState(resolver.State{
       Addresses: adds,
       // Stratégie de round-robin
       ServiceConfig: c.cc.ParseServiceConfig(
          `{"loadBalancingPolicy":"round_robin"}`),
    })
}

func (c ConsulResolver) ResolveNow(options resolver.ResolveNowOptions) {
    c.resolve()
}

func (c ConsulResolver) Close() {

}

Le client enregistre le résolveur au démarrage

go
package main

import (
    "context"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/insecure"
    "google.golang.org/grpc/resolver"
    "grpc_learn/helloworld/client/myresolver"
    hello2 "grpc_learn/helloworld/hello"
    "log"
    "time"
)

func init() {
    // Enregistrer le builder
    resolver.Register(
       // Enregistrer le résolveur Consul personnalisé
       myresolver.NewConsulResolverBuilder("192.168.48.138:8500"),
    )
}

func main() {

    // Établir la connexion, sans chiffrement
    conn, err := grpc.Dial("consul:hello-service",
       grpc.WithTransportCredentials(insecure.NewCredentials()),
    )
    if err != nil {
       panic(err)
    }
    defer conn.Close()
    // Créer le client
    client := hello2.NewSayHelloClient(conn)
    for range time.Tick(time.Second) {
       // Appel distant
       helloRep, err := client.Hello(context.Background(), &hello2.HelloReq{Name: "client"})
       if err != nil {
          panic(err)
       }
       log.Printf("received grpc resp: %+v", helloRep.String())
    }

}

Démarrez d'abord le serveur, puis le client. Il y a deux serveurs qui fournissent le même service, mais avec des adresses différentes. La stratégie d'équilibrage de charge du client est le round-robin. On peut voir dans les logs du serveur que la stratégie fonctionne, en regardant l'intervalle de temps.

2023/08/29 17:39:54 server running...
2023/08/29 21:03:46 received grpc req: name:"client"
2023/08/29 21:03:48 received grpc req: name:"client"
2023/08/29 21:03:50 received grpc req: name:"client"
2023/08/29 21:03:52 received grpc req: name:"client"
2023/08/29 21:03:54 received grpc req: name:"client"
2023/08/29 21:03:56 received grpc req: name:"client"
2023/08/29 21:03:58 received grpc req: name:"client"
2023/08/29 21:04:00 received grpc req: name:"client"

Ceci est un exemple simple d'enregistrement et de découverte de services utilisant Consul combiné avec gRPC.

Golang by www.golangdev.cn edit