一.模块概览
使用ServiceEntry把服务添加到istio内部服务注册表,配置sidecar代理,使用Envoy Filter定制Envoy 配置。
使用ServiceEntry,sidecar,Envoy Filter的前提是已经安装好了istio,关于istio的安装部署,请查看博客《Istio(二):在Kubernetes(k8s)集群上安装部署istio1.14》https://www.cnblogs.com/renshengdezheli/p/16836404.html
二.系统环境
服务器版本 | docker软件版本 | Kubernetes(k8s)集群版本 | Istio软件版本 | CPU架构 |
---|---|---|---|---|
CentOS Linux release 7.4.1708 (Core) | Docker version 20.10.12 | v1.21.9 | Istio1.14 | x86_64 |
Kubernetes集群架构:k8scloude1作为master节点,k8scloude2,k8scloude3作为worker节点
服务器 | 操作系统版本 | CPU架构 | 进程 | 功能描述 |
---|---|---|---|---|
k8scloude1/192.168.110.130 | CentOS Linux release 7.4.1708 (Core) | x86_64 | docker,kube-apiserver,etcd,kube-scheduler,kube-controller-manager,kubelet,kube-proxy,coredns,calico | k8s master节点 |
k8scloude2/192.168.110.129 | CentOS Linux release 7.4.1708 (Core) | x86_64 | docker,kubelet,kube-proxy,calico | k8s worker节点 |
k8scloude3/192.168.110.128 | CentOS Linux release 7.4.1708 (Core) | x86_64 | docker,kubelet,kube-proxy,calico | k8s worker节点 |
三.ServiceEntry
通过 ServiceEntry 资源,我们可以向 Istio 的内部服务注册表添加额外的条目,使不属于我们网格的外部服务或内部服务看起来像是我们服务网格的一部分。
当一个服务在服务注册表中时,我们就可以使用流量路由、故障注入和其他网格功能,就像我们对其他服务一样。
下面是一个 ServiceEntry 资源的例子,它声明了一个可以通过 HTTPS 访问的外部 API(api.external-svc.com
)。
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: external-svc
spec:
hosts:
- api.external-svc.com
ports:
- number: 443
name: https
protocol: TLS
resolution: DNS
location: MESH_EXTERNAL
hosts
字段可以包含多个外部 API,在这种情况下,Envoy sidecar 会根据下面的层次结构来进行检查。如果任何一项不能被检查,Envoy 就会转到层次结构中的下一项。
- HTTP Authority 头(在HTTP/2中)和 Host 头(HTTP/1.1中)
- SNI
- IP 地址和端口
如果上述数值都无法检查,Envoy 会根据 Istio 的安装配置,盲目地转发请求或放弃该请求。
与 WorkloadEntry 资源一起,我们可以处理虚拟机工作负载向 Kubernetes 迁移的问题。在 WorkloadEntry 中,我们可以指定在虚拟机上运行的工作负载的细节(名称、地址、标签),然后使用 ServiceEntry 中的 workloadSelector
字段,使虚拟机成为 Istio 内部服务注册表的一部分。
例如,假设 customers
的工作负载正在两个虚拟机上运行。此外,我们已经有在 Kubernetes 中运行的 Pod,其标签为 app: customers
。
让我们这样来定义 WorkloadEntry 资源:
apiVersion: networking.istio.io/v1alpha3
kind: WorkloadEntry
metadata:
name: customers-vm-1
spec:
serviceAccount: customers
address: 1.0.0.0
labels:
app: customers
instance-id: vm1
---
apiVersion: networking.istio.io/v1alpha3
kind: WorkloadEntry
metadata:
name: customers-vm-2
spec:
serviceAccount: customers
address: 2.0.0.0
labels:
app: customers
instance-id: vm2
现在我们可以创建一个 ServiceEntry 资源,该资源同时跨越 Kubernetes 中运行的工作负载和虚拟机:
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: customers-svc
spec:
hosts:
- customers.com
location: MESH_INTERNAL
ports:
- number: 80
name: http
protocol: HTTP
resolution: STATIC
workloadSelector:
labels:
app: customers
在 location
字段中设置 MESH_INTERNAL
,这是说这个服务是网格的一部分。这个值通常用于包括未管理的基础设施(VM)上的工作负载的情况。这个字段的另一个值,MESH_EXTERNAL
,用于通过 API 消费的外部服务。MESH_INTERNAL
和 MESH_EXTERNAL
设置控制了网格中的 sidecar 如何尝试与工作负载进行通信,包括它们是否会默认使用 Istio 双向TLS。
四.sidecar
4.1 Sidecar
默认情况下,在istio中,注入的 sidecar 代理接收所有端口的流量,并且在转发流量时可以到达网格中的任何服务。
在某些情况下,你可能想改变这种配置,配置代理,所以它只能使用特定的端口和访问某些服务。要做到这一点,你可以在 Istio 中使用 Sidecar 资源。
Sidecar 资源可以被部署到 Kubernetes 集群内的一个或多个命名空间,但如果没有定义工作负载选择器,每个命名空间只能有一个 sidecar 资源。
Sidecar 资源由三部分组成,一个工作负载选择器、一个入口(ingress)监听器和一个出口(egress)监听器。
4.2 工作负载选择器
工作负载选择器决定了哪些工作负载会受到 sidecar 配置的影响。你可以决定控制一个命名空间中的所有 sidecar,而不考虑工作负载,或者提供一个工作负载选择器,将配置只应用于特定的工作负载。
例如,这个 YAML 适用于默认命名空间内的所有代理,因为没有定义选择器。
apiVersion: networking.istio.io/v1alpha3
kind: Sidecar
metadata:
name: default-sidecar
namespace: default
spec:
egress:
- hosts:
- "default/*"
- "istio-system/*"
- "staging/*"
在 egress 部分,我们指定代理可以访问运行在 default
、istio-system
和 staging
命名空间的服务。要将资源仅应用于特定的工作负载,我们可以使用 workloadSelector
字段。例如,将选择器设置为 version: v1
将只适用于有该标签设置的工作负载。
apiVersion: networking.istio.io/v1alpha3
kind: Sidecar
metadata:
name: default-sidecar
namespace: default
spec:
workloadSelector:
labels:
version: v1
egress:
- hosts:
- "default/*"
- "istio-system/*"
- "staging/*"
4.3 入口和出口监听器
资源的入口(ingress)监听器部分定义了哪些入站流量被接受。同样地,通过出口(egress)监听器,你可以定义出站流量的属性。
每个入口监听器都需要一个端口设置,以便接收流量(例如,下面的例子中的 3000)和一个默认的端点。默认端点可以是一个回环 IP 端点或 Unix 域套接字。端点配置了流量将被转发到哪里。
...
ingress:
- port:
number: 3000
protocol: HTTP
name: somename
defaultEndpoint: 127.0.0.1:8080
...
上面的片段将入口监听器配置为在端口 3000 上监听,并将流量转发到服务监听的端口 8080 上的回环 IP。此外,我们可以设置 bind
字段,以指定一个 IP 地址或域套接字,我们希望代理监听传入的流量。最后,字段 captureMode
可以用来配置如何以及是否捕获流量。
出口监听器有类似的字段,但增加了hosts
字段。通过 hosts
字段,你可以用 namespace/dnsName
的格式指定服务主机。例如, myservice.default
或 default/*
。在 hosts
字段中指定的服务可以是来自网格注册表的实际服务、外部服务(用 ServiceEntry 定义),或虚拟服务。
egress:
- port:
number: 8080
protocol: HTTP
hosts:
- "staging/*"
通过上面的 YAML文件,sidecar 代理了运行在 staging
命名空间的服务的 8080 端口的流量。
五.Envoy Filter
5.1 Envoy Filter
EnvoyFilter 资源允许你定制由 Istio Pilot 生成的 Envoy 配置。使用该资源,你可以更新数值,添加特定的过滤器,甚至添加新的监听器、集群等等。小心使用这个功能,因为不正确的定制可能会破坏整个网格的稳定性。
过滤器是叠加应用的,这意味着对于特定命名空间中的特定工作负载,可以有任何数量的过滤器。根命名空间(例如 istio-system
)中的过滤器首先被应用,然后是工作负载命名空间中的所有匹配过滤器。
下面是一个 EnvoyFilter 的例子,它在请求中添加了一个名为 api-version
的头。
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: api-header-filter
namespace: default
spec:
workloadSelector:
labels:
app: web-frontend
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
portNumber: 8080
filterChain:
filter:
name: "envoy.http_connection_manager"
subFilter:
name: "envoy.router"
patch:
operation: INSERT_BEFORE
value:
name: envoy.lua
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
inlineCode: |
function envoy_on_response(response_handle)
response_handle:headers():add("api-version", "v1")
end
如果你向 $GATEWAY_URL
发送一个请求,你可以注意到 api-version
头被添加了,如下所示:
$ curl -s -I -X HEAD http://$GATEWAY_URL
HTTP/1.1 200 OK
x-powered-by: Express
content-type: text/html; charset=utf-8
content-length: 2471
etag: W/"9a7-hEXE7lJW5CDgD+e2FypGgChcgho"
date: Tue, 17 Nov 2020 00:40:16 GMT
x-envoy-upstream-service-time: 32
api-version: v1
server: istio-envoy