# /usr/local/bin/pilot-agent --help Istio Pilot agent runs in the side car or gateway container and bootstraps envoy.
Usage: pilot-agent [command]
Available Commands: help Help about any command proxy Envoy proxy agent request Makes an HTTP request to the Envoy admin API version Prints out build version information
Flags: -h, --helphelpfor pilot-agent --log_as_json Whether to format output as JSON or in plain console-friendly format --log_caller string Comma-separated list of scopes forwhich to include caller information, scopes can be any of [default, model] --log_output_level string Comma-separated minimum per-scope logging level of messages to output, in the form of <scope>:<level>,<scope>:<level>,... where scope can be one of [default, model] and level can be one of [debug, info, warn, error, none] (default "default:info") --log_rotate string The path for the optional rotating log file --log_rotate_max_age int The maximum age in days of a log file beyond which the file is rotated (0 indicates no limit) (default 30) --log_rotate_max_backups int The maximum number of log file backups to keep before older files are deleted (0 indicates no limit) (default 1000) --log_rotate_max_size int The maximum size in megabytes of a log file beyond which the file is rotated (default 104857600) --log_stacktrace_level string Comma-separated minimum per-scope logging level at which stack traces are captured, in the form of <scope>:<level>,<scope:level>,... where scope can be one of [default, model] and level can be one of [debug, info, warn, error, none] (default "default:none") --log_target stringArray The set of paths where to output the log. This can be any path as well as the special values stdout and stderr (default [stdout])
Use "pilot-agent [command] --help"for more information about a command.
Flags: --applicationPorts stringSlice Ports exposed by the application. Used to determine that Envoy is configured and ready to receive traffic. --availabilityZone string Availability zone --binaryPath string Path to the proxy binary (default "/usr/local/bin/envoy") --bootstrapv2 Use bootstrap v2 - DEPRECATED (default true) --concurrency int number of worker threads to run --configPath string Path to the generated configuration file directory (default "/etc/istio/proxy") --connectTimeout duration Connection timeout used by Envoy for supporting services (default 1s) --controlPlaneAuthPolicy string Control Plane Authentication Policy (default "NONE") --customConfigFile string Path to the custom configuration file --disableInternalTelemetry Disable internal telemetry --discoveryAddress string Address of the discovery service exposing xDS (e.g. istio-pilot:8080) (default "istio-pilot:15007") --discoveryRefreshDelay duration Polling interval for service discovery (used by EDS, CDS, LDS, but not RDS) (default 1s) --domain string DNS domain suffix. If not provided uses ${POD_NAMESPACE}.svc.cluster.local --drainDuration duration The time in seconds that Envoy will drain connections during a hot restart (default 2s) -h, --helphelpfor proxy --id string Proxy unique ID. If not provided uses ${POD_NAME}.${POD_NAMESPACE} from environment variables --ip string Proxy IP address. If not provided uses ${INSTANCE_IP} environment variable. --parentShutdownDuration duration The time in seconds that Envoy will wait before shutting down the parent process during a hot restart (default 3s) --proxyAdminPort uint16 Port on which Envoy should listen for administrative commands (default 15000) --proxyLogLevel string The log level used to start the Envoy proxy (choose from {trace, debug, info, warn, err, critical, off}) (default "warn") --serviceCluster string Service cluster (default "istio-proxy") --serviceregistry string Select the platform for service registry, options are {Kubernetes, Consul, CloudFoundry, Mock, Config} (default "Kubernetes") --statsdUdpAddress string IP Address and Port of a statsd UDP listener (e.g. 10.75.241.127:9125) --statusPort uint16 HTTP Port on which to serve pilot agent status. If zero, agent status will not be provided. --templateFile string Go template bootstrap config --zipkinAddress string Address of the Zipkin service (e.g. zipkin:9411)
type Agent interface { // ConfigCh returns the config channel used to send configuration updates. // Agent compares the current active configuration to the desired state and // initiates a restart if necessary. If the restart fails, the agent attempts // to retry with an exponential back-off. ConfigCh() chan<- interface{}
// Run starts the agent control loop and awaits for a signal on the input // channel to exit the loop. Run(ctx context.Context) }
// Proxy defines command interface for a proxy type Proxy interface { // Run command for a config, epoch, and abort channel Run(interface{}, int, <-chan error) error
// Cleanup command for an epoch Cleanup(int)
// Panic command is invoked with the desired config when all retries to // start the proxy fail just before the agent terminating Panic(interface{}) }
// Throttle processing up to smoothed 1 qps with bursts up to 10 qps. // High QPS is needed to process messages on all channels. rateLimiter := rate.NewLimiter(1, 10)
var reconcileTimer *time.Timer for { err := rateLimiter.Wait(ctx) if err != nil { a.terminate() return }
// maximum duration or duration till next restart var delay time.Duration = 1<<63 - 1 if a.retry.restart != nil { // 如果设置了下次重启的时间间隔,则 delay 设置为该值 delay = time.Until(*a.retry.restart) } // 停止原有的 reconcileTimer, 并设置成当前的 delay 值 if reconcileTimer != nil { reconcileTimer.Stop() } reconcileTimer = time.NewTimer(delay)
select { // 1. 如果相关的配置发生了变化,如果没有变化则忽略 case config := <-a.configCh: if !reflect.DeepEqual(a.desiredConfig, config) { log.Infof("Received new config, resetting budget") a.desiredConfig = config
// reset retry budget if and only if the desired config changes // 因为配置发生了变化,把下一次重启时间间隔设置为最大 a.retry.budget = a.retry.MaxRetries a.reconcile() } // 默认的重试策略值为 /* DefaultRetry = Retry{ MaxRetries: 10, InitialInterval: 200 * time.Millisecond, }*/ // 2. 如果 proxy-envoy 的状态发生了变化 case status := <-a.statusCh: // delete epoch record and update current config // avoid self-aborting on non-abort error delete(a.epochs, status.epoch) delete(a.abortCh, status.epoch) a.currentConfig = a.epochs[a.latestEpoch()]
// NOTE: due to Envoy hot restart race conditions, an error from the // process requires aggressive non-graceful restarts by killing all // existing proxy instances // Envoy热重启竞争条件,进程中的错误需要通过终止所有现有代理实例来进行积极的非正常重启 a.abortAll() } else { // 正常情况下的退出 log.Infof("Epoch %d exited normally", status.epoch) }
// cleanup for the epoch // 删除当前 epoch 对应的配置文件 a.proxy.Cleanup(status.epoch)
// check that the config is current if reflect.DeepEqual(a.desiredConfig, a.currentConfig) { log.Infof("Desired configuration is already applied") return }
// discover and increment the latest running epoch epoch := a.latestEpoch() + 1 // buffer aborts to prevent blocking on failing proxy abortCh := make(chan error, maxAborts) a.epochs[epoch] = a.desiredConfig a.abortCh[epoch] = abortCh a.currentConfig = a.desiredConfig // 最终的调用,会将相关相关结果放到 abortCh channel 中 go a.runWait(a.desiredConfig, epoch, abortCh) }
reconcile 设置相关参数后,最终启动一个新的 goroutine 来进行启动最终的程序
1 2 3 4 5 6
// runWait runs the start-up command as a go routine and waits for it to finish func(a *agent)runWait(config interface{}, epoch int, abortCh <-chan error) { log.Infof("Epoch %d starting", epoch) err := a.proxy.Run(config, epoch, abortCh) a.statusCh <- exitStatus{epoch: epoch, err: err} }
func(e *envoy)Run(config interface{}, epoch int, abort <-chan error)error { var fname string // Note: the cert checking still works, the generated file is updated if certs are changed. // We just don't save the generated file, but use a custom one instead. Pilot will keep // monitoring the certs and restart if the content of the certs changes. // 1. 如果指定了模板文件,则使用用户指定的,否则则使用默认的 iflen(e.config.CustomConfigFile) > 0 { // there is a custom configuration. Don't write our own config - but keep watching the certs. fname = e.config.CustomConfigFile } else { out, err := bootstrap.WriteBootstrap(&e.config, e.node, epoch, e.pilotSAN, e.opts, os.Environ(), e.nodeIPs) if err != nil { log.Errora("Failed to generate bootstrap config", err) os.Exit(1) // Prevent infinite loop attempting to write the file, let k8s/systemd report return err } fname = out }
// spin up a new Envoy process args := e.args(fname, epoch) log.Infof("Envoy command: %v", args)
// Set if the caller is monitoring envoy, for example in tests or if envoy runs in same // container with the app. if e.errChan != nil { // Caller passed a channel, will wait itself for termination gofunc() { e.errChan <- cmd.Wait() }() returnnil }
func(w *watcher)Run(ctx context.Context) { // kick start the proxy with partial state (in case there are no notifications coming) w.SendConfig() // 用于向 agent 发送相关的摘要值
// monitor certificates certDirs := make([]string, 0, len(w.certs)) for _, cert := range w.certs { certDirs = append(certDirs, cert.Directory) }
go watchCerts(ctx, certDirs, watchFileEvents, defaultMinDelay, w.SendConfig)
// watchCerts watches all certificate directories and calls the provided // `updateFunc` method when changes are detected. This method is blocking // so it should be run as a goroutine. // updateFunc will not be called more than one time per minDelay. funcwatchCerts(ctx context.Context, certsDirs []string, watchFileEventsFn watchFileEventsFn, minDelay time.Duration, updateFunc func()) { fw, err := fsnotify.NewWatcher() if err != nil { log.Warnf("failed to create a watcher for certificate files: %v", err) return } deferfunc() { if err := fw.Close(); err != nil { log.Warnf("closing watcher encounters an error %v", err) } }()
// watch all directories for _, d := range certsDirs { if err := fw.Watch(d); err != nil { log.Warnf("watching %s encounters an error %v", d, err) return } } watchFileEventsFn(ctx, fw.Event, minDelay, updateFunc) }
关于监听的相关证书,则来自于注入时从命名空间中 secret 中加载到 pod 中的文件,deployment文件如下: