Pilot高层架构
Pilot在Istio的控制面板中负责流量管理
Istio流量管理相关组件
图中红色的线表示控制流,黑色的线表示数据流。蓝色部分为和Pilot相关的组件。
控制面板组件
- Discovery Services
对应的docker为istio-release/pilot,进程为pilot-discovery,该组件的功能包括:
- 从Service provider(如kubernetes)中获取服务信息
- 从K8S API Server中获取流量规则(K8S CRD Resource)
- 将服务信息和流量规则转化为数据面可以理解的格式,通过标准的数据面API下发到网格中的各个sidecar中。
- K8S API Server
提供Pilot相关的CRD Resource的增、删、改、查。和Pilot相关的CRD有以下几种:
- Virtualservice:用于定义路由规则,如根据来源或 Header 制定规则,或在不同服务版本之间分拆流量。
- DestinationRule:定义目的服务的配置策略以及可路由子集。策略包括断路器、负载均衡以及 TLS 等。
- ServiceEntry:用 ServiceEntry 可以向Istio中加入附加的服务条目,以使网格内可以向istio 服务网格之外的服务发出请求。
- Gateway:为网格配置网关,以允许一个服务可以被网格外部访问。
- EnvoyFilter:可以为Envoy配置过滤器。由于Envoy已经支持Lua过滤器,因此可以通过EnvoyFilter启用Lua过滤器,动态改变Envoy的过滤链行为。
数据面板组件
在数据面有两个进程Pilot-agent和envoy,这两个进程被放在一个docker容器gcr.io/istio-release/proxyv2中。
- Pilot-agent
该进程根据K8S API Server中的配置信息生成Envoy的配置文件,并负责启动Envoy进程。注意Envoy的大部分配置信息都是通过xDS接口从Pilot中动态获取的,因此Agent生成的只是用于初始化Envoy的少量静态配置。在后面的章节中,本文将对Agent生成的Envoy配置文件进行进一步分析。 - Envoy
Envoy由Pilot-agent进程启动,启动后,Envoy读取Pilot-agent为它生成的配置文件,然后根据该文件的配置获取到Pilot的地址,通过数据面标准API的xDS接口从pilot拉取动态配置信息,包括路由(route),监听器(listener),服务集群(cluster)和服务端点(endpoint)。Envoy初始化完成后,就根据这些配置信息对微服务间的通信进行寻址和路由。
XDS服务接口
为了避免Envoy配置数据更新过程中出现流量丢失的情况,xDS接口应采用下面的顺序:
- CDS (Cluster Discovery Service) 首先更新Cluster数据(如果有变化)
- EDS (Endpoint Discovery Service) 更新相应Cluster的Endpoint信息(如果有变化)
- LDS (Listener Discovery Service) 更新CDS/EDS相应的Listener。
- RDS (Route Discovery Service) 最后更新新增Listener相关的Route配置。
- 删除不再使用的CDS cluster和 EDS endpoints。
Envoy
- Envoy调试方法
Envoy提供了管理接口,缺省为localhost的15000端口,可以获取listener,cluster以及完整的配置数据导出功能。
kubectl exec productpage-v1-67c8d9bc58-zq7m2 -c istio-proxy curl http://127.0.0.1:15000/help
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 823 0 823 0 0 3112 0 --:--:-- --:--:-- --:--:-- 5715
admin commands are:
/: Admin home page
/certs: print certs on machine
/clusters: upstream cluster status
/config_dump: dump current Envoy configs (experimental)
/cpuprofiler: enable/disable the CPU profiler
/healthcheck/fail: cause the server to fail health checks
/healthcheck/ok: cause the server to pass health checks
/help: print out list of admin commands
/hot_restart_version: print the hot restart compatibility version
/listeners: print listener addresses
/logging: query/change logging levels
/quitquitquit: exit the server
/reset_counters: reset all counters to zero
/runtime: print runtime values
/runtime_modify: modify runtime values
/server_info: print server version/status information
/stats: print server stats
/stats/prometheus: print server stats in prometheus format
- 查看Envoy监听端口
进入productpage pod中的Envoy(istio-proxy) container,查看监听端口
- 9080: productpage进程对外提供的服务端口
- 15001: Envoy的入口监听器,iptable会将pod的流量导入该端口中由Envoy进行处理
- 15000: Envoy管理端口,该端口绑定在本地环回地址上,只能在Pod内访问。
[root@k8-master-1 ~]# kubectl exec productpage-v1-67c8d9bc58-zq7m2 -c istio-proxy -- netstat -ln
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.1:15000 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:9080 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:15001 0.0.0.0:* LISTEN
Active UNIX domain sockets (only servers)
Proto RefCnt Flags Type State I-Node Path
Envoy启动过程
Istio通过K8s的Admission webhook机制实现了sidecar的自动注入,Mesh中的每个微服务会被加入Envoy相关的容器。以Porductpage为例,容器中除了productpage之外,istio还为该Pod注入了gcr.io/istio-release/proxy_init和gcr.io/istio-release/proxyv2。
[root@k8-master-1 ~]# kubectl describe pods productpage-v1-67c8d9bc58-zq7m2 | grep Image:
Image: gcr.io/istio-release/proxy_init:1.0.0
Image: istio/examples-bookinfo-productpage-v1:1.8.0
Image: gcr.io/istio-release/proxyv2:1.0.0
- proxy_init
Productpage的Pod中有一个InitContainer proxy_init,InitContrainer是K8S提供的机制,用于在Pod中执行一些初始化任务.在Initialcontainer执行完毕并退出后,才会启动Pod中的其它container。
#查看容器内容,一下截取主要部分
docker inspect gcr.io/istio-release/proxy_init:1.0.0
Proxy_init中执行的命令是istio-iptables.sh,该脚本的作用是通过配置iptable来劫持Pod中的流量。
该容器的命令行参数-p 15001,可以得知Pod中的数据流量被iptable拦截,并发向Envoy的15001端口。 -u 1337参数用于排除用户ID为1337,即Envoy自身的流量,以避免Iptable把Envoy发出的数据又重定向到Envoy,形成死循环。
Proxyv2
查看容器中的Pilot-agent和envoy两个进程信息
[root@k8-master-1 ~]# kubectl exec productpage-v1-67c8d9bc58-zq7m2 -c istio-proxy -- ps -ef
UID PID PPID C STIME TTY TIME CMD
istio-p+ 1 0 0 01:24 ? 00:00:00 /usr/local/bin/pilot-agent proxy sidecar --configPath /etc/istio/proxy --binaryPath /usr/local/bin/envoy --serviceCluster productpage --drainDuration 45s --parentShutdownDuration 1m0s --discoveryAddress istio-pilot.istio-system:15005 --discoveryRefreshDelay 1s --zipkinAddress zipkin.istio-system:9411 --connectTimeout 10s --statsdUdpAddress istio-statsd-prom-bridge.istio-system:9125 --proxyAdminPort 15000 --controlPlaneAuthPolicy MUTUAL_TLS
istio-p+ 12 1 0 01:24 ? 00:02:20 /usr/local/bin/envoy -c /etc/istio/proxy/envoy-rev0.json --restart-epoch 0 --drain-time-s 45 --parent-shutdown-time-s 60 --service-cluster productpage --service-node sidecar~10.244.1.120~productpage-v1-67c8d9bc58-zq7m2.default~default.svc.cluster.local --max-obj-name-len 189 -l warn --v2-config-only
Pilot-agent进程根据启动参数和K8S API Server中的配置信息生成Envoy的初始配置文件,并负责启动Envoy进程。从ps命令输出可以看到Pilot-agent在启动Envoy进程时传入了pilot地址和zipkin地址,并为Envoy生成了一个初始化配置文件envoy-rev0.json
- 导出json文件
kubectl exec productpage-v1-67c8d9bc58-zq7m2 -c istio-proxy -- cat /etc/istio/proxy/envoy-rev0.json > envoy-ev0.json
- 配置文件结构图
- node
包含了Envoy所在节点相关信息
"node": {
"id": "sidecar~10.244.1.120~productpage-v1-67c8d9bc58-zq7m2.default~default.svc.cluster.local",
"cluster": "productpage",
"metadata": {
"INTERCEPTION_MODE": "REDIRECT",
"ISTIO_PROXY_SHA": "istio-proxy:6166ae7ebac7f630206b2fe4e6767516bf198313",
"ISTIO_PROXY_VERSION": "1.0.0",
"ISTIO_VERSION": "1.0.0",
"POD_NAME": "productpage-v1-67c8d9bc58-zq7m2",
"istio": "sidecar"
}
}
- admin
配置Envoy的日志路径及管理端口
"admin": {
"access_log_path": "/dev/stdout",
"address": {
"socket_address": {
"address": "127.0.0.1",
"port_value": 15000
}
}
}
- dynamic_resources
配置动态资源,这里配置的为ads服务器
"dynamic_resources": {
"lds_config": {
"ads": {}
},
"cds_config": {
"ads": {}
},
"ads_config": {
"api_type": "GRPC",
"refresh_delay": {"seconds": 1, "nanos": 0},
"grpc_services": [
{
"envoy_grpc": {
"cluster_name": "xds-grpc"
}
}
]
}
}
- static_resources
配置静态资源,包括了xds-grpc和zipkin两个cluster。其中xds-grpc cluster对应前面dynamic_resources中ADS配置,指明了Envoy用于获取动态资源的服务器地址。
"static_resources": {
"clusters": [
{
"name": "xds-grpc",
"type": "STRICT_DNS",
"connect_timeout": {"seconds": 10, "nanos": 0},
"lb_policy": "ROUND_ROBIN",
"tls_context": {
"common_tls_context": {
"alpn_protocols": "h2",
"tls_certificates": {
"certificate_chain": {
"filename": "/etc/certs/cert-chain.pem"
},
"private_key": {
"filename": "/etc/certs/key.pem"
}
},
"validation_context": {
"trusted_ca": {
"filename": "/etc/certs/root-cert.pem"
},
"verify_subject_alt_name": [
"spiffe://cluster.local/ns/istio-system/sa/istio-pilot-service-account"
]
}
}
}
- tracing
配置分布式链路跟踪
"tracing": {
"http": {
"name": "envoy.zipkin",
"config": {
"collector_cluster": "zipkin"
}
}
}
- stats_sinks
这里配置的是和Envoy直连的metrics收集sink,和Mixer telemetry没有关系。Envoy自带stats格式的metrics上报。
"stats_sinks": [
{
"name": "envoy.statsd",
"config": {
"address": {
"socket_address": {"address": "10.100.26.51", "port_value": 9125}
}
}
}
]
Envoy配置分析
- Envoy配置初始化流程
- Pilot-agent根据启动参数和K8S API Server中的配置信息生成Envoy的初始配置文件envoy-rev0.json,该文件告诉Envoy从xDS server中获取动态配置信息,并配置了xDS server的地址信息,即控制面的Pilot。
- Pilot-agent使用envoy-rev0.json启动Envoy进程。
- Envoy根据初始配置获得Pilot地址,采用xDS接口从Pilot获取到Listener,Cluster,Route等d动态配置信息。
- Envoy根据获取到的动态配置启动Listener,并根据Listener的配置,结合Route和Cluster对拦截到的流量进行处理。