hashicorp/consul
Architecture
Consul is a single Go binary (consul) that runs in one of two modes — agent (client) or server — plus a CLI. This page maps the runtime topology and the in-process layers.
Cluster topology
Every node in a datacenter runs an agent. A small set (typically 3 or 5) run as servers and form a Raft consensus group. Servers from different datacenters federate over WAN gossip and forward RPCs through the WAN pool.
graph TB
subgraph DC1["Datacenter A (LAN gossip)"]
A1[Client agent<br/>app+sidecar] --> SRV1[Server 1<br/>Raft leader]
A2[Client agent<br/>app+sidecar] --> SRV1
A3[Client agent<br/>app+sidecar] --> SRV1
SRV1 -.Raft.- SRV2[Server 2]
SRV1 -.Raft.- SRV3[Server 3]
end
subgraph DC2["Datacenter B (LAN gossip)"]
B1[Client agent] --> SRV4[Server 1]
SRV4 -.Raft.- SRV5[Server 2]
SRV4 -.Raft.- SRV6[Server 3]
end
SRV1 ==WAN gossip + RPC forward==> SRV4
SRV2 -.WAN.- SRV5
SRV3 -.WAN.- SRV6LAN gossip and WAN gossip are implemented on top of HashiCorp's Serf and memberlist libraries. The server-side Serf handlers live in agent/consul/server_serf.go and agent/consul/client_serf.go; WAN federation logic lives under agent/consul/wanfed/ and agent/consul/leader_federation_state_ae.go.
In-process architecture
graph TB
subgraph CLI["consul CLI (main.go → command/*)"]
CMD[Cobra-style command tree<br/>command/registry.go]
end
subgraph Agent["Agent (agent/agent.go)"]
HTTP[HTTP server<br/>agent/http.go]
DNS[DNS server<br/>agent/dns.go]
Local[Local state<br/>agent/local/]
Cache[RPC cache + materialized views<br/>agent/cache, agent/submatview]
ProxyCfg[Proxy config manager<br/>agent/proxycfg/]
XDS[xDS gRPC server<br/>agent/xds/]
Checks[Health checks<br/>agent/checks/]
end
subgraph Server["Server-only (agent/consul/)"]
Raft[Raft + FSM<br/>agent/consul/fsm/]
State[(MemDB state store<br/>agent/consul/state/)]
Endpoints[RPC endpoints<br/>*_endpoint.go]
GRPCInt[Internal gRPC<br/>agent/grpc-internal/]
GRPCExt[External gRPC<br/>agent/grpc-external/]
Leader[Leader loops<br/>agent/consul/leader*.go]
end
CMD --> HTTP
HTTP --> Endpoints
DNS --> Endpoints
HTTP --> Local
Local <--> Endpoints
ProxyCfg --> Cache
XDS --> ProxyCfg
Checks --> Local
Endpoints --> State
Endpoints --> Raft
Raft --> State
Leader --> State
GRPCExt --> Endpoints
GRPCInt --> StateLayered responsibilities
| Layer | Code | Role |
|---|---|---|
| CLI | command/, main.go |
Parse user commands, talk to a running agent over HTTP |
| HTTP API | agent/http.go, agent/*_endpoint.go |
REST surface that the CLI, UI, and integrations consume |
| DNS API | agent/dns.go, agent/dns/ |
DNS interface for service and node lookups |
| Agent runtime | agent/agent.go (157k lines, the central object), agent/setup.go |
Wires every subsystem into one Agent struct, handles config reload |
| Local state | agent/local/ |
Tracks services, checks, and proxies on this node and reconciles with servers via anti-entropy (agent/ae/) |
| RPC cache | agent/cache/, agent/cache-types/, agent/submatview/ |
Caches RPC results and supports streaming updates so blocking queries don't hammer the leader |
| Proxy config | agent/proxycfg/, agent/proxycfg-glue/, agent/proxycfg-sources/ |
Computes the proxy snapshot (clusters, listeners, routes, endpoints, secrets) for each registered Connect proxy |
| xDS server | agent/xds/ |
Translates proxy snapshots into Envoy xDS resources and streams them over delta-xDS |
| Server core | agent/consul/server.go (68k LoC), agent/consul/client.go |
Joins Raft, exposes RPC, runs leader-only loops |
| Raft + FSM | agent/consul/fsm/, agent/consul/raft_handle.go |
Applies replicated log entries to the in-memory state store |
| State store | agent/consul/state/ (built on go-memdb) |
The authoritative in-memory database with watch indices |
| RPC endpoints | agent/consul/*_endpoint.go (catalog, health, kvs, acl, intention, connect_ca, prepared_query, txn, ...) |
Net/RPC handlers that read/write through Raft for writes and from MemDB for reads |
| gRPC | agent/grpc-internal/, agent/grpc-external/, proto-public/ (DNS, ACL, ConnectCA, dataplane, server discovery, resource, multicluster) |
Internal control-plane gRPC and external public APIs |
| V2 resource framework | internal/resource/, internal/controller/, internal/storage/ |
Generic resource/controller machinery used by the next-generation v2 catalog and multicluster APIs |
| Service mesh | agent/connect/, connect/, agent/consul/leader_connect_ca.go, agent/consul/connect_ca_endpoint.go |
CA management, leaf cert issuance, intentions, identity |
| Auto-config | agent/auto-config/, agent/consul/auto_config_endpoint.go |
Bootstrap and TLS material distribution to client agents |
| Snapshots | agent/consul/fsm/snapshot.go, snapshot/ |
Save/restore the Raft FSM to a binary archive |
Read and write paths
sequenceDiagram
participant App
participant Agent as Local agent
participant Server as Server (follower)
participant Leader as Server (Raft leader)
participant State as MemDB state store
App->>Agent: HTTP PUT /v1/kv/foo
Agent->>Server: RPC KVS.Apply
Server->>Leader: forward (RPC, if not leader)
Leader->>Leader: Raft.Apply(log)
Leader->>State: FSM applies entry
State-->>Leader: index updated
Leader-->>Server: ok
Server-->>Agent: ok
Agent-->>App: 200 OK
App->>Agent: GET /v1/kv/foo?index=42
Agent->>Server: RPC KVS.Get (blocking)
Server->>State: blocking query (waits for index > 42)
State-->>Server: new value, index 43
Server-->>Agent: payload
Agent-->>App: 200 OKWrites go through Raft. Reads go through MemDB and use blocking queries (long polling on a memdb watch index). Reads can also be served via the gRPC streaming subscribe backend (agent/consul/subscribe_backend.go, agent/consul/stream/) and the materialized-view cache (agent/submatview/).
Service mesh data path
graph LR
Manager[proxycfg.Manager<br/>agent/proxycfg/manager.go] -->|snapshot| XDS
XDS[xDS server<br/>agent/xds/server.go,delta.go] -->|CDS/EDS/LDS/RDS/SDS<br/>delta xDS over gRPC| Envoy
LeafCert[leafcert<br/>agent/leafcert/] -->|leaf cert| Manager
CA[Connect CA<br/>agent/consul/leader_connect_ca.go] -->|root CA| Manager
Catalog[Catalog/health watches] -->|targets, endpoints| Manager
Intentions[Intentions<br/>agent/consul/intention_endpoint.go] -->|RBAC rules| Manager
Manager -->|extensions runtime| Ext[envoyextensions/<br/>extensionruntime]
Ext --> XDSThe proxy config manager fetches everything an Envoy needs (clusters, endpoints, routes, secrets, intentions, JWT providers, gateway state, ...), assembles a ConfigSnapshot, and hands it to the xDS server, which serializes Envoy resources and streams them with the delta-xDS protocol.
Sub-modules
The repo is a Go workspace. Each of these has its own go.mod:
| Module | Purpose |
|---|---|
Root (github.com/hashicorp/consul) |
The consul binary (agent, server, CLI) |
api/ |
Public Go HTTP client used by the CLI, integrations, and external Go apps |
sdk/ |
Test helpers: freeport, iptables, testutil, certificate helpers, etc. |
envoyextensions/ |
Envoy extension framework + bundled extensions and xdscommon |
proto-public/ |
Public protobuf packages (pbacl, pbconnectca, pbdataplane, pbdns, pbresource, pbserverdiscovery, ...) |
troubleshoot/ |
Library used by consul troubleshoot to diagnose mesh wiring |
See Packages for the per-module deep dive.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.