本文翻译 Istio Pilot sidecar 代理流量重定向方法,原文链接为 proxy-redirection-configuration。
查看 Microservice Proxies in Kubernetes 了解对服务网格代理部署(service-mesh proxy deployments)的详细比较和初始设计与实现方案。 本文介绍当前的对于重定向每个pod的sidecar proxy的进站和出站流量的方法和备选方案。
如果Envoy受到非提升特权的攻击,攻击影响将是最小化的。如果我们增加任何特权给Envoy 容器,则会引起很大的震动。随着特权升级,增加到Envoy的特性受到很多审查(举例: URL中的正则表达式)。高级特权会被限制成一次性的初始化(通过 init-container)中,并保持在proxy container之外。
下面假设所有的进站和出站流量被重定向(通过iptables)到一个独立的port。Envoy进程绑定到这个port并用SO_ORIGINAL_DST 去覆盖原始的目的地和传递给匹配的过滤器。(查看 config-listeners)。
ISTIO_PROXY_PORT=5001
Envoy代理集成的UID,用来做基于UID的iptables重定向
ISTIO_PROXY_UID=1337
基于mark的iptables重定向的数据包标记
ISTIO_SO_MARK=0x1
ISTIO_NET_CLS_ID=0x100001
入栈重定向的iptables规则很简单,直接假设所有的流量需要重定向到代理。如果进站流量需要bypass代理,那么需要增加额外的规则,例子:
iptables -t nat -A PREROUTING -p tcp -j REDIRECT --to-port ${ISTIO_PROXY_PORT}
UID方法是当前的计划主要是因为proxy container中不需要提权。该方法的缺点是需要UID协作,但是短期计划里面这不是一个问题,在长期的计划里面,可以探索缓解措施,例如,将可覆盖的UID暴露给最终用户。 UID(–uid-owner)
iptables -t nat -A OUTPUT -p tcp -j REDIRECT ! -s 127.0.0.1/32 \
--to-port ${ISTIO_PROXY_PORT} -m owner '!' --uid-owner ${ISTIO_PROXY_UID}
(查看 http://man7.org/linux/man-pages/man7/socket.7.html)
iptables -t nat -A OUTPUT -p tcp -j REDIRECT ! -s 127.0.0.1/32 \
--to-port ${ISTIO_PROXY_PORT} -m mark '!' --mark ${ISTIO_SO_MARK}
${ISTIO_SO_MARK}
的值被配置在pod spec(例如configmap、envvar),被init-container 用来编程iptables,proxy agent 用每一个上游集群的合适的SO_MARK 值创建envoy config。SO_MARK
以支持envoy,可能配置在每个上游集群?NET_CAP_ADMIN
去设置sockets的SO_MARK.(查看 https://www.kernel.org/doc/Documentation/cgroup-v1/net_cls.txt)
iptables -t nat -A OUTPUT -p tcp -j REDIRECT ! -s 127.0.0.1/32 \
--to-port ${ISTIO_PROXY_PORT} -m cgroups '!' --cgroup ${ISTIO_NET_CLS_ID}
/sys/fs/cgroup/net_cls
。会在proxy container内要求额外的特权, 通过proxy agent可以在启动或执行envoy之前丢弃特权。另外,节点级的代理可以通过诸如UDS之类的每pod proxy agent来代表管理net_cls。本文翻译 Istio Pilot Proxy sidecar 注入,原文链接为 proxy-injectiont。
Istio的目标是给最终用户部署一个透明的切最小影响的代理注入。理想情况下,一个K8S注入控制器会通过重写specs以在提交之前包含必要的初始化和代理容器,但是当前这需要先upstream K8S的变化,而这是我们当前想要避免的。如果存在一种动态插件机制以使准入控制器可以保持在out-of-tree的状态将会是较好的替代方法。当前还没有平台支持这样,但是已经创建了一个增加这个特性的proposal(查阅 Proposal: Extensible Admission Control)。 Istio 自动代理注入将被长期跟踪在 Kubernetes Admission Controller for proxy injection。
一个短期的解决缺少合适的istio准入控制器的解决办法是客户端注入。使用 istioctl kube-inject
去增加必要的额配置到K8S resources files中。
istioctl kube-inject -f deployment.yaml -o deployment-with-istio.yaml
或者 在applying之前即时更新resource。
istioctl kube-inject -f depoyment.yaml | kubectl apply -f -
或者更新一个存在的deployment
kubectl get deployment -o yaml | istioctl kube-inject -f - | kubectl apply -f -
istioctl kube-inject 会在K8S obj、DaemonSet和Deployment YAML 资源文件中更新 PodTemplateSpec。支持额外的基于pod的必要的resource类型。
不受支持的reources未修改,例如,在一个包含多个Service和Configmap以及Deployment定义的复杂应用的独立文件上执行 istioctl kube-inject
。
Istio 项目正持续发展,所以low-level 的代理配置可能在没有通知的情况下发生变化。当你产生疑惑时,请在你的原始的部署上重新运行istioctl kube-inject
。
$ istioctl kube-inject --help
Inject istio runtime into existing kubernete resources
Usage:
inject [flags]
Flags:
```
--discoveryPort int Pilot discovery port (default 8080)
```
-f, --filename string Unmodified input kubernetes resource filename
```
--initImage string Istio init image (default "docker.io/istio/init:latest")
--mixerPort int Mixer port (default 9091)
```
-o, --output string Modified output kubernetes resource filename
```
--runtimeImage string Istio runtime image (default "docker.io/istio/runtime:latest")
--sidecarProxyUID int Sidecar proxy UID (default 1337)
--verbosity int Runtime verbosity (default 2)
```
本文翻译 Istio Pilot 代理控制器,原文链接为 roxy controller。
Istio Pilot 通过传播服务注册信息和路由规则给目的代理 来控制Istio代理的网格。当前,Istio 代理是基于Envoy的,Envoy的控制器由以下两部分组成:
为保证所有的流量能被Istio 代理抓取。Istio Pilot依赖于iptables规则。 服务实例用常规的HTTP headers进行通信,但所有的请求会被Istio 代理基于请求的元数据和Istio路由规则 抓取并重路由。 代理注入的详细细节位于proxy-injection。由于所有的网络流量会被抓取,外部服务请求在服务模型中需要特殊的外部服务representation。
代理agent是一个简单的agent,主要的工作是订阅网状拓扑和配置存储中的变化,并重配置代理。随着越来越多部分的Envoy配置通过服务发现变得有价值,我们这正渐渐地将配置生成委托给服务发现。举个例子,TCP 代理配置大部分由本地代理agent来配置,因为Envoy尚未实现对tcp_proxy的路由发现的支持。
服务发现发布服务拓扑和路由信息给网格中所有的代理。每个代理都携带一个身份(在k8s sidecar 部署的场景中为pod name和IP address)。Envoy 使用这个身份构造一个请求给发现服务(discovery service)。发现服务(discovery service)通过服务注册表(service registry)计算跑在这个代理address上的服务实例集合,并创建适配于发出请求的代理的Envoy配置。 Istio Pilot暴露了三种类型的发现服务:
ip:port
对的集合路由规则被定义在Istio API proto schema 中。可用的例子放在integration tests中。
待续
本文翻译 Istio Pilot 配置流程,原文链接为 Configuration flow in Istio Pilot。
Istio 配置由配置对象(configuration objects)组成。每个对象拥有kind(像routing rule就是一种kind),name和namespace,唯一标识对象。 Istio Pilot 提供一套基于rest的接口,并用objects的key去操作objects。Objects可以被用keys来检索并按照kind或namespace列出来(listed),或删除(deleted),或创建(created, 就是POST操作),或更新(updated, 就是PUT 操作)。
配置注册表(configuration registry)提供了一个监视配置存储变更的缓存控制器借口。举个例子,一个功能能订阅接收特性对象的创建objects事件。控制器流化这些订阅者的事件,并维护一个所有存储的本地缓存视图。
配置流开始于操作者(operator 下面的1小节讲解),接着到平台指定的永久存储(persistent storage 下面的2小节讲解),然后在远程代理组件(remote proxy component 下面的3小节讲解)上触发一个通知事件。
Istio Pilot 提供istioctl的命令行工具,用于暴露基于rest的配置存储借口。这个工具为已注册的Isito配置类型验证输入的Yaml文件满足模式要求(schema),并存储验证过的输入信息到存储中。
Istio 配置存储(configuration storage) 是平台相关的。下面,我们聚焦K8S, 因为Istio Pilot模型与K8S模型相近,类似于第三方的资源(K8S的Resources)。实际上,如果kubectl能够支持第三方资源的验证和补丁语义,kubectl 能够代替istioctl。
每个Istio配置对象 被存储作一个K8S的三方资源类型 istioconfig。这个资源的名字是一个Istio和configuration的组合, 并namespaces在K8S和Istio之间共享。在内部,这意味着K8S为istio在etcd中分配了一个key子集,暴露一个用于流更新的http 端点给存储,并为创建一个缓存控制器接口(cached controller interface)提供了必要的API 机制。你可以使用kubectl get istioconfigs
查询K/V存储。
一旦一个配置对象存在于etcd中,存储的更新就会被发送给代理的代理控制器。代理的agent通过创建新的代理配置并本地化到agent所运行的pod来做出反应。如果配置不变,则通知被成功处理。相反地,agent触发代理重配置(proxy reconfiguration)。一个Istio未来的目标,是提供一个反馈回路,当代理配置失败或者其他原因导致代理失败时报告给存储。
本文翻译 Istio Pilot 设计概述,原文链接为 [Istio Pilot design overview]https://github.com/istio/pilot/blob/master/doc/design.md)。
Istio Pilot 负责消费和传递 Istio 配置给Istio 组件。它在如K8S这样的底层集群管理平台上提供了一层抽象层,和代理控制器动态重配置Istio代理。
Service模型的概述文档位于 Service model。它介绍了Service version的概念,Service version是一个用versions(v1,v2)或者environment(staging环境,prod环境)来细分service实例精细化的Service 概念。Istio routing rules可以通过引用service version提供服务之间的增强的流控能力。
Istio Pilot的配置流(configuration flow)的概述文章位于 configuration-flow。指定routing rules的模式(schema) 位于代码中的istio/pilot/api/proxy/v1/config/
。Istio配置以分布式K/V存储为后端。Istio pilot组件通过在配置存储中订阅变更事件(change events)以执行实时配置更新。
Istio Pilot的代理控制器的概述文档位于 Proxy controller。Istio Pilot 监管与服务实例以sidecar container共存的代理的网格。一个proxy的代理人(agant)从服务和配置模型生成适合本地代理实例的新配置,并触发代理更新配置。
图中使用黑箭头表示数据通道,用红箭头表示控制通道。代理(Proxies)从服务抓取流量,并使用从服务发现(discovery services)和代理生成的配置(agaent-gnerated configurations)获取的控制信息将流量在内部和外部进行路由。这里获取的控制信息(control information)存储在K8S的API server中,并被kubectl或者istioctl这些操作工具管理。
本文翻译 Istio服务模型,原文链接为 Istio service model。
本文描述了Istio的服务和实例的抽象模型。该模型独立于K8S和Mesos这一类的底层平台。平台(istio/pilot/platform, 有consul,eureka,kube)下的特定适配器通过平台的元数据填充模型对象的各个字段。(istio/pilot/proxy)下的代码是独立于平台的代理,它使用模型中的representaion去生成七层sidecar代理的配置文件。proxy的代码具体到各个代理的实现。
Service是具有唯一名称的应用程序的单位,其他服务在引用它的功能的时候会通过名称来调用。实例实现了Service的功能,如 pods/VMs/containers。
有多种版本的Service,在一个持续部署的环境,对于一个Service,会有多组实例以多种二进制的不同变体潜在运行着。这些变体不一定是不同的API版本,它们对同一个服务进行迭代变更,部署在不同的环境上,如生产环境、演示环境和开发环境等,常见发生的场景是A/B测试和金丝雀等。
每个服务拥有一个全域名(FQDN)和一个或多个监听连接的端口,有些服务会拥有独立的负载均衡器或虚IP,如DNS,使得DNS查询全域名去解析为虚IP或负载均衡IP。
例子:在K8S中,一个Service foo 被 foo.default.svc.cluster.local hostname 关联,拥有一个虚IP 10.0.1.1 和80以及8080监听端口。
每个服务拥有一个或多个实例,就像服务的实际表现。实例代表实体,就像containers, pod(kubernetes/mesos), VMs等,举个例子,设想配置一个叫catalog的nodeJs后端服务,hostname为catalogservice.mystore.com
, 跑在10个虚拟机上,监听8080端口。
注意在上面例子中,后端的虚机并不需要暴露服务在一个端口上。实例可以是NAT-ed(mesos)或者跑在一个隧道网络上,这取决于不同的网络规划。这些虚机可以用来托管监听在一个或多个端口上的服务,直到负载均衡器直到如何去转发一个连接到正确的pod上。
举个例子,一个调用,http://catalogservice.mystore.com:8080/getCatalog
会解析到负载局衡器IP 10.0.0.1:8080
, 负载均衡器会转发连接到十个虚机的其中一个,如172.16.1.1:55446
或 172.16.0.2:22425
, 172.16.0.3:35345
等。
网络端点:网络IP地址和端口与各个实例关联(如上面的172.16.0.1:55446
),这被称作网络端点。到负载均衡器IP 10.0.0.1:8080
或主机名 catalog.mystore.com:8080
的调用会最终路由到一个实际的网络端点。
Service并不一定需要一个负载器IP,也可以拥有一个简单的基于DNV 服务器的系统,这样,DNS 服务器通过解析catalog.mystore.com:8080
,调用到10个后端的IP。
一个服务的每个version 被与版本关联的一组唯一的labels区别开。Lables是分配给service version的实例的简单键值对,如, 同一个version的所有实例会拥有相同的标签。举个例子,我们可以说,catalog.mystore.com
拥有V1和V2 两个version。
我们可以说,v1版本有labels对应于gitCommit=aeiou234,region=us-east
, V2版本拥有labels name=kittyCat,region=us-east
。我们可以说, 实例172.16.0.1 .. 171.16.0.5
跑这个服务的v1版本。
这些实例会使用labels gitCommit=aeiou234
, region=us-east
通过服务注册自注册他们自己,同时, 172.16.0.6 .. 172.16.0.10
的实例会使用labels name=kittyCat,region=us-east
通过服务注册进行自注册。
Isitio期望底层平台能够提供服务注册和发现的机制。大多数的容器平台,像K8S或mesos会内置服务注册,并且pod规范会包含所有与版本相关的额labels。pod启动后,平台会使用注册表以及labels自动注册pod。对于其他的平台,可能需要一个像Consul这样的特定的服务注册代理使用服务祖册或发现方案来自动注册服务。
当前,Istio已经集成K8S 服务注册,可以自动发现pod的服务,或代表一个服务版本的一组唯一的pod集合。未来,Istio将支持从Mesos注册表或其他注册表拉取同类信息。
当监听一个服务的不同实例时,labels将不同实例组合分开到不同的子集合里,举个例子,由labels gitCommit=aeiou234,region=us-east
标识的这组pod,会给所有的实例标识成 service catalog.mystore.com
的V1版本。
在缺少多version的情况下,每个service拥有一个由该服务的所有实例组成的默认version,九个例子,如果catalog.mystore.com
下的所有pod没有任何labels,那么 Istio会认为catalog.mystore.com
是这个服务的默认version,由10个IP范围在 172.16.0.1 .. 172.16.0.10
的虚机组成。
应用不会感知service的不同version。他们通过hostname/ip 地址访问服务,但Istio会基于管理员设置的routing rules路由连接或请求到对于对应的version。这个模型使得应用代码能够从所依赖服务的演进中解耦出来, 同时提供其他的好处。
请注意,Istio并没有DNS能力。应用可以使用底层平台的DNS服务区解析全域名。在一些平台,像K8S, DNS名字解析成服务的负载均衡器IP地址,对于其他的平台,DNS名字可能会解析成一个或多个实例的IP地址,像mesos-dns。两种情况都是可行的,对应用程序没有影响。
应用不会感知service的不同version。他们通过hostname/ip 地址访问服务,但Istio会基于管理员设置的routing rules路由连接或请求到对于对应的version。这个模型使得应用代码能够从所依赖服务的演进中解耦出来, 同时提供其他的好处。
请注意,Istio并没有DNS能力。应用可以使用底层平台的DNS服务区解析全域名。在一些平台,像K8S, DNS名字解析成服务的负载均衡器IP地址,对于其他的平台,DNS名字可能会解析成一个或多个实例的IP地址,像mesos-dns。两种情况都是可行的,对应用程序没有影响。
Istio sidecar 代理 在应用和服务之间拦截和转发所有的额请求和响应。对于service version的实际选择是有代理sidecar进程基于由管理员设置的routing rules动态确定。4层和7层routing roules都支持。
Routing rules允许代理基于像headers或url等标准, 或source/destination,或权重等标准选择labels关联version。