浅尝consul
先决条件
两台sever,一台client模拟集群情况
docker-compose如下,直接启动即可.
services:
# Consul Server 1
consul-server-1:
image: hashicorp/consul:latest
container_name: consul-server-1
ports:
- "8500:8500" # HTTP API
- "8600:8600/udp" # DNS
command: >
consul agent -server -bootstrap-expect=2 -datacenter=dc1 -data-dir=/consul/data
-retry-join=consul-server-2 -client=0.0.0.0 -bind=0.0.0.0 -ui
volumes:
- consul-server-1-data:/consul/data
networks:
- dev-network
# Consul Server 2
consul-server-2:
image: hashicorp/consul:latest
container_name: consul-server-2
ports:
- "8501:8500" # HTTP API (different port to avoid conflict)
command: >
consul agent -server -bootstrap-expect=2 -datacenter=dc1 -data-dir=/consul/data
-retry-join=consul-server-1 -client=0.0.0.0 -bind=0.0.0.0
volumes:
- consul-server-2-data:/consul/data
networks:
- dev-network
depends_on:
- consul-server-1
# Consul Client
consul-client:
image: hashicorp/consul:latest
container_name: consul-client
ports:
- "8502:8500" # HTTP API (different port to avoid conflict)
command: >
consul agent -datacenter=dc1 -data-dir=/consul/data
-retry-join=consul-server-1 -retry-join=consul-server-2
-client=0.0.0.0 -bind=0.0.0.0
volumes:
- consul-client-data:/consul/data
networks:
- dev-network
depends_on:
- consul-server-1
- consul-server-2
volumes:
consul-server-1-data:
consul-server-2-data:
consul-client-data:
networks:
dev-network:
driver: bridge
跑起来后访问:http://localhost:8500/ui/dc1/nodes 会有3个节点
启动命令中的-server和-client:
-server
以服务方式启动,这个节点可以加入集群,参与选举,接收服务发现信息同步等.
启动时会顺带注册一个consul服务,所有consul程序都会同步这个consul服务.因此在nodes里面可以看到以server启动的consul,service为 1
-client
简单理解成尿袋.即每个pod/宿主机都需要部署一个client端,client启动不会注册consul服务.但是会向leader节点同步service信息
客户端负责接收程序发来的请求,转发给server端,这也就解决了如果是硬编码consul server的ip,如果刚好编码的ip地址服务挂了/换了,就歇逼的问题(如果真出这个问题,那就不是咱们能解决的了 XD ).
Speak you mother,show me your code
package main
import (
"fmt"
consulapi "github.com/hashicorp/consul/api"
"log"
"net/http"
)
var client *consulapi.Client
func startConsul() {
baseConfig := consulapi.DefaultConfig()
baseConfig.Address = "127.0.0.1:8502"
var err error
client, err = consulapi.NewClient(baseConfig)
if err != nil {
log.Fatal(err)
return
}
registration := consulapi.AgentServiceRegistration{
Tags: []string{"user"},
Port: 8080,
Address: "host.docker.internal",
Name: "user-service-east-1",
}
check := consulapi.AgentServiceCheck{
Interval: "15s",
Timeout: "5s",
HTTP: fmt.Sprintf("http://%s:%d", registration.Address, registration.Port),
DeregisterCriticalServiceAfter: "30s",
}
registration.Check = &check
err = client.Agent().ServiceRegister(®istration)
if err != nil {
log.Fatal(err)
return
}
log.Println("consul service registered")
}
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, World!"))
})
startConsul()
if client == nil {
log.Fatal("consul client is nil")
}
testDifferentNodes()
testConsulServiceDetails()
testClientNodeInfo()
log.Fatal(http.ListenAndServe(":8080", nil))
}
func testDifferentNodes() {
addresses := []string{"127.0.0.1:8500", "127.0.0.1:8501", "127.0.0.1:8502"}
for _, addr := range addresses {
config := consulapi.DefaultConfig()
config.Address = addr
client, _ := consulapi.NewClient(config)
services, _, _ := client.Catalog().Services(nil)
log.Printf("节点 %s 的服务:", addr)
for name := range services {
log.Printf(" - %s", name)
}
}
}
func testConsulServiceDetails() {
addresses := []string{"127.0.0.1:8500", "127.0.0.1:8501", "127.0.0.1:8502"}
for _, addr := range addresses {
config := consulapi.DefaultConfig()
config.Address = addr
client, _ := consulapi.NewClient(config)
// 获取consul服务的详细信息
consulServices, _, _ := client.Health().Service("consul", "", false, nil)
log.Printf("节点 %s 上的consul服务:", addr)
for _, service := range consulServices {
log.Printf(" - 服务ID: %s", service.Service.ID)
log.Printf(" - 节点名: %s", service.Node.Node)
log.Printf(" - 节点地址: %s", service.Node.Address)
log.Printf(" - 服务地址: %s:%d", service.Service.Address, service.Service.Port)
}
log.Println("---")
}
}
func testClientNodeInfo() {
config := consulapi.DefaultConfig()
config.Address = "127.0.0.1:8502" // Client节点
client, _ := consulapi.NewClient(config)
// 查看当前节点信息
self, _ := client.Agent().Self()
log.Printf("Client节点信息:")
log.Printf(" - 节点名: %s", self["Config"]["NodeName"])
log.Printf(" - 节点类型: %s", self["Config"]["Server"])
// 查看本地注册的服务
services, _ := client.Agent().Services()
log.Printf("Client本地服务:")
for name := range services {
log.Printf(" - %s", name)
}
}
输出示例
2025/07/18 11:11:52 consul service registered
2025/07/18 11:11:52 节点 127.0.0.1:8500 的服务:
2025/07/18 11:11:52 - user-service-east-1
2025/07/18 11:11:52 - consul
2025/07/18 11:11:52 节点 127.0.0.1:8501 的服务:
2025/07/18 11:11:52 - consul
2025/07/18 11:11:52 - user-service-east-1
2025/07/18 11:11:52 节点 127.0.0.1:8502 的服务:
2025/07/18 11:11:52 - consul
2025/07/18 11:11:52 - user-service-east-1
2025/07/18 11:11:52 节点 127.0.0.1:8500 上的consul服务:
2025/07/18 11:11:52 - 服务ID: consul
2025/07/18 11:11:52 - 节点名: c05b2365cbe8
2025/07/18 11:11:52 - 节点地址: 172.20.0.3
2025/07/18 11:11:52 - 服务地址: :8300
2025/07/18 11:11:52 - 服务ID: consul
2025/07/18 11:11:52 - 节点名: c65d941ab42d
2025/07/18 11:11:52 - 节点地址: 172.20.0.2
2025/07/18 11:11:52 - 服务地址: :8300
2025/07/18 11:11:52 ---
2025/07/18 11:11:52 节点 127.0.0.1:8501 上的consul服务:
2025/07/18 11:11:52 - 服务ID: consul
2025/07/18 11:11:52 - 节点名: c05b2365cbe8
2025/07/18 11:11:52 - 节点地址: 172.20.0.3
2025/07/18 11:11:52 - 服务地址: :8300
2025/07/18 11:11:52 - 服务ID: consul
2025/07/18 11:11:52 - 节点名: c65d941ab42d
2025/07/18 11:11:52 - 节点地址: 172.20.0.2
2025/07/18 11:11:52 - 服务地址: :8300
2025/07/18 11:11:52 ---
2025/07/18 11:11:52 节点 127.0.0.1:8502 上的consul服务:
2025/07/18 11:11:52 - 服务ID: consul
2025/07/18 11:11:52 - 节点名: c05b2365cbe8
2025/07/18 11:11:52 - 节点地址: 172.20.0.3
2025/07/18 11:11:52 - 服务地址: :8300
2025/07/18 11:11:52 - 服务ID: consul
2025/07/18 11:11:52 - 节点名: c65d941ab42d
2025/07/18 11:11:52 - 节点地址: 172.20.0.2
2025/07/18 11:11:52 - 服务地址: :8300
2025/07/18 11:11:52 ---
2025/07/18 11:11:52 Client节点信息:
2025/07/18 11:11:52 - 节点名: 7830f95db485
2025/07/18 11:11:52 - 节点类型: %!s(bool=false)
2025/07/18 11:11:52 Client本地服务:
2025/07/18 11:11:52 - user-service-east-1
从上面可以看到所有节点都同步到了 user-service和consul服务的节点信息.并且consul服务中是没有client节点的consul服务的.
面板中的service和nodes
service
以服务名分类.
nodes
展示所有节点,并显示从其节点注册的服务数.
参阅顶部 nodes图,当你初始化完3个docker后,默认server有1个service,client有0个service.
当你运行go代码注册一个服务后client有1个service,server依旧还是1个service.这也说明了节点下的service数量是从其节点注册的服务数,与存储了多个少service信息无关.
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。