Istio在服务网络中统一提供了许多关键功能:

  • 流量管理:控制服务之间的流量和API调用的流向,使得调用更可靠,并使网络在恶劣情况下更加健壮。

  • 可观察性:了解服务之间的依赖关系,以及它们之间流量的本质和流向,从而提供快速识别问题的能力。

  • 策略执行:将组织策略应用于服务之间的互动,确保访问策略得以执行,资源在消费者之间良好分配。策略的更改是通过配置网格而不是修改应用程序代码。

  • 服务身份和安全:为网格中的服务提供可验证身份,并提供保护服务流量的能力,使其可以在不同可信度的网络上流转。

 

Istio针对可扩展性进行了设计,以满足不同的部署需要:

  • 平台支持:Istio旨在在各种环境中运行,包括跨云, 预置,Kubernetes,Mesos等。最初专注于Kubernetes,但很快将支持其他环境。

  • 集成和定制:策略执行组件可以扩展和定制,以便与现有的ACL,日志,监控,配额,审核等解决方案集成。

 

istio 配置解读_经验分享

 

Envoy:

    istio 使用Envoy 代理的扩展版本,Envoy是以c++开发的高性能代理,用于解释服务网格中所有服务的所有入站和出站的流量,Envoy的许多内置功能被iosio发扬光大,例如动态发现,负载均衡,TLS终止,HTTP1/2&Grpc代理,熔断器,健康检查,基于百分比流量拆分的分段推出,故障注入和丰富指标。

    Envoy被部署为边车,和对应服务在同一个pod中,这允许istio将大量关于流量行为的型号作为属性提取出来,而这些属性又可以在Mixer中用于执行策略决策,并发送到监控系统,以提供整个网格行为的信息

 

Mixer:

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

 

Pilot

   负责手机和验证配置,并将其传播到各种istio组件,它从Mixer和Envoy中提取环境特定的实现细节,为他们提供用户服务的抽象表示,独立于底层平台,此外,流量管理规则可以在运行时通过pilot进行编程。

 

lstio-auth

     提供强大的服务间认证和终端用户认证,使用交互tls,内置身份和证书管理,可以升级服务网格中的未加密流量,并为运维人员提供基于服务身份而不是网络控制来执行策略的能力。

 

 istio 配置解读_经验分享_02

 

安装Istio Sidecar

 在Kubernetes 1.9及更高版本中默认启用。从Istio 0.5.0开始,自动代理注入使用突变webhooks,并且已经删除了对初始化程序注入的支持。无法升级到Kubernetes 1.9的用户应使用手动注入。

 

自动把 sidecar 插入到 pod中, 需要在api中打开 

 

[root@master1 addons]# cat /lib/systemd/system/kube-apiserver.service 
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target

[Service]
User=root
ExecStart=/usr/local/bin/kube-apiserver \
  --admission-control=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota,,MutatingAdmissionWebhook,ValidatingAdmissionWebhook \
  --advertise-address=192.168.200.51 \
  --allow-privileged=true \
  --anonymous-auth=false \
  --apiserver-count=1 \
  --audit-policy-file=/etc/kubernetes/audit-policy.yaml \
  --audit-log-maxage=30 \
  --audit-log-maxbackup=3 \
  --audit-log-maxsize=100 \
  --audit-log-path=/var/log/kubernetes/audit.log \
  --authorization-mode=Node,RBAC \
  --bind-address=0.0.0.0 \
  --secure-port=6443 \
  --client-ca-file=/etc/kubernetes/ssl/ca.pem \
  --enable-swagger-ui=true \
  --etcd-cafile=/etc/kubernetes/ssl/ca.pem \
  --etcd-certfile=/etc/kubernetes/ssl/kubernetes.pem \
  --etcd-keyfile=/etc/kubernetes/ssl/kubernetes-key.pem \
  --etcd-servers=https://192.168.200.51:2379,https://192.168.200.52:2379,https://192.168.200.53:2379 \
  --event-ttl=1h \
  --kubelet-https=true \
  --insecure-bind-address=192.168.200.51 \
  --insecure-port=8080 \
  --service-account-key-file=/etc/kubernetes/ssl/ca-key.pem \
  --service-cluster-ip-range=10.254.0.0/16 \
  --service-node-port-range=30000-32000 \
  --tls-cert-file=/etc/kubernetes/ssl/kubernetes.pem \
  --tls-private-key-file=/etc/kubernetes/ssl/kubernetes-key.pem \
  --enable-bootstrap-token-auth=true \
  --token-auth-file=/etc/kubernetes/token.csv \
  --requestheader-client-ca-file=/etc/kubernetes/ssl/front-proxy-ca.pem \
  --proxy-client-cert-file=/etc/kubernetes/ssl/front-proxy-client.pem \
  --proxy-client-key-file=/etc/kubernetes/ssl/front-proxy-client-key.pem \
  --requestheader-allowed-names=aggregator \
  --requestheader-group-headers=X-Remote-Group \
  --requestheader-extra-headers-prefix=X-Remote-Extra- \
  --requestheader-username-headers=X-Remote-User \
  --runtime-config=admissionregistration.k8s.io/v1alpha1 \
  --runtime-config=api/all=true \
  --enable-aggregator-routing=true \
  --v=0
Restart=on-failure
RestartSec=5
Type=notify
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

 

 

 

Pod规格要求

1.服务关联

2.命名端口

服务端口必须命名。端口名称必须是形式<protocol>[-<suffix>]与 HTTP, http2, GRPC,或 Redis的作为<protocol>,以便采取的Istio的路由功能。例如,name: http2-foo或者name: http是有效的端口名称,但name: http2foo不是。如果端口名称未以可识别的前缀开头,或者端口未命名,则端口上的流量将被视为纯TCP流量(除非端口明确用于Protocol: UDP表示UDP端口

 

3. 使用应用标签进行部署:建议使用Kubernetes部署的Pod在部署规范中Deployment具有明确的app标签。每个部署规范都应该有一个明确的app标签,其中有一个值表示有意义的值 该app标签用于在分布式跟踪中添加上下文信息

 

自动边车注入

使用webhook准入控制器,可将Sidecars自动添加到适用的Kubernetes Pod中。此功能需要Kubernetes 1.9或更高版本。验证kube-apiserver进程是否已设置admission-control标记,MutatingAdmissionWebhookValidatingAdmissionWebhook按照正确的顺序添加并准许控制器,并且启用许可注册API。

kubectl api-versions | grep admissionregistration
admissionregistration.k8s.io/v1beta1

 

安装webhook

kubectl apply -f install/kubernetes/istio.yaml

 

Webhooks需要签名的证书/密钥对。使用install/kubernetes/webhook-create-signed-cert.sh来产生由Kubernetes' CA签名的证书/密钥对 生成的证书/密钥文件作为Kubernetes机密文件存储,供边车注入器webhook使用。

注意:Kubernetes CA批准需要创建和批准CSR的权限

./install/kubernetes/webhook-create-signed-cert.sh \
    --service istio-sidecar-injector \
    --namespace istio-system \
    --secret sidecar-injector-certs

 

安装边车注入配置图。

kubectl apply -f install/kubernetes/istio-sidecar-injector-configmap-release.yaml

 

Set the caBundle in the webhook install YAML that the Kubernetes api-server uses to invoke the webhook.

cat install/kubernetes/istio-sidecar-injector.yaml | \
     ./install/kubernetes/webhook-patch-ca-bundle.sh > \
     install/kubernetes/istio-sidecar-injector-with-ca-bundle.yaml

 

Install the sidecar injector webhook.

kubectl apply -f install/kubernetes/istio-sidecar-injector-with-ca-bundle.yaml

 

The sidecar injector webhook should now be running.

kubectl -n istio-system get deployment -listio=sidecar-injector

NAME                     DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
istio-sidecar-injector   1         1         1            1           1d

 

NamespaceSelector根据该对象的名称空间是否与选择器匹配来决定是否在对象上运行webhook,默认的webhook配置使用istio-injection=enabled

查看显示istio-injection标签的default名称空间并验证名称空间未被标记。

kubectl get namespace -L istio-injection

NAME           STATUS        AGE       ISTIO-INJECTION
default        Active        1h        
istio-system   Active        1h        
kube-public    Active        1h        
kube-system    Active        1h

 

default名称空间标签istio-injection=enabled

kubectl label namespace default istio-injection=enabled
kubectl get namespace -L istio-injection

NAME           STATUS    AGE       ISTIO-INJECTION
default        Active    1h        enabled
istio-system   Active    1h        
kube-public    Active    1h        
kube-system    Active    1h  

 

部署一个应用程序

kubectl apply -f samples/sleep/sleep.yaml 

 

 

禁用default名称空间的注入

kubectl label namespace default istio-injection-

 

 

卸载webhook

kubectl delete -f install/kubernetes/istio-sidecar-injector-with-ca-bundle.yaml

 

kubectl -n istio-system delete secret sidecar-injector-certs
kubectl delete csr istio-sidecar-injector.istio-system
kubectl label namespace default istio-injection-

 

 

 

流量管理
介绍演示Istio服务网格的流量路由功能的任务。

配置请求路由:  此任务向您展示如何根据权重和HTTP标头配置动态请求路由。
故障注入  :  此任务显示如何注入延迟并测试应用程序的弹性。
交通转移  :  此任务向您显示如何将流量从旧版本迁移到新版本的服务。
设置请求超时:  本任务向您展示如何使用Istio在Envoy中设置请求超时。
Istio Ingress  :  介绍如何在Kubernetes上配置Istio Ingress。
控制出口流量:  介绍如何配置Istio以将流量从网格中的服务路由到外部服务。
控制出口TCP流量:介绍如何配置Istio以将TCP流量从网格中的服务路由到外部服务。
断路    :  这项任务演示了弹性应用的断路能力
镜像    :  演示Istio的流量投影/镜像功能

 

 

 deployment 和 service 模版 ,使用标签 app version, 一个服务对应不同的deployment
apiVersion: v1
kind: Service
metadata:
  name: reviews
  labels:
    app: reviews
spec:
  type: NodePort
  ports:
  - port: 9080
    name: http
  selector:
    app: reviews
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: reviews-v1
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: reviews
        version: v1
    spec:
      containers:
      - name: reviews
        image:  192.168.200.10/istio/examples-bookinfo-reviews-v1:1.5.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: reviews-v2
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: reviews
        version: v2
    spec:
      containers:
      - name: reviews
        image:  192.168.200.10/istio/examples-bookinfo-reviews-v2:1.5.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: reviews-v3
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: reviews
        version: v3
    spec:
      containers:
      - name: reviews
        image:  192.168.200.10/istio/examples-bookinfo-reviews-v3:1.5.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080

 

配置请求路由

 

原理: 首先使用istio将100%的请求流量路由到了 v1 版本上, 然后设置了一条路由规则, 该规则基于请求header(一个用户的cookie)将流量路由到了 v2 版本,  如果v2 版本经过测试后满足要求,我们就可以一次性

或者渐进的路由到v2版本上。

 

1. 默认访问 version v1 版本

apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  name: reviews-default
spec:
  destination:
    name: reviews
  precedence: 1
  route:
  - labels:
      version: v1

 

2. 将特定用户的请求路由到 version v2上

apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  name: reviews-test-v2
spec:
  destination:
    name: reviews
  precedence: 2
  match:
    request:
      headers:
        cookie:
          regex: "^(.*?;)?(user=jason)(;.*)?$"
  route:
  - labels:
      version: v2

 

 

故障注入

istio 注入延迟 测试应用弹性

2个服务, serverA  和 serverB

serverA 用户(feng) 和 serverB 之间 注入7秒延迟,    serverA 针对 serverB 服务设置了10秒超时,期望 端对端的流程能无错持续。

 注意: 其他用户没有注入7秒延迟。

apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  name: ratings-test-delay
spec:
  destination:
    name: ratings
  precedence: 2
  match:
    request:
      headers:
        cookie:
          regex: "^(.*?;)?(user=jason)(;.*)?$"
  route:
  - labels:
      version: v1
  httpFault:
    delay:
      percent: 100
      fixedDelay: 7s

 

使用账户 feng 登录, 如果应用首页已经设置了正确处理延迟,那么首页将会在 7秒加载完成,但是 serverA 到 serverB 需要等待10秒,那么将超时。

 

 流量转移:

应用流量 逐步有旧版本的服务 迁移到新版本, 通过istio 可以使用不同权重的规则,将流量平稳的从旧版本服务 迁移到新版本上, 金丝雀 灰度发布。

 1. 请求v1 版本

apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  name: reviews-default
spec:
  destination:
    name: reviews
  precedence: 1
  route:
  - labels:
      version: v1

 

 2. 把50% 的流量从 v1 版本 转移到 v3版本

 

apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  name: reviews-default
spec:
  destination:
    name: reviews
  precedence: 1
  route:
  - labels:
      version: v1
    weight: 50
  - labels:
      version: v3
    weight: 50

用 kubectl  apply/ replace 替换

 

3. v3 和 v1 版本交替出现后, 将100%的流量路由到v3 版本中

apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  name: reviews-default
spec:
  destination:
    name: reviews
  precedence: 1
  route:
  - labels:
      version: v3
    weight: 100

 

 

 ###################################################################################################

 实战:

一个服务,对应3个deployment, 最后通过istio-ingress 映射域名

 

nginx.yaml

apiVersion: v1
kind: Service
metadata:
  namespace: fengjian
  name: nginx
  labels:
    app: nginx
spec:
  type: NodePort
  ports:
  - port: 80
    name: http
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  namespace: fengjian
  name: nginx-v1
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
        version: v1
    spec:
      containers:
      - name: nginx
        image:  192.168.200.10/test/nginx:v1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  namespace: fengjian
  name: nginx-v2
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
        version: v2
    spec:
      containers:
      - name: nginx
        image:  192.168.200.10/test/nginx:v2
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  namespace: fengjian
  name: nginx-v3
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
        version: v3
    spec:
      containers:
      - name: nginx
        image:  192.168.200.10/test/nginx:v3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

 

2. 通过istio-ingress 让外网访问,注意: pod 注入 enovy后,nodeport 不起作用了,服务无法访问。

istio-ingress-bookinfo.yaml 

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: gatewayfengjian
  namespace: fengjian
  annotations:
    kubernetes.io/ingress.class: "istio"
spec:
  rules:
  - http:
      paths:
      - path: /
        backend:
          serviceName: nginx
          servicePort: 80

 

创建执行

[root@master1 nginx-istio]# kubectl create -f booktest.yaml  -f istio-ingress-bookinfo.yaml 

 

istio 配置解读_经验分享_03

 

 默认情况, 访问应该轮训到 3个deployment的上的nginx ,  通过流量管理中的 配置请求路由规则,指定到 deployment  nginx:v1 版本上

vim rule-choice-deployment-nginx-v1.yaml

apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  namespace: fengjian
  name: nginx-default
spec:
  destination:
    name: nginx
  precedence: 1
  route:
  - labels:
      version: v1

 

创建规则

kubectl create -f rule-choice-deployment-nginx-v1.yaml

 

 访问istio-ingress 

istio 配置解读_经验分享_04

 

 注意的问题: 

 istio 配置解读_经验分享_05

 

 

流量转移

流量从 旧版本中迁移到新版本中, 通过istio,可以使用一系列不同权重的规则(10%,20%.....100%),将流量平稳的迁移到新版本中

1. 迁移50%到新版本中

route-rule-reviews-50.yaml

apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  namespace: fengjian
  name: nginx-50
spec:
  destination:
    name: nginx
  precedence: 1
  route:
  - labels:
      version: v1
    weight: 50
  - labels:
      version: v3
    weight: 50

 

通过访问页面,基本上是50%的轮训到页面。

 

2. 迁移100%到新版本中

route-rule-reviews-100.yaml

apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  namespace: fengjian
  name: nginx-50
spec:
  destination:
    name: nginx
  precedence: 1
  - labels:
      version: v3
    weight: 100

 

 是更新,不是创建

kubectl apply -f route-rule-reviews-100.yaml

 

 注意该方式和使用容器编排平台的部署特点来进行版本迁移是完全不同的,容器编排平台使用了实例scaling来对流量进行管理,而通过istio,两个版本的的服务可以独立进行

scale up 和 scale down,并不会影响这两个版本的服务之间的流量分发。

 

 

 熔断

限制因为故障、延迟高峰以及其他预计外的网络异常所造成的影响范围。

服务端使用 nginx

 

 

配置目的策略,对nginx 的调用过程进行断路设置。

 

nginx-destinaionpolicy.yaml

apiVersion: config.istio.io/v1beta1
kind: DestinationPolicy
metadata:
 name: nginx-circuit-breaker
spec:
 destination:
   name: nginx
   labels:
     version: v1
 circuitBreaker:
   simpleCb:
     maxConnections: 1
     httpMaxPendingRequests: 1
     sleepWindow: 3m
     httpDetectionInterval: 1s
     httpMaxEjectionPercent: 100
     httpConsecutiveErrors: 1
     httpMaxRequestsPerConnection: 1

 

kubectl  create -f  nginx-destinaionpolicy.yaml

istioctl get destinationpolicy

NAME                    KIND                                            NAMESPACE
nginx-circuit-breaker DestinationPolicy.v1alpha2.config.istio.io        istio-samples

 

设置客户端

客户端调用ginx服务的规则, 创建一个客户端,向服务端发送流量, 使用负载测试工具fortio, 使用fortio 可以控制连接数量,并发数以及外发http调用的延迟。

kubectl apply -f <(istioctl kube-inject -f samples/httpbin/sample-client/fortio-deploy.yaml)

 

使用-curl 指定只执行一次调用。

FORTIO_POD=$(kubectl get pod | grep fortio | awk '{ print $1 }')
kubectl exec -it $FORTIO_POD  -c fortio /usr/local/bin/fortio -- load -curl  http://nginx:8000

 

测试断路器

在断路器设置中,我们指定maxConnections: 1以及httpMaxPendingRequests: 1。这样的设置下,如果我们并发超过一个连接和请求,istio-proxy就会断掉后续的请求和连接。设置两个并发链接(-c 2),发送20个请求(-n 20):

[root@master1 httpbin]# kubectl exec -it fortio-deploy-d86464f9d-ks4hm   -c fortio /usr/local/bin/fortio -- load -c 2 -qps 0 -n 20 -loglevel Warning http://nginx.fengjian
08:10:21 I logger.go:97> Log level is now 3 Warning (was 2 Info)
Fortio 0.9.0 running at 0 queries per second, 4->4 procs, for 20 calls: http://nginx.fengjian
Starting at max qps with 2 thread(s) [gomax 4] for exactly 20 calls (10 per thread + 0)
Ended after 18.157183ms : 20 calls. qps=1101.5
Aggregated Function Time : count 20 avg 0.0016854434 +/- 0.0008323 min 0.000847509 max 0.004309432 sum 0.033708867
# range, mid point, percentile, count
>= 0.000847509 <= 0.001 , 0.000923755 , 15.00, 3
> 0.001 <= 0.002 , 0.0015 , 65.00, 10
> 0.002 <= 0.003 , 0.0025 , 95.00, 6
> 0.004 <= 0.00430943 , 0.00415472 , 100.00, 1
# target 50% 0.0017
# target 75% 0.00233333
# target 90% 0.00283333
# target 99% 0.00424755
# target 99.9% 0.00430324
Sockets used: 2 (for perfect keepalive, would be 2)
Code 200 : 20 (100.0 %)
Response Header Sizes : count 20 avg 237 +/- 0 min 237 max 237 sum 4740
Response Body/Total Sizes : count 20 avg 246 +/- 0 min 246 max 246 sum 4920
All done 20 calls (plus 0 warmup) 1.685 ms avg, 1101.5 qps

 

 

设置两个并发链接(-c 100000),发送20个请求(-n 200000

kubectl exec -it fortio-deploy-d86464f9d-ks4hm   -c fortio /usr/local/bin/fortio -- load -c 100000 -qps 0 -n 20000 -loglevel Warning http://nginx.fengjian

> 50 <= 75 , 62.5 , 42.37, 12001
> 75 <= 100 , 87.5 , 47.88, 5515
> 100 <= 283.465 , 191.733 , 100.00, 52118
# target 50% 107.452
# target 75% 195.459
# target 90% 248.263
# target 99% 279.945
# target 99.9% 283.113
Sockets used: 100001 (for perfect keepalive, would be 100000)
Code  -1 : 62857 (62.9 %)
Code 200 : 19587 (19.6 %)
Code 503 : 17558 (17.6 %)
Response Header Sizes : count 100002 avg 46.731345 +/- 94.69 min 0 max 240 sum 4673228
Response Body/Total Sizes : count 100002 avg 86.594238 +/- 113 min 0 max 249 sum 8659597
All done 100002 calls (plus 0 warmup) 123391.636 ms avg, 352.1 qps

 

 

策略实施

限流

如果是一个外部付费API服务, 限制1 qps免费, 使用istio 控制。