Skip to content

8、Istio工作负载

更新于:2023年12月28日2

Istio工作负载

目录

[toc]

本节实战

实战名称
🚩 实战:WorkloadEntry测试-2023.12.21(测试成功)

前言

在之前的章节中我们已经多次提到了工作负载,在 Istio 中工作负载是指部署在 Kubernetes 中的应用程序,但是如果我们的工作负载是不在 Kubernetes 集群中(如虚拟机中)那么还能否使用 Istio 呢?答案是肯定的。

Istio 提供了 WorkloadEntry资源对象,用于将非 Kubernetes 工作负载引入到 Istio 网格中。

WorkloadEntry必须与一个 Istio ServiceEntry一起使用,配合对 ServiceEntry定义的服务进行服务实例注册。WorkloadEntry允许我们描述非 Pod 端点,这些端点应该仍然是网格的一部分,并将其与 Pod 同等对待,比如在工作负载之间启用 MUTUAL_TLS,无论它们是否是容器化的。

1、WorkloadEntry

要创建一个 WorkloadEntry并将其附加到一个 ServiceEntry上,可以这样实现:

yaml
apiVersion:networking.istio.io/v1beta1kind:WorkloadEntrymetadata:name:vm1namespace:ns1spec:address:1.1.1.1labels:app:fooinstance-id:vm-78ad2class:vm---apiVersion:networking.istio.io/v1beta1kind:ServiceEntrymetadata:name:svc1namespace:ns1spec:hosts:- svc1.internal.comports:- number:80name:httpprotocol:HTTPresolution:STATICworkloadSelector:# 工作负载选择器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(测试成功)

实验环境:(实验软件-无)

bash
k8sv1.27.6(containerd:istiov1.19.3(--setprofile=demo)

  • 比如现在我们在虚拟机上面部署一个 whoami的应用,当然可以使用手动的方式来进行部署,为了方便我们将在 192.168.0.100这个节点上使用 Docker(或者 Containerd)来部署这个服务,并暴露 8888 端口:
bash
# 如果是 docker 则使用 docker$nerdctlrun-d-p8888:80--namewhoamitraefik/whoami:v1.10.1--verbose$nerdctlpsCONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES98cd22ef6d1adocker.io/traefik/whoami:v1.10.1"/whoami --verbose"5secondsagoUp0.0.0.0:8888->80/tcpwhoami[root@master1 ~]#curl http:Hostname:8f66c4c3da05IP:127.0.0.1IP:::1IP:10.4.0.2IP:fe80::9cbc:94ff:fe9d:7dceRemoteAddr:172.29.9.61:49796GET/HTTP/1.1Host:172.29.9.61:8888User-Agent:curl/7.29.0Accept:*/*[root@master1 ~]###查看日志[root@master1 ~]#nerdctl logs -f whoami2023/12/1923:58:44Startinguponport802023/12/2004:12:30172.29.9.61:49796--[20/Dec/2023:04:12:30 +0000]"GET / HTTP/1.1"--##当然,在浏览器里访问也是一样的。……

现在如果我们想通过 Istio 来代理这个服务,那么我们需要将这个外部的服务引入到 Istio 网格中。

  • 首先需要创建一个如下所示的 WorkloadEntry对象:
yaml
# whoami-we.yamlapiVersion:networking.istio.io/v1beta1kind:WorkloadEntrymetadata:name:whoami-wespec:address:172.29.9.61labels:app:whoamiinstance-id:vm1

在上面的 WorkloadEntry对象中我们指定了 addresslabels字段,其中 address字段指定了我们在虚拟机上面的服务地址,labels字段指定了我们的服务的标签,这些标签可以用于 ServiceEntry对象中的 workloadSelector字段,这样就可以将 ServiceEntryWorkloadEntry关联起来了。

  • 然后再创建一个如下所示的 ServiceEntry对象:
yaml
# whoami-se.yamlapiVersion:networking.istio.io/v1beta1kind:ServiceEntrymetadata:name:whoami-sespec:hosts:- whoami.internal.com# 这里的域名可以自定义ports:- number:80name:httpprotocol:HTTPtargetPort:8888# 注意这里的端口要和上面的端口一致location:MESH_INTERNALresolution:STATIC# 静态解析workloadSelector:labels:app:whoami

上面的 ServiceEntry对象中我们指定了 hosts字段,这个字段指定了我们的服务的域名,这个域名可以自定义,但是要保证这个域名在网格中是唯一的。然后我们还指定了 ports字段,这个字段指定了我们的服务的端口,里面的 targetPort端口要和我们在 WorkloadEntry中指定的端口一致。然后最重要的是指定 workloadSelector字段,这个字段指定了我们的服务的标签,这些标签可以用于 WorkloadEntry对象中的 labels字段,这样就可以将 ServiceEntryWorkloadEntry关联起来了。

另外需要注意其中有一个 location字段,这个字段指定了服务是属于 Istio 网格之内还是网格之外,位置决定了一些功能的行为,例如服务之间的 mTLS 身份验证、策略执行等。当与网格之外的服务通信时,Istio 的 mTLS 身份验证被禁用,并且策略执行是在客户端而不是服务器端执行的,可以配置的值有两个:

  • MESH_EXTERNAL:表示该服务位于网格外部,通常用于指示通过 API 使用的外部服务。
  • MESH_INTERNAL:表示该服务是网格的一部分,常用于指示在扩展服务网格以包含非托管基础设施时显式添加的服务(例如,添加到基于 Kubernetes 的服务网格的虚拟机)。

我们这里是要将服务引入到 Istio 网络中来所以使用 MESH_INTERNAL

  • 然后再创建一个如下所示的 VirtualServiceGateway对象:
yaml
# whoami-istio.yamlapiVersion:networking.istio.io/v1beta1kind:Gatewaymetadata:name:whoami-gwspec:selector:istio:ingressgatewayservers:- port:number:8080name:httpprotocol:HTTPhosts:- whoami.internal.com---apiVersion:networking.istio.io/v1beta1kind:VirtualServicemetadata:name:whoami-vsspec:hosts:- whoami.internal.comgateways:- whoami-gwhttp:- route:- destination:host:whoami.internal.comport:number:80---apiVersion:networking.istio.io/v1beta1kind:DestinationRulemetadata:name:whoami-drspec:host:whoami.internal.comtrafficPolicy:loadBalancer:simple:ROUND_ROBIN
  • 直接应用上面的资源对象即可:
yaml
##部署kubectl apply -f whoami-we.yamlkubectl apply -f whoami-se.yamlkubectl apply -f whoami-istio.yaml##查看[root@master1 WorkloadEntry]#kubectl get workloadentryNAME AGE ADDRESSwhoami-we 10s 192.168.0.100[root@master1 WorkloadEntry]#kubectl get serviceentryNAME HOSTS LOCATION RESOLUTION AGEwhoami-se ["whoami.internal.com"] MESH_INTERNAL STATIC 17s[root@master1 ~]#kubectl get gatewayNAME AGEbookinfo-gateway 2d1hhttpbin-gateway 4d10hwhoami-gw 3m1s[root@master1 ~]#kubectl get vsNAME GATEWAYS HOSTS AGEbookinfo ["bookinfo-gateway"] ["*"] 2d1hhttpbin ["httpbin-gateway"] ["*"] 4d10hwhoami-vs ["whoami-gw"] ["whoami.internal.com"] 3m20s[root@master1 ~]#kubectl get drNAME HOST AGEwhoami-dr whoami.internal.com 3m41s[root@master1 ~]#
  • 然后我们就可以访问 whoami.internal.com来验证是否可以正常访问了,也可以通过查看 whoami的日志来验证是否可以正常访问:
bash
$nerdctllogs-fwhoami2023/12/1505:35:37Startinguponport802023/12/1505:35:54192.168.0.100:54958--[15/Dec/2023:05:35:54 +0000]"GET / HTTP/1.1"--

记得将 whoami.internal.com解析到 Istio Ingress Gateway 的 IP 地址。

bash
[root@master1 ~]#kubectl get po -nistio-system -owide -l app=istio-ingressgatewayNAMEREADYSTATUSRESTARTSAGEIPNODENOMINATEDNODEREADINESSGATESistio-ingressgateway-9c8b9b586-5nx581/1Running015m10.244.2.28node2<none><none>[root@master1 ~]#kubectl get svc -nistio-system -l app=istio-ingressgatewayNAMETYPECLUSTER-IPEXTERNAL-IPPORT(S) AGEistio-ingressgatewayLoadBalancer10.105.233.167<pending>15021:31410/TCP,80:31666/TCP,443:32213/TCP,31400:30291/TCP,15443:31787/TCP43d##host映射172.29.9.63whoami.internal.com

从上面的结果可以看到我们的服务已经成功引入到 Istio 网格中了。 测试结束。😘

同样我们还可以在 Kubernetes 集群中这个 whoami工作负载,由于前面我们在 ServiceEntry中通过 workloadSelector指定了 app:whoami标签,所以只要保证我们的工作负载具有这个标签即可。

  • 比如我们创建一个如下所示的 Deployment对象:
yaml
# whoami-deploy.yamlapiVersion:apps/v1kind:Deploymentmetadata:name:whoamispec:selector:matchLabels:app:whoamitemplate:metadata:labels:app:whoamispec:containers:- name:whoamiimage:traefik/whoami:v1.10.1command:- --verbose# 打印详细日志- --port=8888# 指定端口,匹配我们在 ServiceEntry 中指定的端口ports:- containerPort:8888
  • 直接创建上面的资源对象即可:
bash
# 记得要注入 sidecar,我们这里 default 命名空间的自动注入是开启的。(为什么要注入sideacar呢???😥)$kubectlapply-fwhoami-deploy.yaml$kubectlgetpods-lapp=whoamiNAMEREADYSTATUSRESTARTSAGEwhoami-5c685456d6-8cskw2/2Running05m27s
  • 部署完成后,我们再次访问 whoami.internal.com,可以看到请求会在 Kubernetes 集群中的 Pod 和虚拟机中的工作负载之间进行负载均衡请求。


🔱:注意

  • 奇怪:我这里k8s的pod创建失败了,报如下错误?

nerdctl命令创建的容器都是可以运行的哇:

bash
[root@master1 WorkloadEntry]#nerdctl psCONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES8f66c4c3da05docker.io/traefik/whoami:v1.10.1"/whoami --verbose"22hoursagoUp0.0.0.0:8888->80/tcpwhoami

难道是端口问题???--(没错呀。。。估计是文档哪里出现问题了。。。)

🔰 注意:以上问题可以用如下方式解决

command换成args 。

自己本次未实际测试,这里仅做记录!!!(2023年12月28日)

🔰 那么问题来了:

k8s的deployment资源对象下container里使用command和使用args有啥区别吗?

在Kubernetes的Deployment资源对象中,container字段用于定义Pod中的容器。在这个container字段中,你可以使用commandargs字段来配置容器的启动命令和参数。这两者之间有一些区别:

  1. command字段:

    • command字段用于指定在容器启动时执行的命令。
    • 如果在command字段中提供了一个非空的命令列表,Kubernetes将仅执行该命令,而不会启动默认的应用程序。
    • 该命令将覆盖容器映像中定义的任何默认命令。

    例如:

    yaml
    yamlcontainers:- name:my-containerimage:my-imagecommand:["echo","Hello"]

    上面的例子中,容器将执行echo Hello命令。

  2. args字段:

    • args字段用于指定在容器启动时传递给容器中的命令的参数。
    • 它允许你在容器启动时传递额外的参数给容器中运行的应用程序。

    例如:

    yaml
    yamlcontainers:- name:my-containerimage:my-imagecommand:["echo"]args:["Hello"]

    上面的例子中,容器将执行echo Hello命令,与上面的command示例相同。

总的来说,command字段用于指定容器的启动命令,而args字段用于向该命令传递参数。你可以根据需要选择使用它们中的一个或两者结合使用。


多实例

在 Kubernetes 中一个服务可以有多个实例,同样对于一个 ServiceEntry当然也可以关联多个 WorkloadEntry,每个实例还可以使用标签标识实例的版本。

这个小部分没做测试哦,只记录。

  • 比如我们可以创建一个如下所示的 WorkloadEntry对象:
yaml
apiVersion:networking.istio.io/v1beta1kind:WorkloadEntrymetadata:name:test1-wespec:address:192.168.0.10labels:app:testversion:v1---apiVersion:networking.istio.io/v1beta1kind:WorkloadEntrymetadata:name:test2-wespec:address:192.168.0.11labels:app:testversion:v2---apiVersion:networking.istio.io/v1beta1kind:WorkloadEntrymetadata:name:test3-wespec:address:192.168.0.12labels:app:testversion:v2
  • 我们在 ServiceEntry对象中只需要将 workloadSelector的标签设置为 app:test即可,这样就会将这三个实例都关联到这个 ServiceEntry对象中,然后我们就可以通过 version标签来区分不同的实例了。
yaml
apiVersion:networking.istio.io/v1beta1kind:ServiceEntrymetadata:name:test-sespec:hosts:- test.internal.comports:- number:80name:httpprotocol:HTTPlocation:MESH_INTERNALresolution:STATICworkloadSelector:labels:app:test

不同端口

在大多数情况下,服务和实例的端口我们都可以在 ServiceEntry对象中进行统一的定义,在WorkloadEntry对象中我们只需要指定 addresslabels字段即可,但是如果我们的服务和实例的端口不一致,那么我们就需要在 WorkloadEntry对象中指定 ports字段,比如有两个虚拟机上面的实例分别在 8091 和 8092 端口上接收流量,这种方式在传统的微服务场景中比较常见,一个服务的多个实例被部署在同一个虚拟机上面,但是每个实例都使用不同的端口,这种方式可以避免端口冲突。

  • 创建一个如下所示的 WorkloadEntry对象:
yaml
apiVersion:networking.istio.io/v1beta1kind:WorkloadEntrymetadata:name:test1-wespec:address:192.168.0.10labels:app:testversion:v1ports:http:8091---apiVersion:networking.istio.io/v1beta1kind:WorkloadEntrymetadata:name:test2-wespec:address:192.168.0.12labels:app:testversion:v2ports:http:8092

权重

此外 WorkloadEntry对象中我们还可以通过 weight字段来指定与端点关联的负载均衡权重,具有较高权重的端点将获得相应比例的流量。

  • 比如我们可以创建一个如下所示的 WorkloadEntry对象:
yaml
apiVersion:networking.istio.io/v1beta1kind:WorkloadEntrymetadata:name:test1-wespec:address:192.168.0.10labels:app:testversion:v1ports:http:8091weight:20---apiVersion:networking.istio.io/v1beta1kind:WorkloadEntrymetadata:name:test2-wespec:address:192.168.0.12labels:app:testversion:v2ports:http:8092weight: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

yaml
apiVersion:networking.istio.io/v1beta1kind:WorkloadEntrymetadata:name:test1-wespec:address:192.168.0.10labels:app:testversion:v1ports:http:8091locality:us/us-east-1/az-1/r11---apiVersion:networking.istio.io/v1beta1kind:WorkloadEntrymetadata:name:test2-wespec:address:192.168.0.20labels:app:testversion:v2ports:http:8092locality:us/us-east-1/az-2/r12

上面的 WorkloadEntry对象中我们指定了 locality字段,这个字段用于指定与端点相关联的位置,当然还是需要一个 ServiceEntry对象来关联这两个 WorkloadEntry对象,这里就不再赘述了。

除了通过配置 sidecar 之外我们也可以在 DestinationRule对象中指定 localityLbSetting字段来指定位置的负载策略,比如我们可以创建一个如下所示的 DestinationRule对象:

yaml
apiVersion:networking.istio.io/v1alpha3kind:DestinationRulemetadata:name:test-drspec:host:test.internal.comtrafficPolicy:loadBalancer:consistentHash:useSourceIp:truelocalityLbSetting:enabled:truefailover:- from:us/us-east-1/az-1/r11to:us/us-east-1/az-2/r12- from:us/us-east-1/az-2/r12to:us/us-east-1/az-1/r11outlierDetection:consecutive5xxErrors:1interval:1sbaseEjectionTime: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位置的端点上。

2、WorkloadGroup

除了支持通过 WorkloadEntry创建服务实例之外,Istio 还引入了一个 WorkloadGroup资源对象,该资源对象描述了一组工作负载实例,它提供了一个规范,工作负载实例可以使用该规范来引导其代理,包括元数据和身份信息。它仅用于非 Kubernetes 工作负载(如虚拟机)。

WorkloadGroup对象的定义和 Deployment非常类似,比如我们可以定义一个如下所示的 WorkloadGroup对象:

yaml
apiVersion:networking.istio.io/v1beta1kind:WorkloadGroupmetadata:name:test-wgspec:metadata:labels:app:testtemplate:ports:http:8091serviceAccount:defaultprobe:httpGet:path:/healthport:8091

WokloadGroup对象中描述了一个负载的模板,这个模板可以用来动态生成 WorkloadEntry的服务实例,类似在 Kubernetes 中的 Deployment对象中的模板生成 Pod 实例。

上面的示例中可以看到 WorkloadGroup对象中并不涉及到服务访问的 Host 等信息,同样的服务相关的定义还是需要通过 ServiceEntry来定义。

WorkloadGroupWorkloadEntryServiceEntry三者之间的关系就和 Kubernetes 中的 DeploymentPodService三者之间的关系类似,如下表所示:

对比项Kubernetes虚拟机
基础调度实体PodWorkloadEntry
编排组合DeploymentWorkloadGroup
服务注册与发现ServiceServiceEntry

整体上 WorkloadGroup对象的核心包括三个字段: metadatatemplateprobe

  • metadata:这个字段用来定义在 WorkloadEntry上生成的元数据信息,包括标签、注解等信息。
  • template:定义 WorkloadEntry的模板,需要注意该模板里面只配置负载通用的信息,无须配置实例地址和实例标签等服务实例的自身信息。
  • probe:和 Kubernetes 中的健康检查类似的配置和机制,只有探针通过的实例才被注册到服务段,否则不会被注册。WorkloadGroup支持配置 HTTP、TCP 和 EXEC 三种类型的探针。

WorkloadGroup主要用于虚拟机服务的自动注册,比如在每个虚拟机节点上部署的服务网格数据面都连接到控制面 Istiod,控制面会根据配置的 WorkloadGroup信息自动创建 WorkloadEntry实例,在后面虚拟机章节中再和大家演示,这里就不再赘述了。

关于我

我的博客主旨:

  • 排版美观,语言精炼;
  • 文档即手册,步骤明细,拒绝埋坑,提供源码;
  • 本人实战文档都是亲测成功的,各位小伙伴在实际操作过程中如有什么疑问,可随时联系本人帮您解决问题,让我们一起进步!

🍀 微信二维码 x2675263825 (舍得), qq:2675263825。 image-20230107215114763

🍀 微信公众号 《云原生架构师实战》 image-20230107215126971

🍀 个人博客站点 http:

版权:此文章版权归 One 所有,如有转载,请注明出处!

链接:可点击右上角分享此页面复制文章链接

上次更新时间:

最近更新