Documentation
¶
Index ¶
- Variables
- func MDNSAdvertise(ctx context.Context, nodeConfig *node.NodeConfig) (*mdns.Server, error)
- func ObserveMemberlistPeers(ctx context.Context, logger *zap.Logger, localNodeID uuid.UUID, ...)
- func ResolveAdvertise(bind netip.AddrPort, advertise netip.Addr) netip.AddrPort
- type AnchorResolver
- type MDNSResolver
- type MemberService
- func (m *MemberService) Join(existingMembers []netip.AddrPort) (int, error)
- func (m *MemberService) LocalAddr() (netip.AddrPort, error)
- func (m *MemberService) Members() ([]Node, error)
- func (m *MemberService) Publish() error
- func (m *MemberService) SetAnchor(anchored bool)
- func (m *MemberService) SetPosition(lat, lon float64)
- func (m *MemberService) SetPressure(cpu, mem, disk uint8)
- func (m *MemberService) SetWorkloadCount(n int)
- func (m *MemberService) Shutdown() error
- type MemberlistLogWriter
- type Node
- type NodeMetadata
- type NodeState
- type NoiseIdentity
- type Resolver
- type ResolverFunc
Constants ¶
This section is empty.
Variables ¶
var ( DNSService = "_concord._udp" DNSPort = "8053" )
Service identifiers for Concord peer discovery. The format follows RFC 6763.
* MDNSService (_concord._udp) is used for mDNS / LAN discovery. Nodes on the same local network advertise themselves via multicast. Other nodes discover them by browsing for this service.
* DNSService (_concord._udp) names the embedded DNS server's service. Workloads resolve peer names against it; member discovery no longer queries it, gossip carries membership instead.
var OverlayPrefix = netip.MustParsePrefix("10.0.0.0/16")
OverlayPrefix is the container and WireGuard mesh. Memberlist must not advertise or Join addresses in this range. It must stay disjoint from the underlay NIC.
Functions ¶
func MDNSAdvertise ¶
MDNSAdvertise publishes this node on the local network under DNSService. It advertises only the resolved underlay address, the same one memberlist publishes, so peers never learn overlay endpoints such as cn0 or docker0. Advertising all interfaces leaks those addresses into peer candidate pools, and joining them dials the local bridge instead of a peer. A nil IP list falls back to all interfaces and is used only when no usable address resolves.
func ObserveMemberlistPeers ¶
func ObserveMemberlistPeers( ctx context.Context, logger *zap.Logger, localNodeID uuid.UUID, memberService *MemberService, j journal.Journal, views []journalview.View, )
ObserveMemberlistPeers is passive. It polls the already-joined memberlist every 5 seconds, diffs against the previous snapshot, and records peer.seen, peer.updated, and peer.lost events. It does not query mDNS or DNS SRV and does not call Join. Active discovery is handled by runDiscoveryLoop in runtime. It blocks until context is cancelled.
func ResolveAdvertise ¶
ResolveAdvertise picks the address other peers should dial when contacting this node. Callers pass the memberlist bind address and an optional config override.
advertise is the operator-supplied IP hint (AdvertiseAddress from config). Empty (zero Addr) means the runtime picks one from the bind address or a non-loopback interface. The port always comes from bind regardless.
Resolution order: 1. Advertise hint if set (IP from config, port from bind). 2. The bind address if it is already a real IP peers can dial. 3. Otherwise the first usable host interface IP, with the bind port.
Returns the zero AddrPort only if no usable address exists; memberlist will then choose an interface on its own.
Types ¶
type AnchorResolver ¶
type AnchorResolver struct {
// Self is this node's position, or nil when unknown.
Self *geo.Point
// Anchors is the configured rendezvous list from node config.
Anchors []nodepackage.AnchorEntry
}
AnchorResolver returns configured rendezvous addresses as join candidates. With a known self position it orders nearest-first, so a truck dials its own depot instead of a far anchor that happens to sit first in the list; without one it keeps list order. Entries with out-of-planet coordinates sort last: they may still dial fine, their position just orders nothing. Empty anchors resolve empty, which keeps LAN-only fleets on mDNS alone.
type MDNSResolver ¶
type MemberService ¶
type MemberService struct {
// contains filtered or unexported fields
}
MemberService wraps memberlist membership tracking for Concord peer discovery.
func Start ¶
func Start( logger *zap.Logger, node Node, join []netip.AddrPort, advertise netip.Addr, identity NoiseIdentity, ) (*MemberService, error)
Start creates a memberlist-backed peer discovery service for node.
The node ID is used as memberlist's node name so discovered members can be mapped back to stable Concord identities. The node address is the local bind endpoint for memberlist traffic. Port 0 asks the OS for an ephemeral port; use LocalAddr after Start to learn the bound endpoint.
advertise is an optional IP hint from config overriding which IP to publish (see ResolveAdvertise). A zero Addr means auto-detect.
If join is non-empty, Start attempts to join those bootstrap addresses. A failed join does not abort startup: the node keeps running as a solo member (membership = this node only). Discovery may have returned a non-Concord host; soft-fail avoids taking the whole process down. Callers can retry Join later.
identity is this node's Noise identity for gossip. An empty identity (nil Pub) advertises no Noise key; peers then cannot open Noise sessions to this node until it restarts with an identity.
func (*MemberService) Join ¶
func (m *MemberService) Join( existingMembers []netip.AddrPort, ) (int, error)
Join asks the running memberlist service to join existing peer addresses.
The addresses are bootstrap endpoints, not durable peer identities. After a successful join, memberlist exchanges membership state and Members can return the reachable nodes known to the local process.
func (*MemberService) LocalAddr ¶
func (m *MemberService) LocalAddr() (netip.AddrPort, error)
LocalAddr returns the address memberlist is advertising for this node.
func (*MemberService) Members ¶
func (m *MemberService) Members() ([]Node, error)
Members returns the current memberlist view as Concord peer discovery nodes.
Memberlist stores each member's identity in Node.Name. Concord writes UUIDs into that field when starting memberlist, so this method parses the name back into a uuid.UUID and pairs it with the member's advertised address.
func (*MemberService) Publish ¶
func (m *MemberService) Publish() error
Publish pushes current metadata to the mesh when anything volatile changed since the last push. Static identity never differs, so it is not compared; see equalVolatile for the compared set. Unchanged values skip the broadcast entirely. Callers are the fast beat (after sampling) and the discovery beat (after config refresh), hence the mutex: Set* stay lock-free atomics for the gossip hot path while Publish serializes the read-compare-broadcast sequence.
func (*MemberService) SetAnchor ¶
func (m *MemberService) SetAnchor(anchored bool)
SetAnchor marks this node as a rendezvous anchor in gossip metadata.
func (*MemberService) SetPosition ¶
func (m *MemberService) SetPosition(lat, lon float64)
SetPosition updates the geographic position reported in node gossip metadata. Out-of-planet coordinates are ignored, keeping the previous position: callers retry with a real fix next beat. This moves gossip only; history needs Sampler.RecordPosition too. The IPC position setter applies both together.
func (*MemberService) SetPressure ¶
func (m *MemberService) SetPressure(cpu, mem, disk uint8)
SetPressure updates the utilization trio reported in node gossip metadata. Values are 0-100 percents sampled on the fast beat.
func (*MemberService) SetWorkloadCount ¶
func (m *MemberService) SetWorkloadCount(n int)
SetWorkloadCount updates the count of active local workloads reported in node gossip metadata.
func (*MemberService) Shutdown ¶
func (m *MemberService) Shutdown() error
Shutdown stops the memberlist service and releases its network resources.
type MemberlistLogWriter ¶
type MemberlistLogWriter struct {
// contains filtered or unexported fields
}
Adapter for the message levels coming from the memberlist library
type Node ¶
Node identifies a Concord node as it appears in peer discovery.
ID is the stable Concord node identity. Address is the current network endpoint used by memberlist for peer membership traffic. The address can change over time; the ID is the durable identity. State is memberlist's current liveness observation for the node.
type NodeMetadata ¶
type NodeMetadata struct {
WireGuardPublicKey string `json:"wireguard_public_key"`
CPUMHz float64 `json:"cpu_mhz"`
MemoryMB uint64 `json:"memory_mb"`
Workloads int `json:"workload_count"`
// CPUPercent, MemPercent, and DiskPercent are 0-100 utilization sampled
// on the fast beat. Small by design: gossip caps metadata at 512 bytes.
CPUPercent uint8 `json:"cpu_percent"`
MemPercent uint8 `json:"mem_percent"`
DiskPercent uint8 `json:"disk_percent"`
// Lat and Lon are this node's geographic position in decimal degrees.
// Operator-provisioned and stationary in practice; members without a
// known position gossip zeros, which never order anything.
Lat float64 `json:"lat"`
Lon float64 `json:"lon"`
// Anchor marks a rendezvous anchor: a stable reachable member newcomers
// may join. Provisioned with concord --anchor.
Anchor bool `json:"anchor"`
// NoisePublicKey is this node's Noise static public key (32 raw bytes,
// base64 in JSON). Dialers use it as the IK handshake's pre-known peer
// key, so no dial path needs a key the gossip layer did not provide.
// The CA signature over the parcel travels inside the handshake, not
// here: at 256 bytes it would blow memberlist's 512-byte metadata limit.
NoisePublicKey []byte `json:"noise_public_key,omitempty"`
// NoiseGeneration is the rotation counter of NoisePublicKey. Highest
// generation seen for a node wins.
NoiseGeneration uint64 `json:"noise_generation,omitempty"`
}
NodeMetadata carries dynamic metrics and networking capabilities gossiped across the cluster.
type NodeState ¶
type NodeState string
NodeState describes memberlist's current liveness observation for a node.
type NoiseIdentity ¶
NoiseIdentity is this node's Noise identity for gossip: the static public key, its rotation generation, and the CA signature binding all three to the node ID. The private half never leaves disk; see transport.EnsureStaticKey.
type Resolver ¶
Resolver discovers candidate peer addresses for bootstrapping memberlist membership. Different implementations cover different discovery mechanisms such as LAN broadcast or a rendezvous anchor.
Resolve must be safe for concurrent calls from multiple goroutines.
type ResolverFunc ¶
ResolverFunc is an adapter that turns a plain function into a Resolver.