K8S与Istio分工
Istio介绍
术语 服务网格(Service Mesh) 用来描述组成应用程序的微服务网络以及它们之间的交互,它的核心思想就是 Sidecar 模式。Sidecar 模式 是一种将应用功能从应用本身剥离出来作为单独进程的设计模式,该模式允许我们向应用无侵入添加多种功能。通信的事情全部交给 Sidecar 处理,而我们不需要再去关注通信的细节,只要专注开发业务功能本身问题就行。 Istio 是 Service Mesh 的一种实现,提供了流量控制、安全、可观测性等功能。
Istio 在希腊语中是 “sail” 的意思,它延用了 Kubernetes(在希腊语中意为舵手/飞行员)建立的希腊航海主题。 <br>
Istio架构
Istio 从逻辑上分为数据平面和控制平面:
- 数据平面(data plane):数据平面由一组以 Sidecar 方式部署的代理(proxy)组成,所有进入和流出服务的流量都会被代理拦截,并与控制面进行交互,根据配置执行相应的通信功能。
- 控制平面(control plane):在控制平面,Istio 由三个组件( Pilot、Citadel、Galley )整合成了一个单进程、多模块的 istiod。其中 Pilot 组件负责提供服务发现、智能路由(如金丝雀发布)和弹性功能(如超时、重试);Citadel 负责安全,管理密钥和证书;Galley 负责对配置的验证和处理等功能。
1.流量管理:这是 Istio的最基本的功能。 2.策略控制:通过 Mixer组件和各种适配器来实现,实现访问控制系统、遥测捕获、配额管理和计费等。 3.可观测性:通过日志记录来查看。 4.安全认证:Citadel 组件做密钥和证书管理。
envoy? proxy? istio-proxy? 傻傻分不清楚
- Envoy 是用 C++ 开发的高性能代理,用于协调服务网格中所有服务的入站和出站流量,由 Lyft 开源后贡献给了 CNCF。Envoy 和 Istio 并不是强绑定关系,一方面 Envoy 并不局限于 Istio,以它为基础的项目还有很多,比如 K8s 的 Ingress Controller;另一方面,Istio 也不局限于 Envoy,它是数据面的默认选择,但不是唯一选择。
- Sidecar 是服务网格部署模式中的逻辑概念,即运行在业务容器旁的边车。
- Proxy 是 Sidecar 功能上的概念,即作为进出服务流量的代理。
- istio-proxy:是被 Istio 注入的 Pod 中,运行着 Istio 相关进程的容器名称(container name)。
Pod 在创建过程中,实际会创建 3 个容器:
- istio-init 容器:是一个 init 容器,在另外两个容器启动前运行,进行一些初始化操作后退出。因此在 Pod 创建成功后,只会看到另外两个运行中的容器。
- istio-proxy 容器:运行着两个进程:pilot-agent 和 envoy。
- pilot-agent 是 istio-proxy容器的 1 号进程,负责启动 envoy 进程,并监控和管理其状态,如 envoy 出错时重启 envoy,或 envoy 配置变更后reload envoy。
- envoy 进程进行流量治理和转发。
- 微服务容器:具体的业务容器,运行具体的业务。
Istio 注入究竟是什么?
为指定 K8s 命名空间下的资源增加 Istio 的能力
$ kubectl label ns <namespace> istio-injection=enabled
查看是否被注入:
$ kubectl get namespace -L istio-injection | grep wly
wly Active 91d enabled
Istio 为我们提供了什么?
Kubernetes 1.7之后,提供了CRD(CustomResourceDefinitions)自定义资源的二次开发能力来扩展 K8s API,通过此扩展可以向 K8s API 中增加新的资源类型。
查看 Istio 的 CRD:
$ kubectl get crd | grep istio
authorizationpolicies.security.istio.io 2022-08-27T07:32:33Z
destinationrules.networking.istio.io 2022-08-27T07:32:34Z
envoyfilters.networking.istio.io 2022-08-27T07:32:20Z
gateways.networking.istio.io 2022-08-27T07:32:34Z
istiooperators.install.istio.io 2022-08-27T10:03:45Z
peerauthentications.security.istio.io 2022-08-27T07:32:34Z
requestauthentications.security.istio.io 2022-08-27T07:32:34Z
serviceentries.networking.istio.io 2022-08-27T07:32:34Z
sidecars.networking.istio.io 2022-08-27T07:32:34Z
virtualservices.networking.istio.io 2022-08-27T07:32:34Z
workloadentries.networking.istio.io 2022-08-27T07:32:34Z
workloadgroups.networking.istio.io 2022-08-27T07:32:34Z
查看 Istio 提供的 api-resources
$ kubectl api-resources | grep istio
istiooperators iop,io install.istio.io/v1alpha1 true IstioOperator
destinationrules dr networking.istio.io/v1beta1 true DestinationRule
envoyfilters networking.istio.io/v1alpha3 true EnvoyFilter
gateways gw networking.istio.io/v1beta1 true Gateway
serviceentries se networking.istio.io/v1beta1 true ServiceEntry
sidecars networking.istio.io/v1beta1 true Sidecar
virtualservices vs networking.istio.io/v1beta1 true VirtualService
workloadentries we networking.istio.io/v1beta1 true WorkloadEntry
workloadgroups wg networking.istio.io/v1alpha3 true WorkloadGroup
authorizationpolicies security.istio.io/v1beta1 true AuthorizationPolicy
peerauthentications pa security.istio.io/v1beta1 true PeerAuthentication
requestauthentications ra security.istio.io/v1beta1 true RequestAuthentication
Gateway
Istio 使用网关来管理网格的出入流量,具体地说,istio-ingressgateway 管理网格的入口流量,istio-egressgateway 管理网格的出口流量。上面我们提到,网格的流量之所以可被管理,是因为资源被 Istio 注入后在 Pod 中创建并运行了 istio-proxy 容器。网关流量管理的本质也基于同样道理,唯一不同的是 istio-ingressgateway 和 istio-egressgateway 运行时就是一个 istio-proxy 容器,即独立的 Envoy 代理,而不是与 Pod 一起运行的 Sidecar 代理。
$ kubectl get deploy -n istio-system | grep gateway
istio-ingressgateway 2/2 2 2 71d
istio-egressgateway 1/1 1 1 71d
Istio 网关充分利用了 Istio 流量路由的功能和灵活性,因为 Istio 的网关资源仅配置 L4-L6 层负载均衡属性,例如要暴露的端口和 mTLS 配置等,而将 L7 层(即应用层)流量路由使用 VirtualService 绑定网关来实现,这样的一番神操作就可以像管理 Istio 网格中数据平面的流量一样,来管理网关流量。
K8s Ingress 资源如下所示:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-wildcard-host
spec:
rules:
- host: "foo.bar.com"
http:
paths:
- pathType: Prefix
path: "/bar"
backend:
service:
name: service1
port:
number: 80
- host: "*.foo.com"
http:
paths:
- pathType: Prefix
path: "/foo"
backend:
service:
name: service2
port:
number: 80
由上例可知,在 Ingress 层直接就实现了流量管理。
Istio Gateway 资源如下所示(引用 Istio 官网例子):
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
selector:
istio: ingressgateway
servers:
- port: # 开放HTTP的80端口
number: 80
name: http
protocol: HTTP
hosts: # 允许通过此网关访问的host
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts: # 对应于上面配置的host
- "*"
gateways:
- bookinfo-gateway # 对应于上面所定义的网关名称
http: # 详细定义http路由规则
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage
port:
number: 9080
由上可知,Istio Gateway 并不像 K8s Ingress 一样直接在网关层实现流量路由,而是通过 VirtualService 绑定到网关的机制实现流量路由,VirtualService 和 Gateway 各司其职。Gateway 的作用就是分流,而 VirtualService 的作用就是将分流来的流量进行管理。
在 istio-system
命名空间下查看所有网关:
$ kubectl get gw -n istio-system
NAME AGE
gw-wly-admin-http 70d
gw-wly-private-https 70d
gw-wly-public-http 70d
gw-wly-sre-http 43d
istio-egressgateway 43d
istiod 72d
查看某个网关的详情:
$ kubectl get gw -n istio-system gw-wly-private-https -o yaml
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
annotations:
meta.helm.sh/release-name: global
meta.helm.sh/release-namespace: istio-system
labels:
app.kubernetes.io/managed-by: Helm
name: gw-wly-private-https
namespace: istio-system
spec:
selector:
istio: ingressgateway
servers:
- hosts:
- gw.wly.private.https.vpc
port:
name: https-gw
number: 1051
protocol: https
tls:
cipherSuites:
- ECDHE-ECDSA-AES128-GCM-SHA256
- ECDHE-RSA-AES128-GCM-SHA256
- ECDHE-ECDSA-AES256-GCM-SHA384
- ECDHE-RSA-AES256-GCM-SHA384
credentialName: istio-private-wly-certs
maxProtocolVersion: TLSV1_3
minProtocolVersion: TLSV1_2
mode: SIMPLE
DestinationRule
DestinationRule 是 Istio 流量路由的关键功能,它不能独自使用,必须跟 VirtualService 共同发挥作用。
VirtualService 决定将流量路由到的逻辑地址,而 DestinationRule 则决定流量路由到的物理地址,即子集(subset
)。VirtualService 跟 DestinationRule 的关系就像变量到内存的地址映射一样,比如 VirtualService 是程序的指针,而 DestinationRule 代表内存实际地址。
负载均衡选项
Istio 默认使用轮询的负载均衡策略,实例池中的每个实例依次获取请求。Istio 支持以下负载均衡模型,可以在 DestinationRule 中为流向某个特定服务或 subset
的流量进行配置。
- 轮询(
ROUND_ROBIN
):请求以轮询的方式转到池中的实例。 - 随机(
RANDOM
):请求以随机的方式转到池中的实例。 - 最少请求(
LEAST_REQUEST
):请求被转到最少被访问的实例。 - 权重(路由规则中的
weight
字段):请求根据指定的百分比转到实例。
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: bookinfo-ratings
spec:
host: ratings.prod.svc.cluster.local
trafficPolicy:
loadBalancer:
simple: LEAST_REQUEST
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
VirtualService
VirtualService 可以将流量路由到 K8s Service。每个 VirtualService 由一组路由规则组成,这些路由规则会按顺序进行匹配。
如果没有 VirtualService,仅仅使用 K8s Service 的话,那么只能实现最基本的流量负载均衡转发,不能实现类似按百分比来分配流量等更加复杂、丰富、细粒度的流量控制。
金丝雀发布
首先定义 helloworld 服务:
apiVersion: v1
kind: Service
metadata:
name: helloworld
labels:
app: helloworld
spec:
selector:
app: helloworld
...
然后添加 2 个 Deployment,分别为版本 v1
和 v2
,这两个版本都包含服务选择标签 app:helloworld
:
kind: Deployment
metadata:
name: helloworld-v1
spec:
replicas: 1
template:
metadata:
labels:
app: helloworld
version: v1
spec:
containers:
- image: helloworld-v1
...
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: helloworld-v2
spec:
replicas: 1
template:
metadata:
labels:
app: helloworld
version: v2
spec:
containers:
- image: helloworld-v2
...
在 Kubernetes 方式下控制流量分配需要调整每个 Deployment 的副本数目。例如,将 10% 的流量发送到金丝雀版本(v2
),v1
和 v2
的副本可以分别设置为 9 和 1。
但是通过 Istio 的 VirtualService,我们可以通过设置路由规则来控制流量分配,如将 10% 的流量发送到金丝雀版本:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: helloworld
spec:
hosts:
- helloworld
http:
- route:
- destination:
host: helloworld
subset: v1
weight: 90
- destination:
host: helloworld
subset: v2
weight: 10
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: helloworld
spec:
host: helloworld
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
VirtualService Delegate
Istio 通过 VirtualService 定义路由规则,控制流量路由到服务上的各种行为 。实际使用过程中,会遇到维护一个庞大的 VirtualService 的问题。服务的路由升级都要修改这个 VirtualService 规则,同时升级经常会导致服务路由更新冲突,路由配置冗余和耦合。
Istio 引入了 Delegate 机制,使服务的路由规则无需耦合在一个 VirtualService 中。将 VirtualService 拆分为主 VirtualService 和 Delegate VirtualService。主 VirtualService 定义了服务的总规则,Delegate VirtualService 定义详细路由规则,简化路由配置,降低耦合。
实例1:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- "bookinfo.com"
gateways:
- mygateway
http:
- match:
- uri:
prefix: "/productpage"
delegate:
name: productpage
namespace: nsA
- match:
- uri:
prefix: "/reviews"
delegate:
name: reviews
namespace: nsB
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: productpage
namespace: nsA
spec:
http:
- match:
- uri:
prefix: "/productpage/v1/"
route:
- destination:
host: productpage-v1.nsA.svc.cluster.local
- route:
- destination:
host: productpage.nsA.svc.cluster.local
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
namespace: nsB
spec:
http:
- route:
- destination:
host: reviews.nsB.svc.cluster.local
实例2:
Delegate VirtualService
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
annotations:
meta.helm.sh/release-name: istio-wly-task-management-service
meta.helm.sh/release-namespace: wly
generation: 1
labels:
app.kubernetes.io/managed-by: Helm
name: wly-task-management-service-vs-delegate
namespace: wly
spec:
http:
- match:
- gateways:
- mesh
port: 80
retries:
attempts: 1
perTryTimeout: 12s
retryOn: refused-stream,connect-failure,reset,gateway-error
retryRemoteLocalities: true
route:
- destination:
host: wly-task-management-service.wly.svc.cluster.local
port:
number: 80
subset: v1
- match:
- gateways:
- istio-system/gw-wly-admin-http
port: 1050
retries:
attempts: 1
perTryTimeout: 12s
retryOn: refused-stream,connect-failure,reset,gateway-error
retryRemoteLocalities: true
route:
- destination:
host: wly-task-management-service.wly.svc.cluster.local
port:
number: 80
subset: v1
- match:
- gateways:
- istio-system/gw-wly-private-https
port: 1051
retries:
attempts: 1
perTryTimeout: 12s
retryOn: refused-stream,connect-failure,reset,gateway-error
retryRemoteLocalities: true
route:
- destination:
host: wly-task-management-service.wly.svc.cluster.local
port:
number: 80
subset: v1
主 VirtualService:
# 网格内流量路由
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
annotations:
meta.helm.sh/release-name: istio-wly-task-management-service
meta.helm.sh/release-namespace: wly
generation: 1
labels:
app.kubernetes.io/managed-by: Helm
name: wly-task-management-service-vs-default
namespace: wly
spec:
# 如果省略gateways字段,默认值是mesh,表示路由规则会应用到网格内的所有边车上
# gateways:
# - mesh
hosts:
- wly-task-management-service.wly.svc.cluster.local
http:
- delegate:
name: wly-task-management-service-vs-delegate
namespace: wly
match:
- uri:
prefix: /
# 来自wly-admin网关流量的路由
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
annotations:
meta.helm.sh/release-name: istio-wly-task-management-service
meta.helm.sh/release-namespace: wly
generation: 1
labels:
app.kubernetes.io/managed-by: Helm
name: wly-task-management-service-vs-admin-gateway
namespace: wly
spec:
gateways:
- istio-system/gw-wly-admin-http
hosts:
- gw.wly.admin.http.vpc
http:
- delegate:
name: wly-task-management-service-vs-delegate
namespace: wly
match:
- uri:
prefix: /public/ui/wly/taskmanager
# 来自wly-private网关流量的路由
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
annotations:
meta.helm.sh/release-name: istio-wly-task-management-service
meta.helm.sh/release-namespace: wly
generation: 1
labels:
app.kubernetes.io/managed-by: Helm
name: wly-task-management-service-vs-private-gateway
namespace: wly
spec:
gateways:
- istio-system/gw-wly-private-https
hosts:
- gw.wly.private.https.vpc
http:
- delegate:
name: wly-task-management-service-vs-delegate
namespace: wly
match:
- uri:
prefix: /public/api/wly/taskmanager
AuthorizationPolicy
授权功能是 Istio 中安全体系的一个重要组成部分,可以使用 AuthorizationPolicy 来实现访问控制的功能,即判断一个请求是否允许通过,这个请求可以是从外部进入网格内部的请求,也可以是在网格内部从服务 A 到服务 B 的请求。
AuthorizationPolicy 支持 DENY
、ALLOW
、AUDIT
和 CUSTOM
4种类型的操作,默认为 ALLOW
。
$ k get authorizationpolicy -n wly -o yaml wly-metadata-service-authpolicy
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
annotations:
meta.helm.sh/release-name: istio-wly-metadata-service
meta.helm.sh/release-namespace: wly
generation: 6
labels:
app.kubernetes.io/managed-by: Helm
name: wly-metadata-service-authpolicy
namespace: wly
spec:
rules:
- from:
- source:
principals:
- cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account
- cluster.local/ns/ai-security/sa/ai-security-vm
- cluster.local/ns/wly/sa/wly-data-service
- cluster.local/ns/wly/sa/wly-task-management-service
selector:
matchLabels:
app: wly-metadata-service
PeerAuthentication
PeerAuthentication 用于服务间的认证,以验证建立连接的客户端。
当两个服务试图进行通信时,mTLS 要求它们都向对方提供证书,因此双方都知道它们在与谁通信。如果我们想在服务之间启用严格的 mTLS,我们可以将 PeerAuthentication 的 mTLS 模式设置为 STRICT
。
$ k get pa -n wly wly-metadata-service-pa -o yaml
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
annotations:
meta.helm.sh/release-name: istio-wly-metadata-service
meta.helm.sh/release-namespace: wly
generation: 1
labels:
app.kubernetes.io/managed-by: Helm
name: wly-metadata-service-pa
namespace: wly
spec:
mtls:
mode: STRICT
selector:
matchLabels:
app: wly-metadata-service
ServiceEntry
Istio 内部会维护一个与平台无关的使用通用模型表示的服务注册表,当网格内部需要访问外部服务的时候,就需要使用 ServiceEntry 来添加服务注册。添加 ServiceEntry 后,边车可以将流量发送到该服务,就好像该服务是网格中的服务一样。通过配置 ServiceEntry,可以管理在网格外部运行的服务的流量。
$ k get se -n istio-system
NAME HOSTS LOCATION RESOLUTION AGE
se-base ["gw.base.private.https.vpc"] DNS 44d
se-base-sre ["gw.base.sre.private.https.vpc"] DNS 42d
$ k get se -n istio-system -o yaml se-base
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
annotations:
meta.helm.sh/release-name: global
meta.helm.sh/release-namespace: istio-system
generation: 1
labels:
app.kubernetes.io/managed-by: Helm
name: se-base
namespace: istio-system
spec:
hosts:
- gw.base.private.https.vpc
ports:
- name: https
number: 443
protocol: HTTPS
resolution: DNS
服务请求流转案例
集群内访问
如图中pod2 访问pod1, pod2 业务容器发起请求,流量流经pod2 的 istio-proxy, 将流量转发给目标服务pod1的istio-proxy, 最后将流量转发给pod1 业务容器, 在两个边车容器直接传输走mtls, 业务不感知认证信息
同一个服务网格内,不同集群直接访问
如图中pod3 访问pod1, pod3 业务容器发起请求,流量流经pod3 的 istio-proxy, 将流量转发给目标服务pod1的istio-proxy, 最后将流量转发给pod1 业务容器, 在两个边车容器直接传输走mtls, 业务不感知认证信息, 同一个服务网格内访问时,不走网关
跨服务网格方案
不同的服务网格之间,网格是隔离的,需要通过vpcep 打通网络连接(vpc 对等也可以,但是vpc 对等打通的是两个VPC 的网络,范围比较大,乾坤云不推荐使用,乾坤云的网络一般是按需进行打通), 对端的请求通过egress gateway 出口,通过对等连接,达到ELB, 通过ELB 达到ingress-gateway, 通过网关达到业务容器的istio-proxy, 最终达到业务容器
系统外部访问
如上图中黑色的箭头方向,系统外请求通过DNS 域名解析服务器 找到对应的APIG , APIG 根据后端服务器地址找到对应的ELB, ELB 后端服务器绑定对应的ingress-gateway, 流量流经ingress gateway 之后,根据路由策略达到业务pod 的边车服务,边车服务转发给业务容器
标签:wly,VirtualService,name,istio,Istio,玩转,io,K8s From: https://blog.51cto.com/noregrets/7242025