实战名称 |
---|
🚩 实战:WorkloadEntry测试-2023.12.21(测试成功) |
在之前的章节中我们已经多次提到了工作负载,在 Istio 中工作负载是指部署在 Kubernetes 中的应用程序,但是如果我们的工作负载是不在 Kubernetes 集群中(如虚拟机中)那么还能否使用 Istio 呢?答案是肯定的。
Istio 提供了 WorkloadEntry
资源对象,用于将非 Kubernetes 工作负载引入到 Istio 网格中。
WorkloadEntry
必须与一个 Istio ServiceEntry
一起使用,配合对 ServiceEntry
定义的服务进行服务实例注册。WorkloadEntry
允许我们描述非 Pod 端点,这些端点应该仍然是网格的一部分,并将其与 Pod 同等对待,比如在工作负载之间启用 MUTUAL_TLS
,无论它们是否是容器化的。
要创建一个 WorkloadEntry
并将其附加到一个 ServiceEntry
上,可以这样实现:
apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
name: vm1
namespace: ns1
spec:
address: 1.1.1.1
labels:
app: foo
instance-id: vm-78ad2
class: vm
---
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: svc1
namespace: ns1
spec:
hosts:
- svc1.internal.com
ports:
- number: 80
name: http
protocol: HTTP
resolution: STATIC
workloadSelector: # 工作负载选择器
labels:
app: foo
这将创建一个带有一组标签和地址的新 WorkloadEntry
,以及使用 WorkloadSelector
来选择所有带有所需标签的端点的 ServiceEntry
,在这种情况下包括为 VM 创建的 WorkloadEntry
。
ServiceEntry
可以同时引用 Pod 和 WorkloadEntry
,使用相同的选择器,现在 Istio 可以对 VM 和 Pod 进行相同的处理,而不是将它们分开。如果要将一些工作负载迁移到 Kubernetes,且选择保留大量的 VM,则 WorkloadSelector
可以同时选择 Pod 和 VM,Istio 会自动在它们之间进行负载均衡,现在我们就可以让 VM 和 Pod 共存,而不需要任何配置来将两者连接起来。
🚩 实战:WorkloadEntry测试-2023.12.21(测试成功)
实验环境:(实验软件-无)
k8s v1.27.6(containerd://1.6.20)(cni:flannel:v0.22.2)
istio v1.19.3(--set profile=demo)
whoami
的应用,当然可以使用手动的方式来进行部署,为了方便我们将在 192.168.0.100
这个节点上使用 Docker(或者 Containerd)来部署这个服务,并暴露 8888 端口:# 如果是 docker 则使用 docker
$ nerdctl run -d -p 8888:80 --name whoami traefik/whoami:v1.10.1 --verbose
$ nerdctl ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
98cd22ef6d1a docker.io/traefik/whoami:v1.10.1 "/whoami --verbose" 5 seconds ago Up 0.0.0.0:8888->80/tcp whoami
[root@master1 ~]#curl http://172.29.9.61:8888
Hostname: 8f66c4c3da05
IP: 127.0.0.1
IP: ::1
IP: 10.4.0.2
IP: fe80::9cbc:94ff:fe9d:7dce
RemoteAddr: 172.29.9.61:49796
GET / HTTP/1.1
Host: 172.29.9.61:8888
User-Agent: curl/7.29.0
Accept: */*
[root@master1 ~]#
##查看日志
[root@master1 ~]#nerdctl logs -f whoami
2023/12/19 23:58:44 Starting up on port 80
2023/12/20 04:12:30 172.29.9.61:49796 - - [20/Dec/2023:04:12:30 +0000] "GET / HTTP/1.1" - -
##当然,在浏览器里访问也是一样的。
……
现在如果我们想通过 Istio 来代理这个服务,那么我们需要将这个外部的服务引入到 Istio 网格中。
WorkloadEntry
对象:# whoami-we.yaml
apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
name: whoami-we
spec:
address: 172.29.9.61
labels:
app: whoami
instance-id: vm1
在上面的 WorkloadEntry
对象中我们指定了 address
和 labels
字段,其中 address
字段指定了我们在虚拟机上面的服务地址,labels
字段指定了我们的服务的标签,这些标签可以用于 ServiceEntry
对象中的 workloadSelector
字段,这样就可以将 ServiceEntry
和 WorkloadEntry
关联起来了。
ServiceEntry
对象:# whoami-se.yaml
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: whoami-se
spec:
hosts:
- whoami.internal.com # 这里的域名可以自定义
ports:
- number: 80
name: http
protocol: HTTP
targetPort: 8888 # 注意这里的端口要和上面的端口一致
location: MESH_INTERNAL
resolution: STATIC # 静态解析
workloadSelector:
labels:
app: whoami
上面的 ServiceEntry
对象中我们指定了 hosts
字段,这个字段指定了我们的服务的域名,这个域名可以自定义,但是要保证这个域名在网格中是唯一的。然后我们还指定了 ports
字段,这个字段指定了我们的服务的端口,里面的 targetPort
端口要和我们在 WorkloadEntry
中指定的端口一致。然后最重要的是指定 workloadSelector
字段,这个字段指定了我们的服务的标签,这些标签可以用于 WorkloadEntry
对象中的 labels
字段,这样就可以将 ServiceEntry
和 WorkloadEntry
关联起来了。
另外需要注意其中有一个 location
字段,这个字段指定了服务是属于 Istio 网格之内还是网格之外,位置决定了一些功能的行为,例如服务之间的 mTLS 身份验证、策略执行等。当与网格之外的服务通信时,Istio 的 mTLS 身份验证被禁用,并且策略执行是在客户端而不是服务器端执行的,可以配置的值有两个:
MESH_EXTERNAL
:表示该服务位于网格外部,通常用于指示通过 API 使用的外部服务。MESH_INTERNAL
:表示该服务是网格的一部分,常用于指示在扩展服务网格以包含非托管基础设施时显式添加的服务(例如,添加到基于 Kubernetes 的服务网格的虚拟机)。我们这里是要将服务引入到 Istio 网络中来所以使用 MESH_INTERNAL
。
VirtualService
和 Gateway
对象:# whoami-istio.yaml
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: whoami-gw
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 8080
name: http
protocol: HTTP
hosts:
- whoami.internal.com
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: whoami-vs
spec:
hosts:
- whoami.internal.com
gateways:
- whoami-gw
http:
- route:
- destination:
host: whoami.internal.com
port:
number: 80
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: whoami-dr
spec:
host: whoami.internal.com
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
##部署
kubectl apply -f whoami-we.yaml
kubectl apply -f whoami-se.yaml
kubectl apply -f whoami-istio.yaml
##查看
[root@master1 WorkloadEntry]#kubectl get workloadentry
NAME AGE ADDRESS
whoami-we 10s 192.168.0.100
[root@master1 WorkloadEntry]#kubectl get serviceentry
NAME HOSTS LOCATION RESOLUTION AGE
whoami-se ["whoami.internal.com"] MESH_INTERNAL STATIC 17s
[root@master1 ~]#kubectl get gateway
NAME AGE
bookinfo-gateway 2d1h
httpbin-gateway 4d10h
whoami-gw 3m1s
[root@master1 ~]#kubectl get vs
NAME GATEWAYS HOSTS AGE
bookinfo ["bookinfo-gateway"] ["*"] 2d1h
httpbin ["httpbin-gateway"] ["*"] 4d10h
whoami-vs ["whoami-gw"] ["whoami.internal.com"] 3m20s
[root@master1 ~]#kubectl get dr
NAME HOST AGE
whoami-dr whoami.internal.com 3m41s
[root@master1 ~]#
whoami.internal.com
来验证是否可以正常访问了,也可以通过查看 whoami
的日志来验证是否可以正常访问:$ nerdctl logs -f whoami
2023/12/15 05:35:37 Starting up on port 80
2023/12/15 05:35:54 192.168.0.100:54958 - - [15/Dec/2023:05:35:54 +0000] "GET / HTTP/1.1" - -
记得将
whoami.internal.com
解析到 Istio Ingress Gateway 的 IP 地址。
[root@master1 ~]#kubectl get po -nistio-system -owide -l app=istio-ingressgateway
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
istio-ingressgateway-9c8b9b586-5nx58 1/1 Running 0 15m 10.244.2.28 node2 <none> <none>
[root@master1 ~]#kubectl get svc -nistio-system -l app=istio-ingressgateway
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 10.105.233.167 <pending> 15021:31410/TCP,80:31666/TCP,443:32213/TCP,31400:30291/TCP,15443:31787/TCP 43d
##host映射
172.29.9.63 whoami.internal.com
从上面的结果可以看到我们的服务已经成功引入到 Istio 网格中了。
测试结束。😘
同样我们还可以在 Kubernetes 集群中这个 whoami
工作负载,由于前面我们在 ServiceEntry
中通过 workloadSelector
指定了 app: whoami
标签,所以只要保证我们的工作负载具有这个标签即可。
Deployment
对象:# whoami-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: whoami
spec:
selector:
matchLabels:
app: whoami
template:
metadata:
labels:
app: whoami
spec:
containers:
- name: whoami
image: traefik/whoami:v1.10.1
command:
- --verbose # 打印详细日志
- --port=8888 # 指定端口,匹配我们在 ServiceEntry 中指定的端口
ports:
- containerPort: 8888
# 记得要注入 sidecar,我们这里 default 命名空间的自动注入是开启的。(为什么要注入sideacar呢???😥)
$ kubectl apply -f whoami-deploy.yaml
$ kubectl get pods -l app=whoami
NAME READY STATUS RESTARTS AGE
whoami-5c685456d6-8cskw 2/2 Running 0 5m27s
whoami.internal.com
,可以看到请求会在 Kubernetes 集群中的 Pod 和虚拟机中的工作负载之间进行负载均衡请求。在 Kubernetes 中一个服务可以有多个实例,同样对于一个 ServiceEntry
当然也可以关联多个 WorkloadEntry
,每个实例还可以使用标签标识实例的版本。
这个小部分没做测试哦,只记录。
WorkloadEntry
对象:apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
name: test1-we
spec:
address: 192.168.0.10
labels:
app: test
version: v1
---
apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
name: test2-we
spec:
address: 192.168.0.11
labels:
app: test
version: v2
---
apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
name: test3-we
spec:
address: 192.168.0.12
labels:
app: test
version: v2
ServiceEntry
对象中只需要将 workloadSelector
的标签设置为 app: test
即可,这样就会将这三个实例都关联到这个 ServiceEntry
对象中,然后我们就可以通过 version
标签来区分不同的实例了。apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: test-se
spec:
hosts:
- test.internal.com
ports:
- number: 80
name: http
protocol: HTTP
location: MESH_INTERNAL
resolution: STATIC
workloadSelector:
labels:
app: test
在大多数情况下,服务和实例的端口我们都可以在 ServiceEntry
对象中进行统一的定义,在WorkloadEntry
对象中我们只需要指定 address
和 labels
字段即可,但是如果我们的服务和实例的端口不一致,那么我们就需要在 WorkloadEntry
对象中指定 ports
字段,比如有两个虚拟机上面的实例分别在 8091 和 8092 端口上接收流量,这种方式在传统的微服务场景中比较常见,一个服务的多个实例被部署在同一个虚拟机上面,但是每个实例都使用不同的端口,这种方式可以避免端口冲突。
WorkloadEntry
对象:apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
name: test1-we
spec:
address: 192.168.0.10
labels:
app: test
version: v1
ports:
http: 8091
---
apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
name: test2-we
spec:
address: 192.168.0.12
labels:
app: test
version: v2
ports:
http: 8092
此外 WorkloadEntry
对象中我们还可以通过 weight
字段来指定与端点关联的负载均衡权重,具有较高权重的端点将获得相应比例的流量。
WorkloadEntry
对象:apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
name: test1-we
spec:
address: 192.168.0.10
labels:
app: test
version: v1
ports:
http: 8091
weight: 20
---
apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
name: test2-we
spec:
address: 192.168.0.12
labels:
app: test
version: v2
ports:
http: 8092
weight: 80
在上面的 WorkloadEntry
对象中我们指定了 weight
字段,这个字段用于指定权重,这样就可以实现流量的分流了。
另外 WorkloadEntry
对象中还有一个 locality
字段,这个字段用于指定与端点相关联的位置,位置对应于故障域(例如国家/地区/区域)。可以通过使用 /
来分隔每个封装的故障域来表示任意故障域层次结构。例如,位于美国(US)的端点的位置,在 US-East-1
地区,在可用性区域 az-1
中,在数据中心机架 r11
中就可以表示为 us/us-east-1/az-1/r11
。Istio 将配置 sidecar 将路由到与 sidecar 相同位置的端点。如果本地不存在可用的端点,则将选择上级位置(但在相同的网络 ID 中)。例如,如果同一网络(网络 ID n1
)中有两个端点,一个位于位置 us/us-east-1/az-1/r11
的端点 e1
,另一个位于 us/us-east-1/az-2/r12
的端点 e2
,那么来自 us/us-east-1/az-1/r11
位置的 sidecar 将优先选择来自相同位置的 e1
,而不是来自不同位置的 e2
。
apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
name: test1-we
spec:
address: 192.168.0.10
labels:
app: test
version: v1
ports:
http: 8091
locality: us/us-east-1/az-1/r11
---
apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
name: test2-we
spec:
address: 192.168.0.20
labels:
app: test
version: v2
ports:
http: 8092
locality: us/us-east-1/az-2/r12
上面的 WorkloadEntry
对象中我们指定了 locality
字段,这个字段用于指定与端点相关联的位置,当然还是需要一个 ServiceEntry
对象来关联这两个 WorkloadEntry
对象,这里就不再赘述了。
除了通过配置 sidecar 之外我们也可以在 DestinationRule
对象中指定 localityLbSetting
字段来指定位置的负载策略,比如我们可以创建一个如下所示的 DestinationRule
对象:
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: test-dr
spec:
host: test.internal.com
trafficPolicy:
loadBalancer:
consistentHash:
useSourceIp: true
localityLbSetting:
enabled: true
failover:
- from: us/us-east-1/az-1/r11
to: us/us-east-1/az-2/r12
- from: us/us-east-1/az-2/r12
to: us/us-east-1/az-1/r11
outlierDetection:
consecutive5xxErrors: 1
interval: 1s
baseEjectionTime: 1m
在上面的 DestinationRule
对象中我们指定了 localityLbSetting
字段,这个字段用于指定位置的负载均衡设置,其中我们通过 failover
字段指定了故障转移策略,当 us/us-east-1/az-1/r11
位置的端点不可用时,就会将流量转移到 us/us-east-1/az-2/r12
位置的端点上,当 us/us-east-1/az-2/r12
位置的端点不可用时,就会将流量转移到 us/us-east-1/az-1/r11
位置的端点上。
除了支持通过 WorkloadEntry
创建服务实例之外,Istio 还引入了一个 WorkloadGroup
资源对象,该资源对象描述了一组工作负载实例,它提供了一个规范,工作负载实例可以使用该规范来引导其代理,包括元数据和身份信息。它仅用于非 Kubernetes 工作负载(如虚拟机)。
WorkloadGroup
对象的定义和 Deployment
非常类似,比如我们可以定义一个如下所示的 WorkloadGroup
对象:
apiVersion: networking.istio.io/v1beta1
kind: WorkloadGroup
metadata:
name: test-wg
spec:
metadata:
labels:
app: test
template:
ports:
http: 8091
serviceAccount: default
probe:
httpGet:
path: /health
port: 8091
WokloadGroup
对象中描述了一个负载的模板,这个模板可以用来动态生成 WorkloadEntry
的服务实例,类似在 Kubernetes 中的 Deployment
对象中的模板生成 Pod 实例。
上面的示例中可以看到 WorkloadGroup
对象中并不涉及到服务访问的 Host 等信息,同样的服务相关的定义还是需要通过 ServiceEntry
来定义。
WorkloadGroup
、WorkloadEntry
和 ServiceEntry
三者之间的关系就和 Kubernetes 中的 Deployment
、Pod
和 Service
三者之间的关系类似,如下表所示:
对比项 | Kubernetes | 虚拟机 |
基础调度实体 | Pod | WorkloadEntry |
编排组合 | Deployment | WorkloadGroup |
服务注册与发现 | Service | ServiceEntry |
整体上 WorkloadGroup
对象的核心包括三个字段: metadata
、template
与 probe
。
metadata
:这个字段用来定义在 WorkloadEntry
上生成的元数据信息,包括标签、注解等信息。template
:定义 WorkloadEntry
的模板,需要注意该模板里面只配置负载通用的信息,无须配置实例地址和实例标签等服务实例的自身信息。probe
:和 Kubernetes 中的健康检查类似的配置和机制,只有探针通过的实例才被注册到服务段,否则不会被注册。WorkloadGroup
支持配置 HTTP、TCP 和 EXEC 三种类型的探针。WorkloadGroup
主要用于虚拟机服务的自动注册,比如在每个虚拟机节点上部署的服务网格数据面都连接到控制面 Istiod,控制面会根据配置的 WorkloadGroup
信息自动创建 WorkloadEntry
实例,在后面虚拟机章节中再和大家演示,这里就不再赘述了。
我的博客主旨:
🍀 微信二维码
x2675263825 (舍得), qq:2675263825。
🍀 微信公众号
《云原生架构师实战》
🍀 个人博客站点
http://onedayxyy.cn/
🍀 语雀
https://www.yuque.com/xyy-onlyone
🍀 csdn
https://blog.csdn.net/weixin_39246554?spm=1010.2135.3001.5421
🍀 知乎
https://www.zhihu.com/people/foryouone
好了,关于本次就到这里了,感谢大家阅读,最后祝大家生活快乐,每天都过的有意义哦,我们下期见!