在生产环境运行Istio(一)

在生产环境运行Istio(一)

原文地址 https://medium.com/avitotech/running-istio-on-kubernetes-in-production-part-i-a8bbf7fec18e

Istio 是什么?Istio 是服务网格技术,在网络上添加一层抽象层。它截获 Kubernetes 集群里的所有或者部分流量,并在之上执行一系列操作。支持哪些操作呢?比如,搭建智能路由或实现断路器方案,进行“金丝雀部署”等。另外,Istio 还可以限制外部交互并且控制集群和外部网络的所有路由。而且,Istio 支持配置策略规则来控制不同微服务之间的交互。最终,我们可以生成完整的网络交互图,并且得到对于应用来说完全透明的指标集。

官方文档里有 Istio 的详细介绍。本文介绍 Istio 上微服务交互背后的基本原理,展示 Istio 的确是解决各种问题的相当强大的工具。本文尝试回答 Istio 初学者经常会问的各种问题,帮助大家更有效率地使用 Istio。

在介绍安装之前,先介绍一些核心观点,总体看一下 Istio 的组件和组件间交互的原理。

工作原理

Istio 由两大组件组成——控制面板和数据面板。控制面板包含基础组件,确保和其他组件之间的正确交互。在当前的 1.0 版本里,控制面板有三个组件:Pilot,Mixer 和 Citadel。这里不讨论 Citadel,因为在生成证书来进行服务间的双向 TLS 通信时才需要它。我们先了解一下 Pilot 和 Mixer 的设计和目标。

控制面板和数据面板

Pilot 是主要的控制组件,它负责分发集群内的所有信息——服务,它们的端点以及路由规则(比如,金丝雀发布规则或者断流器规则)。

Mixer 是可选的控制面板组件,它负责收集指标、日志以及其他网络交互的信息。它还监控是否符合策略规则以及是否符合速率限制。

数据面板的组件使用 sidecar 代理容器来实现。默认使用强大的代理服务器 Envoy。为了确保 Istio 对于应用来说是彻底透明的,这里使用了自动注入系统。最新的实现支持 Kubernetes 1.9 或更新版本(mutational admission webhook)。对于 Kubernetes 1.7,1.8 版本,可以是用 Initializer。

Sidecar 容器通过 GRPC 协议连接 Pilot,优化集群内变更的 pushdown 模型。Envoy 从 1.6 版本就开始使用 GRPC;Istio 则从 0.8 版本开始使用,它是 pilot-agent——Envoy 之上 GO 的封装,用来配置启动参数。

Pilot 和 Mixer 是纯粹的无状态组件,所有的状态都保存在应用程序的内存里。它们的配置由 Kubernetes 的 Custom Resource 定义,存储在 etcd 里。Istio-agent 得到 Pilot 的地址,并打开 GRPC 连接。

正如我所说,Istio 在对应用完全透明的前提下实现了所有功能。让我们一起看看是怎么实现的。算法原理如下:

  1. 我们部署服务的一个新版本。

  2. 取决于 sidecar 容器的注入类型,在配置阶段添加 istio-init 容器和 istio-agent 容器(Envoy),或者手动插入到 Kubernetes 实体的 Pod 描述里。

  3. istio-init 容器是一些脚本,为 Pod 设置 iptables 规则。有两种方式配置流量重定向到 istio-agent 容器里:使用直接的 iptables 规则或者 TPROXY。撰写本文时,默认使用的是重定向规则。在 istio-init 里,可以配置截获哪些流量并发送给 istio-agent。比如,为了截获所有入站和出站流量,用户需要将参数 -i-b 设置为 *。用户也可以指定截获特定端口的流量。为了避免截获特定子网的流量,可以使用 -x 参数。

  4. 在 init 运行后,会启动容器,包括 pilot-agent(Envoy)。它通过 GRPC 连接上已经部署的 Pilot,得到集群内所有已有服务以及路由策略的信息。根据接收到的数据,它配置集群,将这些流量直接映射到 Kubernetes 集群里的应用程序端口。重要的地方是:Envoy 动态配置监听器(IP,端口对)开始监听。因此,当请求进入 Pod,并且使用 iptables 规则重定向到 sidecar 时,Envoy 已经准备好处理这些连接,并且知道将这些代理流量转发到哪里去。这一步里,信息发送给 Mixer,下文会详细介绍。

最终,我们得到 Envoy 代理 服务器 的所有网络,可以从一点(Pilot)完成配置。最终,所有 inbound 和 outbound 请求都会通过 Envoy。更为重要的是,只截获 TCP 流量。这意味着仍旧是使用 UDP 上的 kube-dns 来解析 Kubernetes 服务 IP,这点没有变化。然后,在 resolver 之后,outbound 请求被 envoy 截获并处理,它决定请求发送到哪个端点(或者不发送,当访问策略禁止或者触发了断流算法时)。

现在我们已经熟悉了 Pilot,接下来研究 Mixer 是怎么工作的,以及为什么我们需要 Mixer。Mixer 的官方文档在这里

Mixer 有两个组件:istio-telemetry,isito-policy(0.8 版本之前使用单个组件 istio-mixer)。它们都是 Mixer。Istio telemetry 接收 sidecar 容器的 GPRC,并且汇报服务交互和参数信息。Istio-policy 接收到检查请求,确保满足 Policy 规则。这些策略检查在客户端(sidecar 里)缓存一段时间。报告检查是批量发送的。这里介绍怎么配置以及需要设置哪些参数。

Mixer 应该是高可用组件,提供 telemetry 数据的不间断收集和处理。整个系统是一个多层缓存器。最初,数据缓存在容器的 sidecar 里,然后在 Mixer,最终发送到 Mixer 后台。因此,如果任意系统组件发生故障,buffer 会增长,之后当系统恢复时,会 flush。Mixer 后台是发送 telemetry 数据的端点:statsd,newrelic 等等。编写自定义后台很简单,之后我会给大家介绍。

Mixer Topology

总结一下,使用 istio-telemetry 的工作流如下:

  1. 服务 1 发送请求给服务 2

  2. 在已有的服务 1 里,请求重定向到 sidecar

  3. Sidecar Envoy 监控到给服务 2 的请求,并准备所需信息

  4. 然后它使用 Report 请求发送给 istio-telemetry。

  5. Istio-telemetry 决定是否将 Report 发送给后台,这里也负责发送请求以及请求内容。

现在看看如何搭建包含两大基础组件 Pilot 和 sidecar envoy 的 Istio 系统。如下是 Pilot 读取的基础配置(Mesh):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
apiVersion: v1
kind: ConfigMap
metadata:
  name: istio
  namespace: istio-system
  labels:
    app: istio
    service: istio
data:
  mesh: |-# disable tracing mechanism for now
    enableTracing: false# do not specify mixer endpoints, so that sidecar containers do not send the information
    #mixerCheckServer: istio-policy.istio-system:15004
    #mixerReportServer: istio-telemetry.istio-system:15004# interval for envoy to check Pilot
    rdsRefreshDelay: 5s# default config for envoy sidecar
    defaultConfig:
      # like rdsRefreshDelay
      discoveryRefreshDelay: 5s# path to envoy executable
      configPath: "/etc/istio/proxy"
      binaryPath: "/usr/local/bin/envoy"# default name for sidecar container
      serviceCluster: istio-proxy# time for envoy to wait before it shuts down all existing connections
      drainDuration: 45s
      parentShutdownDuration: 1m0s# by default, REDIRECT rule for iptables is used. TPROXY can be used as well.
      #interceptionMode: REDIRECT# port for sidecar container admin panel
      proxyAdminPort: 15000# address for sending traces using zipkin protocol (not used as turned off in enableTracing option)
      zipkinAddress: tracing-collector.tracing:9411# statsd address for envoy containers metrics
      # statsdUdpAddress: aggregator:8126# turn off Mutual TLS
      controlPlaneAuthPolicy: NONE# istio-pilot listen port to report service discovery information to sidecars
      discoveryAddress: istio-pilot.istio-system:15007

让我们将所有主要控制组件(控制面板)放到 Kubernetes 的 istio-system 命名空间里。

最小的配置仅仅要求 Pilot 的部署。我们使用如下配置。并且手动配置 sidecar 容器的注入。

Init 容器配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
initContainers:
  - name: istio-init
    args:
      - -p
      - "15001"
      - -u
      - "1337"
      - -m
      - REDIRECT
      - -i
      - "*"
      - -b
      - "*"
      - -d
      - ""
    image: istio/proxy_init:1.0.0
    imagePullPolicy: IfNotPresent
    resources:
      limits:
        memory: 128Mi
    securityContext:
      capabilities:
        add:
          - NET_ADMIN

Sidecar 配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
- name: istio-proxy
  command:
    - "bash"
    - "-c"
    - |
      exec /usr/local/bin/pilot-agent proxy sidecar \
      --configPath \
      /etc/istio/proxy \
      --binaryPath \
      /usr/local/bin/envoy \
      --serviceCluster \
      service-name \
      --drainDuration \
      45s \
      --parentShutdownDuration \
      1m0s \
      --discoveryAddress \
      istio-pilot.istio-system:15007 \
      --discoveryRefreshDelay \
      1s \
      --connectTimeout \
      10s \
      --proxyAdminPort \
      "15000" \
      --controlPlaneAuthPolicy \
      NONE
  env:
    - name: POD_NAME
      valueFrom:
        fieldRef:
          fieldPath: metadata.name
    - name: POD_NAMESPACE
      valueFrom:
        fieldRef:
          fieldPath: metadata.namespace
    - name: INSTANCE_IP
      valueFrom:
        fieldRef:
          fieldPath: status.podIP
    - name: ISTIO_META_POD_NAME
      valueFrom:
        fieldRef:
          fieldPath: metadata.name
    - name: ISTIO_META_INTERCEPTION_MODE
      value: REDIRECT
  image: istio/proxyv2:1.0.0
  imagePullPolicy: IfNotPresent
  resources:
    requests:
      cpu: 100m
      memory: 128Mi
    limits:
      memory: 2048Mi
  securityContext:
    privileged: false
    readOnlyRootFilesystem: true
    runAsUser: 1337
  volumeMounts:
    - mountPath: /etc/istio/proxy
      name: istio-envoy

为了成功部署,需要为 Pilot 创建 ServiceAccount,ClusterRole,ClusterRoleBinding,CRD;更多详细信息在这里。之后,带有注入的 sidecar 和 Envoy 的服务就启动了,会从 Pilot 获取所有数据并且处理请求。

最重要的一点是所有控制面板组件都是无状态的应用程序,都可以轻松地水平扩展。所有数据都以 Kubernetes 资源的自定义描述存储在 etcd 里。

此外,也可以在集群外运行 Istio(实验用途),并且在几个 Kubernetes 集群之间监控并共享服务发现。更多的相关信息在这里。在多集群安装里,要考虑到如下限制:

  1. CIDR Pod 和 Service CIDR 必须在所有集群里都是唯一的,不能重叠。

  2. 集群间的任意 Pod CIDR 必须能够访问所有 CIDR Pod。

  3. 所有 Kubernetes API server 都必须能够相互访问。

本文让你开始了解 Istio。但是,后续文章会接着讨论现有的问题。我们会讨论外部流量路由的特性,探讨最常见的 sidecar debug 和 Profile 的方法。最终,我们会创建跟踪系统并且仔细介绍它和 Envoy 是如何交互的。

Rating: