istio/istio
istiod (pilot-discovery)
Active contributors: howardjohn, costinm, hzxuzhonghu, keithmattix, stevenctl
Purpose
Istiod is Istio's control plane: a single Go binary that watches Kubernetes resources, builds an in-memory model of the mesh, signs short-lived workload certificates, runs admission webhooks, and serves Envoy/ztunnel configuration over xDS. It bundles what used to be Pilot, Citadel, and Galley into a modular monolith — see Lore for the consolidation history.
The binary is built from pilot/cmd/pilot-discovery/main.go (~30 lines of cobra plumbing) and starts a long-running gRPC + HTTP server defined in pilot/pkg/bootstrap/server.go. The Helm template that deploys it is manifests/charts/istio-control/istio-discovery/templates/deployment.yaml.
Directory layout
pilot/
├── cmd/pilot-discovery/ # binary entry point + CLI flags
│ ├── main.go
│ └── app/
│ ├── cmd.go # cobra command, flags
│ ├── options.go # arg validation
│ └── request.go # `pilot-discovery request` subcommand for ad-hoc xDS
├── pkg/
│ ├── bootstrap/ # the wiring of the server (1400+ line server.go)
│ ├── model/ # Proxy, Service, PushContext, sidecar scope
│ ├── networking/core/ # Translation: listeners, clusters, routes, gateways
│ ├── xds/ # The xDS gRPC server, generators, push queue, debug
│ ├── config/ # ConfigStore (CRD, file, xDS) and analyzers
│ ├── serviceregistry/ # Kubernetes + ServiceEntry + memory + ambient
│ ├── controllers/ # IP allocation, untaint
│ ├── credentials/ # SDS credential providers
│ ├── status/ # CRD status reporting
│ ├── trustbundle/ # Aggregated cluster CA bundle
│ ├── leaderelection/ # Leader election helpers
│ ├── server/ # Generic server lifecycle helpers
│ └── features/ # Env-var gated runtime knobs
└── docker/Key abstractions
| Symbol | File | Description |
|---|---|---|
bootstrap.Server |
pilot/pkg/bootstrap/server.go |
Holds every subsystem; constructor wires dependencies. |
bootstrap.PilotArgs |
pilot/pkg/bootstrap/options.go |
All CLI flags + env-derived options. |
model.PushContext |
pilot/pkg/model/push_context.go |
Immutable snapshot of mesh state per push. |
model.Proxy |
pilot/pkg/model/context.go |
xDS client representation: identity, labels, sidecar scope, computed metadata. |
model.IstioConfigStore |
pkg/config/store.go |
Aggregate config interface (Get, List, Create, Update, …). |
serviceregistry.Instance |
pilot/pkg/serviceregistry/instance.go |
Common interface every registry implements. |
xds.DiscoveryServer |
pilot/pkg/xds/discovery.go |
The xDS server: push queue, generators, ADS dispatcher. |
core.ConfigGeneratorImpl |
pilot/pkg/networking/core/configgen.go |
Builds Envoy listeners/clusters/routes for a Proxy from a PushContext. |
inject.Webhook |
pkg/kube/inject/webhook.go |
Mutating admission webhook that injects istio-proxy. |
validation.Webhook |
pkg/webhooks/validation/server/server.go |
Validating admission webhook for Istio CRs. |
ca.IstioCA |
security/pkg/pki/ca/ca.go |
The CA: signs CSRs, manages root cert lifecycle. |
How it works
sequenceDiagram
participant K8s as Kubernetes API
participant Reg as ServiceRegistry<br/>(serviceregistry/*)
participant CS as ConfigStore<br/>(config/kube/crdclient)
participant Push as PushContext<br/>(model)
participant Q as PushQueue<br/>(xds)
participant Gen as Generators<br/>(networking/core, xds/*.go)
participant Cache as XDS cache
participant Stream as ADS stream
K8s->>Reg: Service / Endpoint / Pod events
K8s->>CS: VirtualService / DestinationRule / Gateway / ...
Reg->>Push: incremental updates
CS->>Push: incremental updates
Push->>Q: configsUpdated, full=false
Q->>Gen: pop (Proxy, PushRequest)
Gen->>Cache: lookup encoded.Any
Cache-->>Gen: hit (or compute + store)
Gen->>Stream: Resources (CDS / EDS / LDS / RDS / SDS)The bootstrap initializer in pilot/pkg/bootstrap/server.go runs in this rough order:
- Mesh config and networks — load from file watcher (mounted ConfigMap) or defaults.
- Kube clients — primary
kubelib.Client,multicluster.Controllerfor secondary clusters. - CA / Citadel — build the root cert chain, start the CA server. Code in
security/pkg/pki/. - ConfigStore — wire CRD, file, and xDS clients into an aggregate store.
pilot/pkg/config/aggregate/. - Service registry — Kubernetes controller, ServiceEntry controller, ambient registry, MCS controller.
- Trust bundle — collect CA roots from the cluster (cert-manager, Spire, additional roots).
- xDS server —
pilot/pkg/xds/discovery.go. Register every generator type. - Sidecar injector —
pkg/kube/inject/. Build the template renderer, register the webhook handler. - Validation webhook —
pkg/webhooks/validation/. Validate Istio CRs. - Status reporter —
pilot/pkg/status/. Publish per-resource sync state. - Leader election —
pilot/pkg/leaderelection/. Claim leases for the writer-only roles (status, namespace controller, autoregistration). - HTTP / HTTPS / gRPC servers start on their respective ports.
The push pipeline is the heart of istiod's hot path. A single Server instance handles many proxies; per-proxy work is queued in pilot/pkg/xds/pushqueue.go so a slow client cannot block the rest of the mesh. proxy_dependencies.go filters out proxies that the change cannot affect.
xDS surfaces served
| Surface | Type URL prefix | Generator |
|---|---|---|
| CDS | type.googleapis.com/envoy.config.cluster.v3.Cluster |
cds.go, networking/core/cluster*.go |
| EDS | ...endpoint.v3.ClusterLoadAssignment |
eds.go, endpoints/ |
| LDS | ...listener.v3.Listener |
lds.go, networking/core/listener*.go |
| RDS | ...route.v3.RouteConfiguration |
rds.go, networking/core/route/ |
| SDS | ...auth.v3.Secret |
sds.go (also served by the per-pod agent) |
| ECDS | ...core.v3.TypedExtensionConfig |
ecds.go |
| NDS | Istio name table for DNS | nds.go, pkg/dns/ |
| wDS (workload) | istio.io/...workloadapi/Workload |
workload.go, pkg/workloadapi/ (ztunnel) |
| Debug | istio.io/debug/... |
debuggen.go |
Note that ztunnel, while still using the xDS framing, gets the Istio-specific workload API instead of Envoy CDS/EDS.
Ports
Default ports configured in pilot/cmd/pilot-discovery/app/cmd.go:
| Port | Purpose |
|---|---|
:8080 |
Debug HTTP (configz, syncz, edsz, …). Disabled in production by --httpAddr="". |
:15010 |
Plain-text gRPC ADS (legacy / in-cluster only) |
:15012 |
mTLS gRPC ADS (the production endpoint) |
:15014 |
Prometheus metrics + /healthz |
:15017 |
Mutating + validating webhook HTTPS |
ControlZ is bound separately (default :9876).
Integration points
- Reads: Kubernetes API (Services, Endpoints/EndpointSlices, Pods, Nodes, Namespaces), Istio CRs (VS, DR, Gateway, SE, WE, Sidecar, EnvoyFilter, PeerAuth, RequestAuth, AuthZ, Telemetry, WasmPlugin, ProxyConfig), Kubernetes Gateway API (Gateway, HTTPRoute, …), MCS (
ServiceImport,ServiceExport),IstioOperatorfor runtime info. - Writes: status conditions on Istio and Kubernetes Gateway resources (
pilot/pkg/status/), pod labelservice.istio.io/canonical-revisionvia the namespace-untaint controller. - Outbound: gRPC ADS to every connected sidecar / gateway / ztunnel / waypoint; gRPC CSR endpoint for the agent CA client.
- Webhooks:
mutating-ns named after the revision, plusvalidatingwebhook for Istio CRs. - Multi-cluster: secrets in
istio-systemwith theistio/multiCluster=truelabel triggerpkg/kube/multicluster/to spawn a per-secondary-cluster set of controllers — those forward services and endpoints into the primary's registry.
Entry points for modification
- To add a new xDS surface, register a
Generatorinpilot/pkg/xds/<name>.goand wire it into theXdsServerconstructor inbootstrap/server.go. Don't forget to add a debug endpoint. - To support a new config kind, add a schema entry to
pkg/config/schema/, runmake gen, and extend the relevant generator. The CRD client picks up new kinds automatically once they're in the schema. - To change generator output for an existing kind, the right place is almost always
pilot/pkg/networking/core/. Watch for cache key correctness — the cache is the single biggest source of Pilot CVEs, and-tags=assertwill catch most key-mismatch bugs in unit tests. - Bootstrap-time initialization order matters. If your subsystem needs the Kubernetes client and the mesh config, register it after both are constructed in
server.go.
Key source files
| File | Purpose |
|---|---|
pilot/cmd/pilot-discovery/main.go |
Cobra entry point |
pilot/cmd/pilot-discovery/app/cmd.go |
All CLI flags and the discovery subcommand |
pilot/pkg/bootstrap/server.go |
Server struct and the wire-everything-up constructor |
pilot/pkg/bootstrap/configcontroller.go |
ConfigStore wiring |
pilot/pkg/bootstrap/servicecontroller.go |
Service registry wiring |
pilot/pkg/bootstrap/istio_ca.go |
CA setup |
pilot/pkg/xds/discovery.go |
XdsServer struct |
pilot/pkg/xds/ads.go |
ADS stream dispatcher (state ofworld, delta variant in delta.go) |
pilot/pkg/xds/debug.go |
Debug HTTP endpoints (~1200 lines) |
pilot/pkg/model/push_context.go |
Snapshot of mesh state |
pilot/pkg/model/context.go |
Proxy and supporting types |
pilot/pkg/networking/core/configgen.go |
Top of the translation pipeline |
pilot/pkg/features/pilot.go |
Env-var-gated feature flags |
See also
- systems/xds — deeper dive into the xDS server architecture.
- systems/service-discovery — how istiod ingests services and endpoints.
- systems/networking-core — the translation pipeline.
- systems/security-ca — how Citadel signs certs.
- systems/sidecar-injection — the mutating webhook.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.