前言
前面提到过,Istio 的 Helm Chart,除去用于安装之外,还有部分对 Istio 部署进行调整的能力。Gateways 一节内容,就包含了定制 Istio Ingress/Egress Gateway 的能力。
这个 Chart 的文件结构和其他组件类似,不同的在于内容,它通过对 values.yaml
中定义的 Gateways 相关内容的循环遍历,生成不同的 Gateway 单元,下面将会进行讲解和试验。
values.yaml
中的变量定义:
gateways: enabled: true istio-ingressgateway: enabled: true labels: app: istio-ingressgateway istio: ingressgateway replicaCount: 1 autoscaleMin: 1 autoscaleMax: 5 resources: {} # limits: # cpu: 100m # memory: 128Mi #requests: # cpu: 1800m # memory: 256Mi cpu: targetAverageUtilization: 80 loadBalancerIP: "" serviceAnnotations: {} type: LoadBalancer #change to NodePort, ClusterIP or LoadBalancer if need be ports: ## You can add custom gateway ports - port: 80 targetPort: 80 name: http2 nodePort: 31380 - port: 443 ...
其中包含了一个层次结构:Gateways 的下级除了用于 requirements.yaml
使用的 enabled
字段之外,还包含一个数组,数组的每个元素定义了一个网关。
range $key, $spec := .Values
:对 gateways
一节的局部变量进行遍历,第一层遍历的值用 $key
和 $spec
两个变量来表示键值对,根据每个键值对的定义,逐个创建资源,下面会提到的 $spec
引用就是相当于每个网关控制器的定义变量,$key
就是每个网关控制器的名称。
Chart.yaml
元数据文件,无需赘述。
autoscale.yaml
首先讲解一下头部的渲染条件:
{{- range $key, $spec := .Values }} {{- if and (ne $key "global") (ne $key "enabled") }} {{- if and $spec.enabled $spec.autoscaleMin }} apiVersion: autoscaling/v2beta1 kind: HorizontalPodAutoscaler metadata: name: {{ $key }} namespace: {{ $spec.namespace | default $.Release.Namespace }} spec: maxReplicas: {{ $spec.autoscaleMax }} minReplicas: {{ $spec.autoscaleMin }} scaleTargetRef: apiVersion: apps/v1beta1 kind: Deployment name: {{ $key }} metrics: - type: Resource resource: name: cpu targetAverageUtilization: {{ $spec.cpu.targetAverageUtilization }} --- {{- end }} {{- end }} {{- end }}
顾名思义,这个文件是用来创建 HPA 的,但是整个文件的外层由一个 range
语句所包围:
{{- if and (ne $key "global") (ne $key "enabled") }}
将会跳过global
和enabled
键。{{- if and $spec.enabled $spec.autoscaleMin }}
:如果前面读到的$spec
变量中的enabled
和autoscaleMin
都是true
,才会进行处理。这里条件跟其它几个文件不同:只有设置了autoscaleMin
的情况下才会渲染 HPA 对象。
引用变量:
$key
:也就是网关的名称,例如前面的istio-ingressgateway
。$spec.namespace
:可以为这一 Gateway 定义命名空间,如果没有定义,则沿用 Istio 的命名空间,也就是Release.Namespace
。$spec.autoscaleMax
和$spec.autoscaleMin
,Gateway 伸缩的上下限。cpu.targetAverageUtilization
:伸缩指标,目标平均 CPU 占用率。
RBAC 资源
同样的,这里定义了每个网关所对应的 ServiceAccount
、ClusterRole
以及 ClusterRoleBinding
,用于 RBAC。
Gateway 角色需要对 thirdpartyresources
、virtualservices
、destinationrules
以及 gateways
几种资源进行读写。
看 meta.name
的定义可以看出,每个网关都会有自己的 RBAC 资源,命名规则为 [网关名称]-[Istio 所在的命名空间]
。
另外 ServiceAccount 中引用了全局变量 imagePullSecrets
。
deployment.yaml
这个模板用于 Deployment
的创建过程。这个部署运行的主要服务进程和 Ingress Chart 一样,是 pilot-agent。
全局变量
priorityClassName
hub
tag
istioNamespace
proxy.envoyStatsd
controlPlaneSecurityEnabled
defaultResources
nodeaffinity
变量使用细节
$spec.labels
:这里可以看出,我们可以使用在values.yaml
中定义标签labels
的方式,为新的 Deployment 指定标签。标签将同时出现在 Deployment 和下面的 Pod 中。,从而定义Gateway
资源时,可以用标签来指定对应的控制器。$spec.replicaCount
:可以指定初始副本数量。$spec.ports
:在ports
中定义的各种端口,会在容器中进行发布。Gateway 名称在这里还作为
--serviceCluster
的值,这一参数在 Sidecar 中一般取值为istio-proxy
。如果定义了
global.istioNamespace
,会使用[服务名].[命名空间]
的方式定义zipkin
、istio-pilot
的服务地址。根据
global.proxy.envoyStatsd
设置statsd
地址。如果 Gateway 定义中包含了资源限制的内容,则会在这里进行包含,否则只会使用缺省资源限制。
$spec.additionalContainers
中还可以定义该 Pod 中额外的容器。如果有加载额外 tls secret 的需求,可以定义在
$spec.secretVolume
中。如果有加载额外 Configmap 的需求,可以定义在
$spec.configVolumes
中。
service.yaml
和其他元素一样,Service 也是使用循环的方式逐个建立的。
服务名称同样也是直接使用
$key
。端口、命名空间、标签和 Deployment 模板一致。
$spec.serviceAnnotations
用于生成服务注解。selector
的定义也和标签定义一致。如果定义了
$spec.loadBalancerIP
,这里会给服务的loadBalancerIP
赋值。如果定义了
.type
,则将服务类型进行修改。
测试一下
在 values.yaml
的 gateways
一节加入这样一段:
istio-myingress: enabled: true namespace: default labels: app: istio-ingressgateway istio: myingress replicaCount: 1 autoscaleMax: 5 resources: {} cpu: targetAverageUtilization: 80 loadBalancerIP: "" serviceAnnotations: {} type: NodePort ports: - port: 80 targetPort: 80 name: http-myingress
然后用命令行生成对应的安装文件:
$ helm template istio --name istio -f \ values-new-gateway.yaml --namespace \ istio-system > istio-myingress.yaml
生成的 yaml,用编辑器打开,使用正则表达式 source:.*?gateways
进行搜索,会看到生成的内容符合之前的描述,在 Default
命名空间中出现了新的 ServiceAccount、ClusterRole、ClusterRoleBinding 资源,因为删除了 autoscaleMin
,所以不会产生 HPA 对象,同时服务类型也改成了 NodePort。
仔细看看会发现其中有一些问题:
Pilot、Statsd 等依赖服务的地址还在本命名空间,没有引用
istio-system
中的服务。ClusterRoleBinding 引用的 ServiceAccount 还是指向了
istio-system
中的 ServiceAccount,但是很明显,这是不存在的。
这两点结合起来,足够给这个 Gateway 控制器判了死刑,是不可能正常工作的。如果用这一个文件安装 Istio,这个 Gateway 对应的 Pod 日志一定会出现错误。要修正错误,有三个方式:
不再定义
namespace
。修正 Chart。
修改渲染后的 YAML 文件。
所以这里妥协一下,删掉 namespace
一行,使用缺省设置,重新渲染安装。
安装完成以后,按照控制 Ingress 流量一文的介绍,安装 httpbin
服务,并为其设置 Gateway 和 VirtualService(注意替换其中的域名),其中的 Gateway Selector 使用我们新建的网关 myingress
:
apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: httpbin-gateway spec: selector: istio: myingress servers: - port: number: 80 name: http protocol: HTTP hosts: - "httpbin.example.rocks" --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: httpbin spec: hosts: - "httpbin.example.rocks" gateways: - httpbin-gateway http: route: - destination: port: number: 8000 host: httpbin
创建这两个资源之后,使用 curl 访问 Ingress 服务,会看到正确的结果返回,例如:
$ curl httpbin.example.rocks/ip { "origin": "10.232.0.37"}
再来一次
前面的测试我们模拟了从头部署 Istio 的方式,如果是一个现存的 Istio 部署,又应该怎样新建网关?
根据前面的分析,可以得出引用的所有全局变量:
priorityClassName
hub
tag
istioNamespace
proxy
controlPlaneSecurityEnabled
defaultResources
nodeaffinity
imagePullSecrets
如果保证这些变量的完整性,并且和正在运行的 Istio 一致;同时关掉其它的不必要的组件渲染,应该就可以达到效果。这样写一个 values.yaml
:
global: hub: docker.io/istio tag: 1.0.2 proxy: envoyStatsd: enabled: true host: istio-statsd-prom-bridge port: 9125 imagePullPolicy: IfNotPresent controlPlaneSecurityEnabled: false imagePullSecrets: # - private-registry-key defaultResources: requests: cpu: 10m priorityClassName: "" sidecarInjectorWebhook: enabled: false security: enabled: false ingress: enabled: false mixer: enabled: false pilot: enabled: false grafana: enabled: false prometheus: enabled: false servicegraph: enabled: false tracing: enabled: false galley: enabled: false kiali: enabled: false certmanager: enabled: false gateways: enabled: true istio-ingressgateway: enabled: false istio-egressgateway: enabled: false istio-newingress: enabled: true labels: app: istio-ingressgateway istio: newingress replicaCount: 1 # autoscaleMin: 1 autoscaleMax: 5 resources: {} cpu: targetAverageUtilization: 80 loadBalancerIP: "" serviceAnnotations: {} type: LoadBalancer ports: - port: 80 targetPort: 80 name: http-newingress
重新渲染并执行。
修改 httpbin Gateway 定义,将 Selector 变更为 istio: newingress
,提交后使用 CURL 进行验证,会发现新的 Gateway 已经生效。
小结
目前的 Gateway 管理还无法让人满意,多命名空间或者按需调度方面的功能还有很大缺憾;但是借用 Helm Chart 进行大块功能管理的方式还是一个有趣而且可能有效的尝试。