此篇博文istio相关介绍和测试用例来源于网络,这里结合自己配置加以整理。

istio 介绍

官方中文参考文档

官方英文参考文档

服务网格(Service Mesh)这个术语通常用于描述构成这些应用程序的微服务网络以及应用之间的交互。随着规模和复杂性的增长,服务网格越来越难以理解和管理。它的需求包括服务发现、负载均衡、故障恢复、指标收集和监控以及通常更加复杂的运维需求,例如 A/B 测试、金丝雀发布、限流、访问控制和端到端认证等。

Istio 提供了一个完整的解决方案,通过为整个服务网格提供行为洞察和操作控制来满足微服务应用程序的多样化需求。

使用istio的目标

Istio 提供一种简单的方式来为已部署的服务建立网络,该网络具有负载均衡、服务间认证、监控等功能,只需要对服务的代码进行一点或不需要做任何改动。想要让服务支持 Istio,只需要在您的环境中部署一个特殊的 sidecar 代理,使用 Istio 控制平面功能配置和管理代理,拦截微服务之间的所有网络通信:

  • HTTP、gRPC、WebSocket 和 TCP 流量的自动负载均衡。

  • 通过丰富的路由规则、重试、故障转移和故障注入,可以对流量行为进行细粒度控制。

  • 可插入的策略层和配置 API,支持访问控制、速率限制和配额。

  • 对出入集群入口和出口中所有流量的自动度量指标、日志记录和跟踪。

  • 通过强大的基于身份的验证和授权,在集群中实现安全的服务间通信。

Istio 旨在实现可扩展性,满足各种部署需求。

istio的核心功能

流量管理: 通过简单的规则配置和流量路由,您可以控制服务之间的流量和 API 调用。
通信安全: Istio 的安全功能使开发人员可以专注于应用程序级别的安全性。Istio 提供底层安全通信信道,并大规模管理服务通信的认证、授权和加密。
监控功能: 通过 Istio 的监控功能,可以真正了解服务性能如何影响上游和下游的功能,而其自定义仪表板可以提供对所有服务性能的可视性,并让您了解该性能如何影响您的其他进程。
跨平台: Istio 是独立于平台的,旨在运行在各种环境中,包括跨云、内部部署、Kubernetes、Mesos 等。
集成和定制: 策略执行组件可以扩展和定制,以便与现有的 ACL、日志、监控、配额、审计等方案集成。

系统架构

Istio 服务网格逻辑上分为数据平面和控制平面。

  • 数据平面由一组以 sidecar 方式部署的智能代理(Envoy)组成。这些代理可以调节和控制微服务及 Mixer 之间所有的网络通信。

  • 控制平面负责管理和配置代理来路由流量。此外控制平面配置 Mixer 以实施策略和收集遥测数据。
    image

组件介绍

Istio 使用 Envoy 代理的扩展版本,Envoy 是以 C++ 开发的高性能代理,用于调解服务网格中所有服务的所有入站和出站流量。Envoy 的许多内置功能被 istio 发扬光大,例如:

  • 动态服务发现
  • 负载均衡
  • TLS 终止
  • HTTP/2 & gRPC 代理
  • 熔断器
  • 健康检查、基于百分比流量拆分的灰度发布
  • 故障注入
  • 丰富的度量指标

Envoy 被部署为 sidecar,和对应服务在同一个 Kubernetes pod 中。

Mixer 是一个独立于平台的组件,负责在服务网格上执行访问控制和使用策略,并从 Envoy 代理和其他服务收集遥测数据。代理提取请求级属性,发送到 Mixer 进行评估。

Pilot 为 Envoy sidecar 提供服务发现功能,为智能路由(例如 A/B 测试、金丝雀部署等)和弹性(超时、重试、熔断器等)提供流量管理功能。它将控制流量行为的高级路由规则转换为特定于 Envoy 的配置,并在运行时将它们传播到 sidecar。

Citadel 通过内置身份和凭证管理可以提供强大的服务间和最终用户身份验证。可用于升级服务网格中未加密的流量,并为运维人员提供基于服务标识而不是网络控制的强制执行策略的能力。从 0.5 版本开始,Istio 支持基于角色的访问控制,以控制谁可以访问您的服务。

Galley 代表其他的 Istio 控制平面组件,用来验证用户编写的 Istio API 配置。随着时间的推移,Galley 将接管 Istio 获取配置、 处理和分配组件的顶级责任。它将负责将其他的 Istio 组件与从底层平台(例如 Kubernetes)获取用户配置的细节中隔离开来。

Istio 部署

提示:在Minikube中运行需要至少8G内存和4核CPU。

参考文档:https://thenewstack.io/tutorial-blue-green-deployments-with-kubernetes-and-istio

0. 确认K8S环境配置

如果要成功部署istio,需要给kube-apiserver添加MutatingAdmissionWebhook,ValidatingAdmissionWebhook的参数,成功运行istio的kube-apiserver配置如下:

[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target

[Service]
ExecStart=/opt/kubernetes/bin/kube-apiserver \
  --enable-admission-plugins=MutatingAdmissionWebhook,ValidatingAdmissionWebhook,NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota,NodeRestriction \
  --bind-address=192.168.20.31 \
  --insecure-bind-address=127.0.0.1 \
  --authorization-mode=Node,RBAC \
  --runtime-config=rbac.authorization.k8s.io/v1 \
  --kubelet-https=true \
  --anonymous-auth=false \
  --basic-auth-file=/opt/kubernetes/ssl/basic-auth.csv \
  --enable-bootstrap-token-auth \
  --token-auth-file=/opt/kubernetes/ssl/bootstrap-token.csv \
  --service-cluster-ip-range=10.1.0.0/16 \
  --service-node-port-range=20000-40000 \
  --tls-cert-file=/opt/kubernetes/ssl/kubernetes.pem \
  --tls-private-key-file=/opt/kubernetes/ssl/kubernetes-key.pem \
  --client-ca-file=/opt/kubernetes/ssl/ca.pem \
  --service-account-key-file=/opt/kubernetes/ssl/ca-key.pem \
  --requestheader-client-ca-file=/opt/kubernetes/ssl/ca.pem \
  --requestheader-allowed-names= \
  --requestheader-extra-headers-prefix="X-Remote-Extra-" \
  --requestheader-group-headers=X-Remote-Group \
  --requestheader-username-headers=X-Remote-User \
  --proxy-client-cert-file=/opt/kubernetes/ssl/metrics-server.pem \
  --proxy-client-key-file=/opt/kubernetes/ssl/metrics-server-key.pem \
  --enable-aggregator-routing=true \
  --runtime-config=api/all=true  \
  --etcd-servers=http://192.168.20.31:2379,http://192.168.20.32:2379,http://192.168.20.33:2379 \
  --enable-swagger-ui=true \
  --allow-privileged=true \
  --audit-log-maxage=30 \
  --audit-log-maxbackup=3 \
  --audit-log-maxsize=100 \
  --audit-log-path=/opt/kubernetes/log/api-audit.log \
  --event-ttl=1h \
  --v=2 \
  --logtostderr=false \
  --log-dir=/opt/kubernetes/log
Restart=on-failure
RestartSec=5
Type=notify
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

确认Metrics Server成功安装,并正常运行:

# kubectl  get apiservices |grep metrics-server
v1beta1.metrics.k8s.io                  kube-system/metrics-server   True        5d

# kubectl get apiservices v1beta1.metrics.k8s.io -o yaml

apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
  creationTimestamp: 2018-11-07T06:23:17Z
  name: v1beta1.metrics.k8s.io
  resourceVersion: "747856"
  selfLink: /apis/apiregistration.k8s.io/v1/apiservices/v1beta1.metrics.k8s.io
  uid: 9d638462-e255-11e8-a817-000c29550ccc
spec:
  group: metrics.k8s.io
  groupPriorityMinimum: 100
  insecureSkipTLSVerify: true
  service:
    name: metrics-server
    namespace: kube-system
  version: v1beta1
  versionPriority: 100
status:
  conditions:
  - lastTransitionTime: 2018-11-12T09:21:46Z
    message: all checks passed
    reason: Passed
    status: "True"
    type: Available

# kubectl  top node                 # k8s 1.12版本默认会使用metrics api
NAME            CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
192.168.20.32   580m         28%    2263Mi          61%       
192.168.20.33   381m         19%    2317Mi          63% 

1.下载istio

执行如下命令,会下载安装包并自动解压缩:

curl -L https://git.io/getLatestIstio | sh -

进入 Istio 包目录。例如,假设这个包是 istio-1.1.0.0:

cd istio-1.1.0

安装目录中包含:

  • 在 install/ 目录中包含了 Kubernetes 安装所需的 .yaml 文件
  • samples/ 目录中是示例应用
  • istioctl 客户端文件保存在 bin/ 目录之中。istioctl 的功能是手工进行 Envoy Sidecar 的注入,以及对路由规则、策略的管理
  • istio.VERSION 配置文件

添加bin目录到系统的环境变量,或者将bin/istioctl文件拷贝到/usr/bin ,这样在使用istioctl命令时就更加方便了:

export PATH=$PWD/bin:$PATH

2. 安装istio

安装istio的自定义资源(CRD):

kubectl apply -f install/kubernetes/helm/istio/templates/crds.yaml

由于是在没有Rancher和云供应商的环境中安装istio,没有LoadBalancer的支持,所以我们需要将istio-1.0.3/install/kubernetes/istio-demo.yam 中的LoadBalancer关键字修改为 NodePort:

apiVersion: v1
kind: Service
metadata:
  name: istio-ingressgateway
  namespace: istio-system
  annotations:
  labels:
    chart: gateways-1.0.3
    release: istio
    heritage: Tiller
    app: istio-ingressgateway
    istio: ingressgateway
spec:
  type: LoadBalancer                # 将此处的LoadBalancer 修改为 NodePort
  selector:
    app: istio-ingressgateway
    istio: ingressgateway
  ports:
    -
      name: http2
      nodePort: 31380
      port: 80
      targetPort: 80
    -
      name: https
      nodePort: 31390
      port: 443

用如下命令安装不启用 Sidecar 间双向 TLS 认证的 Istio:

kubectl apply -f install/kubernetes/istio-demo.yaml

执行这个文件之后,我们会发现已经安装了多个服务和pod,并且创建了istio-system的命名空间:

[root@k8s-node-1 ~]# kubectl  get pod -n istio-system
NAME                                     READY   STATUS      RESTARTS   AGE
grafana-546d9997bb-2z8nj                 1/1     Running     0          4h4m
istio-citadel-6955bc9cb7-b4jm4           1/1     Running     0          4h4m
istio-cleanup-secrets-9rm4c              0/1     Completed   0          4h4m
istio-egressgateway-7dc5cbbc56-gccmr     1/1     Running     0          4h4m
istio-galley-545b6b8f5b-pwckj            1/1     Running     0          3h8m
istio-grafana-post-install-stm7q         0/1     Completed   0          4h4m
istio-ingressgateway-7958d776b5-kf4xf    1/1     Running     0          4h4m
istio-pilot-567dd97ddc-mnmhg             2/2     Running     0          4h4m
istio-policy-5c689f446f-82lbn            2/2     Running     0          4h4m
istio-policy-5c689f446f-jl4lh            2/2     Running     1          102m
istio-policy-5c689f446f-s4924            2/2     Running     0          3m14s
istio-security-post-install-cgqtr        0/1     Completed   0          4h4m
istio-sidecar-injector-99b476b7b-4twb2   1/1     Running     0          4h4m
istio-telemetry-55d68b5dfb-ftlbl         2/2     Running     0          4h4m
istio-telemetry-55d68b5dfb-l8xk6         2/2     Running     0          3h7m
istio-telemetry-55d68b5dfb-t5kdz         2/2     Running     1          3h8m
istio-telemetry-55d68b5dfb-zgljm         2/2     Running     0          3h8m
istio-telemetry-55d68b5dfb-zxg7q         2/2     Running     1          3h8m
istio-tracing-6445d6dbbf-92876           1/1     Running     0          4h4m
prometheus-65d6f6b6c-bpk8q               1/1     Running     1          4h4m
servicegraph-57c8cbc56f-f92rs            1/1     Running     17         4h4m

[root@k8s-node-1 ~]# kubectl  get svc -n istio-system
NAME                     TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)                                                                                                                   AGE
grafana                  NodePort    10.1.157.231   <none>        3000:28271/TCP                                                                                                            4h6m
istio-citadel            ClusterIP   10.1.103.109   <none>        8060/TCP,9093/TCP                                                                                                         4h6m
istio-egressgateway      ClusterIP   10.1.171.122   <none>        80/TCP,443/TCP                                                                                                            4h6m
istio-galley             ClusterIP   10.1.60.32     <none>        443/TCP,9093/TCP                                                                                                          4h6m
istio-ingressgateway     NodePort    10.1.105.144   <none>        80:31380/TCP,443:31390/TCP,31400:31400/TCP,15011:39182/TCP,8060:21878/TCP,853:35905/TCP,15030:22762/TCP,15031:20989/TCP   4h6m
istio-pilot              ClusterIP   10.1.28.6      <none>        15010/TCP,15011/TCP,8080/TCP,9093/TCP                                                                                     4h6m
istio-policy             ClusterIP   10.1.208.196   <none>        9091/TCP,15004/TCP,9093/TCP                                                                                               4h6m
istio-sidecar-injector   ClusterIP   10.1.31.204    <none>        443/TCP                                                                                                                   4h6m
istio-telemetry          ClusterIP   10.1.178.158   <none>        9091/TCP,15004/TCP,9093/TCP,42422/TCP                                                                                     4h6m
jaeger-agent             ClusterIP   None           <none>        5775/UDP,6831/UDP,6832/UDP                                                                                                4h6m
jaeger-collector         ClusterIP   10.1.63.111    <none>        14267/TCP,14268/TCP                                                                                                       4h6m
jaeger-query             ClusterIP   10.1.235.64    <none>        16686/TCP                                                                                                                 4h6m
prometheus               NodePort    10.1.235.55    <none>        9090:28729/TCP                                                                                                            4h6m
servicegraph             ClusterIP   10.1.30.255    <none>        8088/TCP                                                                                                                  4h6m
tracing                  ClusterIP   10.1.114.120   <none>        80/TCP                                                                                                                    4h6m
zipkin                   ClusterIP   10.1.212.242   <none>        9411/TCP                                                                                                                  4h6m

3.标记命名空间

为了对k8s中的各个命名空间进行监控和流量处理,需要对每个命名空间进行 Envoy 容器注入(确认Istio-sidecar-injector正常启动):

 kubectl label namespace <namespace> istio-injection=enabled

 EG:

 kubectl label namespace default istio-injection=enabled

如果要取消标记,使用如下命令:

 kubectl label namespace default istio-injection-

理解原理:
istio提供了缺省的配置,会在带有istio-injection=enabled标签的命名空间中选择pod,添加一个istio-proxy的容器,使用如下命令可以编辑目标命名空间的范围:

kubectl edit mutatingwebhookconfiguration istio-sidecar-injector

istio-system 命名空间中的 ConfigMap istio-sidecar-injector 中包含了缺省的注入策略以及 Sidecar 的注入模板。

有两种注入策略:
disabled: Sidecar 注入器缺省不会向 Pod 进行注入。在 Pod 模板中加入 sidecar.istio.io/inject 注解并赋值为 true 才能启用注入。
enabled: Sidecar 注入器缺省会对 Pod 进行注入。在 Pod 模板中加入 sidecar.istio.io/inject 注解并赋值为 false 就会阻止对这一 Pod 的注入

4.查看相关服务

这里使用jsonpath工具查看istio-ingressgateway的外部服务端口:

kubectl  -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}'

查看grafana的外部映射端口,此端口上的服务展示了当前集群的监控数据:

 kubectl  -n istio-system get service grafana -o jsonpath='{.spec.ports[?(@.name=="http")].nodePort}'

查看prometheus服务的端口:

 kubectl  -n istio-system get service prometheus -o yaml|grep nodePort

所有有UI界面的外部端口都可以通过浏览器采用 ip:端口 的方式正常访问。

如果在默认的grafana模板中,没有正常的展示出数据,可以查看各个节点的时钟是否同步,通过在查看网页URL的请求在prometheus执行,看是否能得到数据。

可以按照官方提供的bookinfo示例对istio进行测试:https://istio.io/docs/examples/bookinfo/

采用分流方式部署一个应用的两个版本

创建服务应用

这里使用一个示例文件,部署两个不同版本的nginx服务,对这两个版本分流。创建myapp.yaml:

apiVersion: v1
kind: Service
metadata:
  name: myapp
  labels:
    app: myapp
spec:
  type: ClusterIP
  ports:
  - port: 80
    name: http
  selector:
    app: myapp
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: myapp-v1
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: myapp
        version: v1
    spec:
      containers:
      - name: myapp
        image: janakiramm/myapp:v1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: myapp-v2
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: myapp
        version: v2
    spec:
      containers:
      - name: myapp
        image: janakiramm/myapp:v2
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

这个文件中,构建了简单的基于Nginx的Docker镜像来作为应用案例:janakiramm/myapp:v1和janakiramm/myapp:v2。部署完成之后,这两个版本的Nginx会分别显示蓝色或者绿色背景的静态页面。

执行:

kubectl apply -f myapp.yaml

成功创建后,使用port-forward 命令映射出本地端口,测试是否能成功访问:

kubectl port-forward deployment/myapp-v1  8081:80

curl 127.0.0.1:8081

创建网关

这里分别创建了网关(Gateway)、目的地规则(DestinationRule)、虚拟服务(VirtualService)到app-gateway.yaml文件中:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: app-gateway
spec:
  selector:
    istio: ingressgateway 
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: myapp
spec:
  host: myapp
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
---      
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: myapp
spec:
  hosts:
  - "*"
  gateways:
  - app-gateway
  http:
    - route:
      - destination:
          host: myapp
          subset: v1
        weight: 50
      - destination:
          host: myapp
          subset: v2
        weight: 50        
---
  • Istio网关描述了在网格边界的负载均衡器如何处理进出的HTTP/TCP连接。着重描述了哪些端口应该被暴露出来,有哪些协议可以用,负载均衡器的SNI配置等。这里默认指向了Ingress网关。
  • Istio目的地规则定义了流量被路由以后访问服务的规则。
  • 虚拟服务定义了当主机获得地址以后一系列流量的路由规则。每一条路由规则都定义了某个基于特定协议的流量的匹配规则。当一个流量被匹配了,基于版本,它会被发送到相关的目标服务。

执行:

kubectl apply -f app-gateway.yaml

可以通过istio-ingressgateway的端口来查看此服务:

kubectl  -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}'

通过访问此端口可以直接访问到应用服务,可以发现当我们不断请求时,会根据之前设置的权重对v1和v2进行轮询。