<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>gateways | 伪架构师</title>
    <link>/tags/gateways/</link>
      <atom:link href="/tags/gateways/index.xml" rel="self" type="application/rss+xml" />
    <description>gateways</description>
    <generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>zh</language><lastBuildDate>Sun, 14 Oct 2018 00:06:31 +0800</lastBuildDate>
    <image>
      <url>/img/logo-wide.png</url>
      <title>gateways</title>
      <link>/tags/gateways/</link>
    </image>
    
    <item>
      <title>Istio Helm Chart 详解 - Gateways</title>
      <link>/post/istio-helm-deep-dive-gateways/</link>
      <pubDate>Sun, 14 Oct 2018 00:06:31 +0800</pubDate>
      <guid>/post/istio-helm-deep-dive-gateways/</guid>
      <description>

&lt;blockquote&gt;
&lt;p&gt;这是《Istio Helm Chart 详解》系列的第四篇，对 Gateways Chart 进行一些介绍，并讲解一下使用 Helm 创建 Istio Gateway 的方法。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;

&lt;p&gt;前面提到过，Istio 的 Helm Chart，除去用于安装之外，还有部分对 Istio 部署进行调整的能力。Gateways 一节内容，就包含了定制 Istio Ingress/Egress Gateway 的能力。&lt;/p&gt;

&lt;p&gt;这个 Chart 的文件结构和其他组件类似，不同的在于内容，它通过对 &lt;code&gt;values.yaml&lt;/code&gt; 中定义的 Gateways 相关内容的循环遍历，生成不同的 Gateway 单元，下面将会进行讲解和试验。&lt;/p&gt;

&lt;h2 id=&#34;values-yaml-中的变量定义&#34;&gt;&lt;code&gt;values.yaml&lt;/code&gt; 中的变量定义&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;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: &amp;quot;&amp;quot;
    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
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;其中包含了一个层次结构：Gateways 的下级除了用于 &lt;code&gt;requirements.yaml&lt;/code&gt; 使用的 &lt;code&gt;enabled&lt;/code&gt; 字段之外，还包含一个数组，数组的每个元素定义了一个网关。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;range $key, $spec := .Values&lt;/code&gt;：对 &lt;code&gt;gateways&lt;/code&gt; 一节的&lt;strong&gt;局部变量&lt;/strong&gt;进行遍历，第一层遍历的值用 &lt;code&gt;$key&lt;/code&gt; 和 &lt;code&gt;$spec&lt;/code&gt; 两个变量来表示键值对，根据每个键值对的定义，逐个创建资源，下面会提到的 &lt;code&gt;$spec&lt;/code&gt; 引用就是相当于每个网关控制器的定义变量，&lt;code&gt;$key&lt;/code&gt; 就是每个网关控制器的名称。&lt;/p&gt;

&lt;h2 id=&#34;chart-yaml&#34;&gt;Chart.yaml&lt;/h2&gt;

&lt;p&gt;元数据文件，无需赘述。&lt;/p&gt;

&lt;h2 id=&#34;autoscale-yaml&#34;&gt;autoscale.yaml&lt;/h2&gt;

&lt;p&gt;首先讲解一下头部的渲染条件：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;{{- range $key, $spec := .Values }}
{{- if and (ne $key &amp;quot;global&amp;quot;) (ne $key &amp;quot;enabled&amp;quot;) }}
{{- 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 }}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;顾名思义，这个文件是用来创建 &lt;a href=&#34;https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/&#34; target=&#34;_blank&#34;&gt;HPA&lt;/a&gt; 的，但是整个文件的外层由一个 &lt;a href=&#34;https://docs.helm.sh/chart_template_guide/#looping-with-the-range-action&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;range&lt;/code&gt;&lt;/a&gt; 语句所包围：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;{{- if and (ne $key &amp;quot;global&amp;quot;) (ne $key &amp;quot;enabled&amp;quot;) }}&lt;/code&gt; 将会跳过 &lt;code&gt;global&lt;/code&gt; 和 &lt;code&gt;enabled&lt;/code&gt; 键。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{{- if and $spec.enabled $spec.autoscaleMin }}&lt;/code&gt;：如果前面读到的 &lt;code&gt;$spec&lt;/code&gt; 变量中的 &lt;code&gt;enabled&lt;/code&gt; 和 &lt;code&gt;autoscaleMin&lt;/code&gt; 都是 &lt;code&gt;true&lt;/code&gt;，才会进行处理。这里条件跟其它几个文件不同：只有设置了 &lt;code&gt;autoscaleMin&lt;/code&gt; 的情况下才会渲染 HPA 对象。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;引用变量：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$key&lt;/code&gt;：也就是网关的名称，例如前面的 &lt;code&gt;istio-ingressgateway&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$spec.namespace&lt;/code&gt;：可以为这一 Gateway 定义命名空间，如果没有定义，则沿用 Istio 的命名空间，也就是 &lt;code&gt;Release.Namespace&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$spec.autoscaleMax&lt;/code&gt; 和 &lt;code&gt;$spec.autoscaleMin&lt;/code&gt;，Gateway 伸缩的上下限。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cpu.targetAverageUtilization&lt;/code&gt;：伸缩指标，目标平均 CPU 占用率。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;rbac-资源&#34;&gt;RBAC 资源&lt;/h2&gt;

&lt;p&gt;同样的，这里定义了每个网关所对应的 &lt;code&gt;ServiceAccount&lt;/code&gt;、&lt;code&gt;ClusterRole&lt;/code&gt; 以及 &lt;code&gt;ClusterRoleBinding&lt;/code&gt;，用于 RBAC。&lt;/p&gt;

&lt;p&gt;Gateway 角色需要对 &lt;code&gt;thirdpartyresources&lt;/code&gt;、&lt;code&gt;virtualservices&lt;/code&gt;、&lt;code&gt;destinationrules&lt;/code&gt; 以及 &lt;code&gt;gateways&lt;/code&gt; 几种资源进行读写。&lt;/p&gt;

&lt;p&gt;看 &lt;code&gt;meta.name&lt;/code&gt; 的定义可以看出，每个网关都会有自己的 RBAC 资源，命名规则为 &lt;code&gt;[网关名称]-[Istio 所在的命名空间]&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;另外 ServiceAccount 中引用了全局变量 &lt;code&gt;imagePullSecrets&lt;/code&gt;。&lt;/p&gt;

&lt;h2 id=&#34;deployment-yaml&#34;&gt;&lt;code&gt;deployment.yaml&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;这个模板用于 &lt;code&gt;Deployment&lt;/code&gt; 的创建过程。这个部署运行的主要服务进程和 Ingress Chart 一样，是 &lt;a href=&#34;https://istio.io/docs/reference/commands/pilot-agent/&#34; target=&#34;_blank&#34;&gt;pilot-agent&lt;/a&gt;。&lt;/p&gt;

&lt;h3 id=&#34;全局变量&#34;&gt;全局变量&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;priorityClassName&lt;/li&gt;
&lt;li&gt;hub&lt;/li&gt;
&lt;li&gt;tag&lt;/li&gt;
&lt;li&gt;istioNamespace&lt;/li&gt;
&lt;li&gt;proxy.envoyStatsd&lt;/li&gt;
&lt;li&gt;controlPlaneSecurityEnabled&lt;/li&gt;
&lt;li&gt;defaultResources&lt;/li&gt;
&lt;li&gt;nodeaffinity&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;变量使用细节&#34;&gt;变量使用细节&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$spec.labels&lt;/code&gt;：这里可以看出，我们可以使用在 &lt;code&gt;values.yaml&lt;/code&gt; 中定义标签 &lt;code&gt;labels&lt;/code&gt; 的方式，为新的 Deployment 指定标签。&lt;strong&gt;标签将同时出现在 Deployment 和下面的 Pod 中。&lt;/strong&gt;，从而定义 &lt;code&gt;Gateway&lt;/code&gt; 资源时，可以用标签来指定对应的控制器。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$spec.replicaCount&lt;/code&gt;：可以指定初始副本数量。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$spec.ports&lt;/code&gt;：在 &lt;code&gt;ports&lt;/code&gt; 中定义的各种端口，会在容器中进行发布。&lt;/li&gt;
&lt;li&gt;Gateway 名称在这里还作为 &lt;code&gt;--serviceCluster&lt;/code&gt; 的值，这一参数在 Sidecar 中一般取值为 &lt;code&gt;istio-proxy&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;如果定义了 &lt;code&gt;global.istioNamespace&lt;/code&gt;，会使用 &lt;code&gt;[服务名].[命名空间]&lt;/code&gt; 的方式定义 &lt;code&gt;zipkin&lt;/code&gt;、&lt;code&gt;istio-pilot&lt;/code&gt; 的服务地址。&lt;/li&gt;
&lt;li&gt;根据 &lt;code&gt;global.proxy.envoyStatsd&lt;/code&gt; 设置 &lt;code&gt;statsd&lt;/code&gt; 地址。&lt;/li&gt;
&lt;li&gt;如果 Gateway 定义中包含了资源限制的内容，则会在这里进行包含，否则只会使用缺省资源限制。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$spec.additionalContainers&lt;/code&gt; 中还可以定义该 Pod 中额外的容器。&lt;/li&gt;
&lt;li&gt;如果有加载额外 tls secret 的需求，可以定义在 &lt;code&gt;$spec.secretVolume&lt;/code&gt; 中。&lt;/li&gt;
&lt;li&gt;如果有加载额外 Configmap 的需求，可以定义在 &lt;code&gt;$spec.configVolumes&lt;/code&gt; 中。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;service-yaml&#34;&gt;service.yaml&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;和其他元素一样，Service 也是使用循环的方式逐个建立的。&lt;/li&gt;
&lt;li&gt;服务名称同样也是直接使用 &lt;code&gt;$key&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;端口、命名空间、标签和 Deployment 模板一致。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$spec.serviceAnnotations&lt;/code&gt; 用于生成服务注解。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;selector&lt;/code&gt; 的定义&lt;strong&gt;也和标签定义一致&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;如果定义了 &lt;code&gt;$spec.loadBalancerIP&lt;/code&gt;，这里会给服务的 &lt;code&gt;loadBalancerIP&lt;/code&gt; 赋值。&lt;/li&gt;
&lt;li&gt;如果定义了 &lt;code&gt;.type&lt;/code&gt;，则将服务类型进行修改。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;测试一下&#34;&gt;测试一下&lt;/h2&gt;

&lt;p&gt;在 &lt;code&gt;values.yaml&lt;/code&gt; 的 &lt;code&gt;gateways&lt;/code&gt; 一节加入这样一段：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;  istio-myingress:
    enabled: true
    namespace: default
    labels:
      app: istio-ingressgateway
      istio: myingress
    replicaCount: 1
    autoscaleMax: 5
    resources: {}
    cpu:
      targetAverageUtilization: 80
    loadBalancerIP: &amp;quot;&amp;quot;
    serviceAnnotations: {}
    type: NodePort
    ports:
    - port: 80
      targetPort: 80
      name: http-myingress
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;然后用命令行生成对应的安装文件：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ helm template istio --name istio -f \
    values-new-gateway.yaml --namespace \
    istio-system &amp;gt; istio-myingress.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;生成的 yaml，用编辑器打开，使用正则表达式 &lt;code&gt;source:.*?gateways&lt;/code&gt; 进行搜索，会看到生成的内容符合之前的描述，在 &lt;code&gt;Default&lt;/code&gt; 命名空间中出现了新的 ServiceAccount、ClusterRole、ClusterRoleBinding 资源，因为删除了 &lt;code&gt;autoscaleMin&lt;/code&gt;，所以不会产生 HPA 对象，同时服务类型也改成了 NodePort。&lt;/p&gt;

&lt;p&gt;仔细看看会发现其中有一些问题：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pilot、Statsd 等依赖服务的地址还在本命名空间，没有引用 &lt;code&gt;istio-system&lt;/code&gt; 中的服务。&lt;/li&gt;
&lt;li&gt;ClusterRoleBinding 引用的 ServiceAccount 还是指向了 &lt;code&gt;istio-system&lt;/code&gt; 中的 ServiceAccount，但是很明显，这是不存在的。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这两点结合起来，足够给这个 Gateway 控制器判了死刑，是不可能正常工作的。如果用这一个文件安装 Istio，这个 Gateway 对应的 Pod 日志一定会出现错误。要修正错误，有三个方式：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;不再定义 &lt;code&gt;namespace&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;修正 Chart。&lt;/li&gt;
&lt;li&gt;修改渲染后的 YAML 文件。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;所以这里妥协一下，删掉 &lt;code&gt;namespace&lt;/code&gt; 一行，使用缺省设置，重新渲染安装。&lt;/p&gt;

&lt;p&gt;安装完成以后，按照&lt;a href=&#34;https://preliminary.istio.io/zh/docs/tasks/traffic-management/ingress/&#34; target=&#34;_blank&#34;&gt;控制 Ingress 流量&lt;/a&gt;一文的介绍，安装 &lt;code&gt;httpbin&lt;/code&gt; 服务，并为其设置 Gateway 和 VirtualService（注意替换其中的域名），其中的 Gateway Selector 使用我们新建的网关 &lt;code&gt;myingress&lt;/code&gt;：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: httpbin-gateway
spec:
  selector:
    istio: myingress
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - &amp;quot;httpbin.example.rocks&amp;quot;
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: httpbin
spec:
  hosts:
  - &amp;quot;httpbin.example.rocks&amp;quot;
  gateways:
  - httpbin-gateway
  http:
    route:
    - destination:
        port:
          number: 8000
        host: httpbin
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;创建这两个资源之后，使用 curl 访问 Ingress 服务，会看到正确的结果返回，例如：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ curl httpbin.example.rocks/ip
{
  &amp;quot;origin&amp;quot;: &amp;quot;10.232.0.37&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;再来一次&#34;&gt;再来一次&lt;/h2&gt;

&lt;p&gt;前面的测试我们模拟了从头部署 Istio 的方式，如果是一个现存的 Istio 部署，又应该怎样新建网关？&lt;/p&gt;

&lt;p&gt;根据前面的分析，可以得出引用的所有全局变量：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;priorityClassName&lt;/li&gt;
&lt;li&gt;hub&lt;/li&gt;
&lt;li&gt;tag&lt;/li&gt;
&lt;li&gt;istioNamespace&lt;/li&gt;
&lt;li&gt;proxy&lt;/li&gt;
&lt;li&gt;controlPlaneSecurityEnabled&lt;/li&gt;
&lt;li&gt;defaultResources&lt;/li&gt;
&lt;li&gt;nodeaffinity&lt;/li&gt;
&lt;li&gt;imagePullSecrets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;如果保证这些变量的完整性，并且和正在运行的 Istio 一致；同时关掉其它的不必要的组件渲染，应该就可以达到效果。这样写一个 &lt;code&gt;values.yaml&lt;/code&gt;：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;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: &amp;quot;&amp;quot;
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: &amp;quot;&amp;quot;
    serviceAnnotations: {}
    type: LoadBalancer
    ports:
    - port: 80
      targetPort: 80
      name: http-newingress
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;重新渲染并执行。&lt;/p&gt;

&lt;p&gt;修改 httpbin Gateway 定义，将 Selector 变更为 &lt;code&gt;istio: newingress&lt;/code&gt;，提交后使用 CURL 进行验证，会发现新的 Gateway 已经生效。&lt;/p&gt;

&lt;h2 id=&#34;小结&#34;&gt;小结&lt;/h2&gt;

&lt;p&gt;目前的 Gateway 管理还无法让人满意，多命名空间或者按需调度方面的功能还有很大缺憾；但是借用 Helm Chart 进行大块功能管理的方式还是一个有趣而且可能有效的尝试。&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
