
With only a few services, addresses can be written directly in configuration. More instances mean changing addresses and occasional failures, so we need a place to record which instances currently serve a name. Consul provides service registration, discovery, and health checks.
1. What are registration and discovery?
- Registration: tell Consul the instance ID, service name, address, and port.
- Discovery: query suitable instances by service name, then choose one to call.
- Health checks: track instance status so consumers can filter unhealthy instances.
Registration and business readiness are different. Query health status, and still apply timeouts and error handling to calls. A passing check cannot guarantee the next request will succeed. See Health API。
2. Install and start
This example starts a local development instance with Docker. Version 1.21.3 is fixed to match the recorded learning environment, not as a recommendation to keep production on that version.
docker run -d \
--name dev-consul \
-p 127.0.0.1:8500:8500 \
hashicorp/consul:1.21.3 agent -dev -client=0.0.0.0
Open http://127.0.0.1:8500。-dev enables development mode; do not rely on it to preserve production state after shutdown. The container listens on all addresses for port mapping, while the host binding remains local.


3. Register and discover a service from Go
Initialize a module in a new example directory:
go mod init example.com/consul-demo
Save the following as main.go, then install the dependency as described below.
package main
import (
"fmt"
"net/http"
"os"
"time"
"github.com/hashicorp/consul/api"
)
func run() error {
cfg := api.DefaultConfig()
cfg.Address = "127.0.0.1:8500"
cfg.HttpClient = &http.Client{Timeout: 3 * time.Second}
client, err := api.NewClient(cfg)
if err != nil {
return err
}
registration := &api.AgentServiceRegistration{
ID: "demo-api-1", Name: "demo-api",
Address: "127.0.0.1", Port: 18080,
Check: &api.AgentServiceCheck{TTL: "15s"},
}
if err := client.Agent().ServiceRegister(registration); err != nil {
return err
}
defer func() {
if err := client.Agent().ServiceDeregister(registration.ID); err != nil {
fmt.Println("注销失败:", err)
}
}()
if err := client.Agent().UpdateTTL("service:demo-api-1", "demo heartbeat", "passing"); err != nil {
return err
}
services, _, err := client.Health().Service("demo-api", "", true, nil)
if err != nil {
return err
}
for _, entry := range services {
fmt.Printf("%s %s:%d\n", entry.Service.ID, entry.Service.Address, entry.Service.Port)
}
return nil
}
func main() {
if err := run(); err != nil {
fmt.Fprintln(os.Stderr, "Consul 示例失败:", err)
os.Exit(1)
}
}
After saving the code, install the SDK version used by the example and run it:
go get github.com/hashicorp/consul/api@v1.30.0
go mod tidy
go run .
This version reproduces the API example. Revalidate when changing versions, and retain go.mod and go.sum. The program registers a service, updates its TTL heartbeat, queries healthy instances, and deregisters on exit. It does not start an actual business server on port 18080. The address is example metadata; printing it does not prove the endpoint is ready.The Go SDK API and service registration API can be read together.
In an application, start the business server before registering a reachable address. Update TTL heartbeats periodically and report passing or critical according to the service’s state. An HTTP check is another option if the Consul agent can reach the endpoint.
4. Common pitfalls
A service name is not an instance ID. Multiple instances may be named demo-api, but each needs a distinct ID to avoid overwriting registrations.
The address must be usable by consumers. The address 127.0.0.1 is appropriate only for callers on the same host. Across machines or containers, register an address the caller can actually reach.
Deregistration is only part of failure handling. Clean shutdown can deregister, but a forcibly terminated process still needs health checks. Query healthy instances, and continue handling call timeouts and connection failures.
KV storage is not an interchangeable database. It can hold configuration, but consider permissions, change notifications, and behavior when reads fail.
References
Consul documentation、Health checks、Version 1.21.3 release notes。