超详细教程,一文入门Istio架构原理及实战应用

语言: CN / TW / HK

Istio简介

2.1、istio架构

file

实际上Istio 就是 Service Mesh 架构的一种实现,服务之间的通信(比如这里的 Service A 访问 Service B)会通过代理(默认是 Envoy)来进行。

而且中间的网络协议支持 HTTP/1.1,HTTP/2,gRPC 或者 TCP,可以说覆盖了主流的通信协议。代理这一层,称之为数据平面。

控制平面做了进一步的细分,分成了 Pilot、Citadel 和 Galley,它们的各自功能如下:

  • Pilot:为 Envoy 提供了服务发现,流量管理和智能路由(AB 测试、金丝雀发布等),以及错误处理(超时、重试、熔断)功能。
  • Citadel:为服务之间提供认证和证书管理,可以让服务自动升级成 TLS 协议。
  • Galley:Galley 是 Istio 的配置验证、提取、处理和分发组件。它负责将其余的 Istio 组件与从底层平台(例如 Kubernetes)获取用户配置的细节隔离开来。

数据平面会和控制平面通信,一方面可以获取需要的服务之间的信息,另一方面也可以汇报服务调用的 Metrics 数据。

2.1、为什么使用 Istio?

通过负载均衡、服务间的身份验证、监控等方法,Istio 可以轻松地创建一个已经部署了服务的网络,而服务的代码只需很少更改甚至无需更改。通过在整个环境中部署一个特殊的 sidecar 代理为服务添加 Istio 的支持,而代理会拦截微服务之间的所有网络通信,然后使用其控制平面的功能来配置和管理 Istio,这包括:

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

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

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

  • 集群内(包括集群的入口和出口)所有流量的自动化度量、日志记录和追踪。

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

Istio 为可扩展性而设计,可以满足不同的部署需求。

2.2、核心特性

Istio 以统一的方式提供了许多跨服务网络的关键功能。

2.2.1、流量管理

Istio 简单的规则配置和流量路由允许您控制服务之间的流量和 API 调用过程。

Istio 简化了服务级属性(如熔断器、超时和重试)的配置,并且让它轻而易举的执行重要的任务(如 A/B 测试、金丝雀发布和按流量百分比划分的分阶段发布)。

有了更好的对流量的可视性和开箱即用的故障恢复特性,就可以在问题产生之前捕获它们,无论面对什么情况都可以使调用更可靠,网络更健壮。

2.2.2、安全

Istio 的安全特性解放了开发人员,使其只需要专注于应用程序级别的安全。

Istio 提供了底层的安全通信通道,并为大规模的服务通信管理认证、授权和加密。有了 Istio,服务通信在默认情况下就是受保护的,可以让您在跨不同协议和运行时的情况下实施一致的策略——而所有这些都只需要很少甚至不需要修改应用程序。

Istio 是独立于平台的,可以与 Kubernetes(或基础设施)的网络策略一起使用。但它更强大,能够在网络和应用层面保护pod到 pod 或者服务到服务之间的通信。

2.2.3、可观察性

Istio 健壮的追踪、监控和日志特性让您能够深入的了解服务网格部署。

通过 Istio 的监控能力,可以真正的了解到服务的性能是如何影响上游和下游的;而它的定制 Dashboard 提供了对所有服务性能的可视化能力,并让您看到它如何影响其他进程。

Istio 的 Mixer 组件负责策略控制和遥测数据收集。它提供了后端抽象和中介,将一部分 Istio 与后端的基础设施实现细节隔离开来,并为运维人员提供了对网格与后端基础实施之间交互的细粒度控制。

所有这些特性都使您能够更有效地设置、监控和加强服务的 SLO。当然,底线是您可以快速有效地检测到并修复出现的问题。

2.3、平台支持

Istio 独立于平台,被设计为可以在各种环境中运行,包括跨云、内部环境、Kubernetes、Mesos 等等。您可以在 Kubernetes 或是装有 Consul 的 Nomad 环境上部署 Istio。Istio 目前支持:

  • Kubernetes 上的服务部署

  • 基于 Consul 的服务注册

  • 服务运行在独立的虚拟机上

3、Istio快速入门

下面我们将Istio进行部署安装,来体验下它的魅力。

3.1、搭建kubernetes集群

Istio运行在kubernetes平台是最佳的选择,所以我们先搭建kubernetes环境。

注意:初学者请参考课程资料提供的一键安装文档

3.1.1、环境准备

准备3台Centos7虚拟机:

名称 IP 角色 CPU 内存 硬盘
node1 192.168.31.106 master 2核 4GB 100GB
node2 192.168.31.107 node 2核 4GB 100GB
node3 192.168.31.108 node 2核 4GB 100GB

3.1.2、前置工作

搭建K8S之前,需要一些前置的准备工作,否则不能完成集群的搭建。yum如果不能用,则使用yum -y install yum-utils或者curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo,然后再使用yum。

#修改主机名
hostnamectl  set-hostname node2
hostnamectl  set-hostname node3
#更新yum源,并且完成yum update操作
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
#如果wget无法使用直接输入 yum install wget安装即可
yum makecache
yum -y update
#安装docker
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum makecache fast
yum -y install docker-ce

#启动docker服务
systemctl start docker.service
#开机自启
systemctl enable docker.service

#添加docker阿里云加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://c6n8vys4.mirror.aliyuncs.com"]
}
EOF

sudo systemctl daemon-reload
sudo systemctl restart docker

#测试一下,看下载速度怎么样
docker pull redis
docker rmi redis:latest
#关闭防火墙
systemctl stop firewalld.service
systemctl disable firewalld.service

#添加hosts映射 可略过 这里设置的目的是为了后续操作中通过 scp将某一个节点上的文件传到别的节点上
vim /etc/hosts
192.168.31.106 node1
192.168.31.107 node2
192.168.31.108 node3

scp /etc/hosts node2:/etc/
scp /etc/hosts node3:/etc/
#设置node1到node2、node3免登陆
ssh-keygen #一路下一步操作
ssh-copy-id node2
ssh-copy-id node3

#测试
ssh node2
ssh node3

3.1.3、搭建集群

#修改系统参数
# 将 SELinux 设置为 permissive 模式(相当于将其禁用)
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

# 禁用swap文件,编辑/etc/fstab,注释掉引用 swap 的行
vim /etc/fstab
swapoff -a

# 设置网桥参数
vim /etc/sysctl.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.ipv4.tcp_tw_recycle = 0

scp /etc/sysctl.conf node2:/etc/
scp /etc/sysctl.conf node3:/etc/

#立即生效
sysctl -p
#如果出现/proc/sys/net/bridge/bridge-nf-call-ip6tables: No such file or directory
#执行modprobe br_netfilter,再试即可

#安装kubectl
vim /etc/yum.repos.d/kubernetes.repo

[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=0

yum list kubectl –showduplicates
yum install -y kubectl.x86_64
#指定版本 一定要指定版本
# yum install -y kubectl-1.18.6
#查看版本
kubectl version

yum install -y kubelet kubeadm --disableexcludes=kubernetes
#指定版本 一定要指定版本
#yum install -y kubelet-1.18.6 kubeadm-1.18.6 --disableexcludes=kubernetes

#如果安装错了,可以用以下命令移除
#yum remove kubectl kubelet kubeadm

#拉取所需要的镜像
kubeadm config images pull --image-repository=registry.cn-hangzhou.aliyuncs.com/itcast --kubernetes-version=v1.18.6
#如果拉取失败,尝试这个:kubeadm config images pull --image-repository=lank8s.cn --kubernetes-version=v1.18.6

#开始初始化,如果使用lank8s.cn拉取的镜像,需要指定--image-repository=lank8s.cn
kubeadm init --apiserver-advertise-address 192.168.31.106 --pod-network-cidr=10.244.0.0/16 --image-repository=registry.cn-hangzhou.aliyuncs.com/itcast  --kubernetes-version=v1.18.6

#当看到 Your Kubernetes control-plane has initialized successfully! 说明初始化成功了!

#拷贝admin.conf到home目录,否则出错:The connection to the server localhost:8080 was refused - did you specify the right host or port?
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

#设置网络 kube-flannel.yml 文件在资料中
kubectl apply -f kube-flannel.yml

#测试
[root[@node1](https://my.oschina.net/u/4273199) k8s]# kubectl get nodes
NAME    STATUS   ROLES    AGE   VERSION
node1   Ready    master   23m   v1.18.6

#将node2、node3加入到集群,token要替换成自己的
kubeadm join 192.168.31.106:6443 --token ekw4eu.cfi77sji1jyczhj6 --discovery-token-ca-cert-hash sha256:21de4177eaf76353dd060f2a783c9dafe17636437ade020bc40d60a8ab903483

#测试
[root[@node1](https://my.oschina.net/u/4273199) k8s]# kubectl get nodes
NAME    STATUS   ROLES    AGE     VERSION
node1   Ready    master   31m     v1.18.6
node2   Ready    <none>   6m46s   v1.18.6
node3   Ready    <none>   2m21s   v1.18.6

#说明集群组件成功了

#如果需要删除集群,执行 kubeadm reset ,3台机器都需要执行

#查看正在执行的pod
kubectl get pod --all-namespaces -o wide

查看正在执行的pod,kubectl get pod --all-namespaces -o wide

file

注意:如果虚拟机重启导致k8s关闭,可以采用systemctl status kubelet查看状态,采用systemctl start kubelet启动k8s,无论是主节点还是工作节点,都需要执行。

file

kubeadm join 192.168.211.151:6443 --token zkkd3y.iompmpb402kyvdq6 \
    --discovery-token-ca-cert-hash sha256:3c500a7df3a3e6857b50c31f9a9a209d57e669d7acd69905f040023094945c04

file

registry.cn-hangzhou.aliyuncs.com/itcast/kube-proxy   v1.18.6
registry.cn-hangzhou.aliyuncs.com/itcast/pause        3.2 


registry.cn-hangzhou.aliyuncs.com/itcast/kube-proxy   v1.18.6
quay.io/coreos/flannel                                v0.12.0-amd64
registry.cn-hangzhou.aliyuncs.com/itcast/pause        3.2

3.2、搭建Istio环境

3.2.1、下载 Istio

下载 Istio,下载内容将包含:安装文件、示例和 istioctl 命令行工具。

  1. 访问 Istio release 页面下载与您操作系统对应的安装文件。在 macOS 或 Linux 系统中,也可以通过以下命令下载最新版本的 Istio:

    $ curl -L https://istio.io/downloadIstio | sh -
    

    可用指定版本:

    $ curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.6.5 sh -
    
  2. 切换到 Istio 包所在目录下。例如:Istio 包名为 istio-1.6.5,则:

    $ cd istio-1.6.5
    

    安装目录包含如下内容:

    • samples/ 目录下,有示例应用程序
    • bin/ 目录下,包含 istioctl 的客户端文件。istioctl 工具用于手动注入 Envoy sidecar 代理。
  3. istioctl 客户端路径增加到 path 环境变量中,macOS 或 Linux 系统的增加方式如下:

    $ export PATH=$PWD/bin:$PATH
    

安装 bash 自动补全文件

如果您使用 bash,istioctl 自动补全的文件位于 tools 目录。通过复制 istioctl.bash 文件到您的 home 目录,然后添加下行内容到您的 .bashrc 文件执行 istioctl tab 补全文件:

source ~/istio-1.6.5/tools/istioctl.bash

如果 istioctl 补全文件已经正确安装,在您输入 istioctl 命令时通过按 Tab 键,它会返回一组推荐命令供您选择:

$ istioctl proxy-<TAB>
proxy-config proxy-status

3.2.2、安装Istio

请按照以下步骤在您所选的平台上使用 demo 配置文件安装 Istio。

  1. 安装 demo 配置

    $ istioctl manifest apply --set profile=demo
    

    选择要安装的组件在istio-1.6.5/manifests/profiles中!

  2. 为了验证是否安装成功,需要先确保以下 Kubernetes 服务正确部署,然后验证除 jaeger-agent 服务外的其他服务,是否均有正确的 CLUSTER-IP

    [root@k8-master ~]# kubectl get svc -n istio-system
    NAME                        TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                                                                      AGE
    grafana                     ClusterIP      10.1.88.100    <none>        3000/TCP                                                                     2m8s
    istio-egressgateway         ClusterIP      10.1.62.15     <none>        80/TCP,443/TCP,15443/TCP                                                     2m8s
    istio-ingressgateway        LoadBalancer   10.1.37.204    <pending>     15020:32010/TCP,80:32672/TCP,443:32187/TCP,31400:32038/TCP,15443:32460/TCP   2m8s
    istiod                      ClusterIP      10.1.233.207   <none>        15010/TCP,15012/TCP,443/TCP,15014/TCP,853/TCP                                2m12s
    jaeger-agent                ClusterIP      None           <none>        5775/UDP,6831/UDP,6832/UDP                                                   2m7s
    jaeger-collector            ClusterIP      10.1.149.13    <none>        14267/TCP,14268/TCP,14250/TCP                                                2m7s
    jaeger-collector-headless   ClusterIP      None           <none>        14250/TCP                                                                    2m7s
    jaeger-query                ClusterIP      10.1.147.252   <none>        16686/TCP                                                                    2m7s
    kiali                       ClusterIP      10.1.165.21    <none>        20001/TCP                                                                    2m7s
    prometheus                  ClusterIP      10.1.180.211   <none>        9090/TCP                                                                     2m7s
    tracing                     ClusterIP      10.1.43.36     <none>        80/TCP                                                                       2m7s
    zipkin                      ClusterIP      10.1.159.254   <none>        9411/TCP                                                                     2m7s
    

    如果集群运行在一个不支持外部负载均衡器的环境中(例如:minikube),istio-ingressgatewayEXTERNAL-IP 将显示为 <pending> 状态。请使用服务的 NodePort 或 端口转发来访问网关。

    请确保关联的 Kubernetes pod 已经部署,并且 STATUSRunning

    [root@k8-master ~]# kubectl get pods -n istio-system
    NAME                                    READY   STATUS    RESTARTS   AGE
    grafana-b54bb57b9-lt4jn                 1/1     Running   0          2m31s
    istio-egressgateway-7486cf8c97-4nxnm    1/1     Running   0          2m31s
    istio-ingressgateway-6bcb9d7bbf-pxnl5   1/1     Running   0          2m31s
    istio-tracing-9dd6c4f7c-zq2hh           1/1     Running   0          2m31s
    istiod-788f76c8fc-z8bqx                 1/1     Running   0          2m35s
    kiali-d45468dc4-v6w9p                   1/1     Running   0          2m31s
    prometheus-6477cfb669-tn272             2/2     Running   0          2m31s
    

3.2.3、卸载Istio

istioctl manifest generate --set profile=demo | kubectl delete -f -

3.3、Bookinfo示例

3.3.1、应用说明

这个示例部署了一个用于演示多种 Istio 特性的应用,该应用由四个单独的微服务构成。 这个应用模仿在线书店的一个分类,显示一本书的信息。 页面上会显示一本书的描述,书籍的细节(ISBN、页数等),以及关于这本书的一些评论。

Bookinfo 应用分为四个单独的微服务:

  • productpage. 这个微服务会调用 detailsreviews 两个微服务,用来生成页面。
  • details. 这个微服务中包含了书籍的信息。
  • reviews. 这个微服务中包含了书籍相关的评论。它还会调用 ratings 微服务。
  • ratings. 这个微服务中包含了由书籍评价组成的评级信息。

reviews 微服务有 3 个版本:

  • v1 版本不会调用 ratings 服务。
  • v2 版本会调用 ratings 服务,并使用 1 到 5 个黑色星形图标来显示评分信息。
  • v3 版本会调用 ratings 服务,并使用 1 到 5 个红色星形图标来显示评分信息。

下图展示了这个应用的端到端架构。

file

Bookinfo 应用中的几个微服务是由不同的语言编写的。 这些服务对 Istio 并无依赖,但是构成了一个有代表性的服务网格的例子:它由多个服务、多个语言构成,并且 reviews 服务具有多个版本。

3.3.2、部署应用

要在 Istio 中运行这一应用,无需对应用自身做出任何改变。 您只要简单的在 Istio 环境中对服务进行配置和运行,具体一点说就是把 Envoy sidecar 注入到每个服务之中。 最终的部署结果将如下图所示:

file

所有的微服务都和 Envoy sidecar 集成在一起,被集成服务所有的出入流量都被 sidecar 所劫持,这样就为外部控制准备了所需的 Hook,然后就可以利用 Istio 控制平面为应用提供服务路由、遥测数据收集以及策略实施等功能。

3.3.3、启动应用服务

  1. 进入 Istio 安装目录。

  2. Istio 默认自动注入 Sidecar. 请为 default 命名空间打上标签 istio-injection=enabled

    $ kubectl label namespace default istio-injection=enabled
    
  3. 使用 kubectl 部署应用:

    $ kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
    

    如果您在安装过程中禁用了 Sidecar 自动注入功能而选择手动注入 Sidecar,请在部署应用之前使用 istioctl kube-inject 命令修改 bookinfo.yaml 文件。

    $ kubectl apply -f <(istioctl kube-inject -f samples/bookinfo/platform/kube/bookinfo.yaml)
    

    上面的命令会启动全部的四个服务,其中也包括了 reviews 服务的三个版本(v1、v2 以及 v3)。

    在实际部署中,微服务版本的启动过程需要持续一段时间,并不是同时完成的。

  4. 确认所有的服务和 Pod 都已经正确的定义和启动:

    $ kubectl get services
    NAME                       CLUSTER-IP   EXTERNAL-IP   PORT(S)              AGE
    details                    10.0.0.31    <none>        9080/TCP             6m
    kubernetes                 10.0.0.1     <none>        443/TCP              7d
    productpage                10.0.0.120   <none>        9080/TCP             6m
    ratings                    10.0.0.15    <none>        9080/TCP             6m
    reviews                    10.0.0.170   <none>        9080/TCP             6m
    

    还有:

    $ kubectl get pods
    NAME                                        READY     STATUS    RESTARTS   AGE
    details-v1-1520924117-48z17                 2/2       Running   0          6m
    productpage-v1-560495357-jk1lz              2/2       Running   0          6m
    ratings-v1-734492171-rnr5l                  2/2       Running   0          6m
    reviews-v1-874083890-f0qf0                  2/2       Running   0          6m
    reviews-v2-1343845940-b34q5                 2/2       Running   0          6m
    reviews-v3-1813607990-8ch52                 2/2       Running   0          6m
    

file

  1. 要确认 Bookinfo 应用是否正在运行,请在某个 Pod 中用 curl 命令对应用发送请求,例如 ratings

    $ kubectl exec -it $(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}') -c ratings -- curl productpage:9080/productpage | grep -o "<title>.*</title>"
    <title>Simple Bookstore App</title>
    

3.3.4、确定 Ingress 的 IP

现在 Bookinfo 服务启动并运行中,您需要使应用程序可以从外部访问 Kubernetes 集群,例如使用浏览器。可以用 Istio Gateway 来实现这个目标。

  1. 为应用程序定义 Ingress 网关:

    $ kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
    
  2. 确认网关创建完成:

    $ kubectl get gateway
    NAME               AGE
    bookinfo-gateway   32s
    
  3. 设置访问网关的 INGRESS_HOSTINGRESS_PORT 变量。确认并设置。

    #设置 ingress 端口
    export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
    export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')
    
    #设置 ingress IP
    export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}')
    
  4. 设置 GATEWAY_URL

    export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
    

可以用浏览器打开网址 http://$GATEWAY_URL/productpage,来浏览应用的 Web 页面。如果刷新几次应用的页面,就会看到 productpage 页面中会随机展示 reviews 服务的不同版本的效果(红色、黑色的星形或者没有显示)。reviews 服务出现这种情况是因为我们还没有使用 Istio 来控制版本的路由。

file

3.3.5、应用默认目标规则

给各个服务创建**DestinationRule**

在使用 Istio 控制 Bookinfo 版本路由之前,您需要在目标规则中定义好可用的版本,命名为 subsets

#设置
kubectl apply -f samples/bookinfo/networking/destination-rule-all.yaml

#查询
kubectl get destinationrules -o yaml

至此,Istio 完成了全部的接管,第一个示例部署完成。

3.4、体验Istio

3.4.1、请求路由

按照版本路由

目前reviews有三个版本,在浏览器中访问 Bookinfo 应用程序的 /productpage 并刷新几次。我们发现有时书评的输出包含星级评分,有时则不包含。 这是因为没有明确的默认服务版本路由。

现在我们要做就是让istio接管路由,比如将所有流量都路由到每个微服务的v1版本,Istio实现起来是非常简单的,只需要添加虚拟服务(VirtualService)即可。

示例:将所有流量都路由到各个微服务的v1版本

#virtual-service-all-v1.yaml是官方提供的示例文件

kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml

其内容如下:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: productpage
spec:
  hosts:
  - productpage
  http:
  - route:
    - destination:
        host: productpage
        subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1  #在这里指定了所有的http请求都通过v1完成,而v1在默认的规则中有定义
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - route:
    - destination:
        host: ratings
        subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: details
spec:
  hosts:
  - details
  http:
  - route:
    - destination:
        host: details
        subset: v1
---

经过测试,发现reviews不再切换样式。

file

按照不同用户身份路由

接下来,您将更改路由配置,以便将来自特定用户的所有流量路由到特定服务版本。在这,来自名为 Jason 的用户的所有流量将被路由到服务 reviews:v2

请注意,Istio 对用户身份没有任何特殊的内置机制。事实上,productpage 服务在所有到 reviews 服务的 HTTP 请求中都增加了一个自定义的 end-user 请求头,从而达到了本例子的效果。

请记住,reviews:v2 是包含星级评分功能的版本。

  1. 运行以下命令以启用基于用户的路由:

    $ kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml
    
  2. 确认规则已创建:

    $ kubectl get virtualservice reviews -o yaml
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: reviews
      ...
    spec:
      hosts:
      - reviews
      http:
      - match:
        - headers:
            end-user:
              exact: jason
        route:
        - destination:
            host: reviews
            subset: v2
      - route:
        - destination:
            host: reviews
            subset: v1
    
  3. 在 Bookinfo 应用程序的 /productpage 上,以用户 jason 身份登录。

    刷新浏览器。你看到了什么?星级评分显示在每个评论旁边。

  4. 以其他用户身份登录(选择您想要的任何名称)。

    刷新浏览器。现在星星消失了。这是因为除了 Jason 之外,所有用户的流量都被路由到 reviews:v1

您已成功配置 Istio 以根据用户身份路由流量。

3.4.2、流量转移

还可以将reviews的部分流量转移到v3版本,基于此可以实现灰度发布、A/B测试等:

#将所有流量都路由到每个服务的v1版本
kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml

#将reviews服务 50%的流量转移到v3
kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-50-v3.yaml

内容如下:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 50
    - destination:
        host: reviews
        subset: v3
      weight: 50

刷新浏览器中的 /productpage 页面,大约有 50% 的几率会看到页面中出带 红色 星级的评价内容。这是因为 v3 版本的 reviews 访问了带星级评级的 ratings 服务,但 v1 版本却没有。

如果认为 reviews:v3 微服务已经稳定,可以通过应用此 virtual service 规则将 100% 的流量路由到 reviews:v3:

#将reviews服务的全部流量都切换到v3版本

kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-v3.yaml

这样,所有的请求都转向到了v3了。

如果需要删除所有服务的虚拟网络,可以执行:

kubectl delete -f samples/bookinfo/networking/virtual-service-all-v1.yaml

virtual-service-all-v1.yaml配置文件中配置了所有服务的路由信息,如果删除了则所有的路由信息都删了

3.4.3、超时与重试

http 请求的超时可以用路由规则timeout 字段来指定。 默认情况下,超时是禁用的

这里我们来实验 reviews 服务的请求超时,将请求路由到 reviews 服务的 v2 版本,它会去调用 ratings 服务,我们首先在 ratings 服务上人为的引入2s的延迟(故障注入),再对 reviews 服务配置超时timeout

1、在istio-1.6.5/samples/bookinfo/networking 目录下创建配置文件

#创建配置文件
vi virtual-service-reviews-v2-timeout.yaml

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - fault:
      delay:
        percent: 100
        fixedDelay: 2s
    route:
    - destination:
        host: ratings
        subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v2
    #timeout: 0.5s

ratings服务上注入2s的延迟,

2、应用该路由配置,就在当前目录下执行即可

kubectl apply -f virtual-service-reviews-v2-timeout.yaml

3、访问该网址,这时可以看到 Bookinfo 应用运行正常(显示了评级的星型符号),但是每次刷新页面,都会有 2 秒的延迟。

4、重新编辑该文件,放开对 reviews 服务的调用增加一个半秒的请求超时(去掉timeout的注释)

5、重新应用该配置,还是执行第2步的命令,然后通过如下命令查看配置是否更新

kubectl get virtualservice -o yaml

6、再次刷新网页

这时候应该看到 1 秒钟就会返回,而不是之前的 2 秒钟,但 reviews 是不可用的(页面没有reviews的数据)

即使超时配置为半秒,响应仍需要 1 秒,是因为 productpage 服务中存在硬编码重试,因此它在返回之前调用 reviews 服务超时两次(重试)。

关于重试:直接参考文档

https://istio.io/v1.6/zh/docs/reference/config/networking/virtual-service/#HTTPRoute

https://istio.io/v1.6/zh/docs/reference/config/networking/virtual-service/#HTTPRetry

3.4.4、熔断

熔断器是 Istio 为创建具有弹性的微服务应用提供的有用的机制。在熔断器中,设置一个对服务中的单个主机调用的限制,例如并发连接的数量或对该主机调用失败的次数。一旦限制被触发,熔断器就会“跳闸”并停止连接到该主机。

使用熔断模式可以快速失败而不必让客户端尝试连接到过载或有故障的主机。

部署httpbin

httpbin是一个开源项目,使用Python+Flask编写,利用它可以测试各种HTTP请求和响应。官网:http://httpbin.org/

kubectl apply -f samples/httpbin/httpbin.yaml

该配置文件的内容为:

##################################################################################################
# httpbin service
##################################################################################################
apiVersion: v1
kind: ServiceAccount
metadata:
  name: httpbin
---
apiVersion: v1
kind: Service
metadata:
  name: httpbin
  labels:
    app: httpbin
spec:
  ports:
  - name: http
    port: 8000
    targetPort: 80
  selector:
    app: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpbin
      version: v1
  template:
    metadata:
      labels:
        app: httpbin
        version: v1
    spec:
      serviceAccountName: httpbin
      containers:
      - image: docker.io/kennethreitz/httpbin
        imagePullPolicy: IfNotPresent
        name: httpbin
        ports:
        - containerPort: 80
配置熔断器

创建一个目标熔断规则(DestinationRule),在调用 httpbin 服务时应用熔断设置:

kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: httpbin
spec:
  host: httpbin
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 1  #最大连接数
      http:
        http1MaxPendingRequests: 1  #http请求pending状态的最大请求数
        maxRequestsPerConnection: 1  #在一定时间内限制对后端服务发起的最大请求数
    outlierDetection:  #熔断设置
      consecutiveErrors: 1  #从连接池开始拒绝连接,已经连接失败的次数,当通过HTTP访问时,返回代码是502、503或504则视为错误。
      interval: 1s  #拒绝访问扫描的时间间隔,即在interval(1s)内连续发生1个consecutiveErrors错误,则触发服务熔断,格式是1h/1m/1s/1ms,但必须大于等于1ms。即分析是否需要剔除的频率,多久分析一次,默认10秒。
      baseEjectionTime: 3m  #最短拒绝访问时长。这个时间主机将保持拒绝访问,且如果决绝访问达到一定的次数。格式:1h/1m/1s/1ms,但必须大于等于1ms。实例被剔除后,至少多久不得返回负载均衡池,默认是30秒。
      maxEjectionPercent: 100  #服务在负载均衡池中被拒绝访问(被移除)的最大百分比,负载均衡池中最多有多大比例被剔除,默认是10%。
EOF

验证目标规则是否已正确创建:

kubectl get destinationrule httpbin -o yaml

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: httpbin
  ...
spec:
  host: httpbin
  trafficPolicy:
    connectionPool:
      http:
        http1MaxPendingRequests: 1
        maxRequestsPerConnection: 1
      tcp:
        maxConnections: 1
    outlierDetection:
      baseEjectionTime: 180.000s
      consecutiveErrors: 1
      interval: 1.000s
      maxEjectionPercent: 100
客户端

创建客户端程序以发送流量到 httpbin 服务。这是一个名为 Fortio 的负载测试客户的,其可以控制连接数、并发数及发送 HTTP 请求的延迟。通过 Fortio 能够有效的触发前面 在 DestinationRule 中设置的熔断策略。

  1. 向客户端注入 Istio Sidecar 代理,以便 Istio 对其网络交互进行管理:

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

    中间稍等一会,让客户端部署成功!!!

  2. 登入客户端 Pod 并使用 Fortio 工具调用 httpbin 服务。-curl 参数表明发送一次调用:

    $ FORTIO_POD=$(kubectl get pod | grep fortio | awk '{ print $1 }')
    $ kubectl exec -it $FORTIO_POD  -c fortio -- /usr/bin/fortio load -curl  http://httpbin:8000/get
    HTTP/1.1 200 OK
    server: envoy
    date: Tue, 16 Jan 2018 23:47:00 GMT
    content-type: application/json
    access-control-allow-origin: *
    access-control-allow-credentials: true
    content-length: 445
    x-envoy-upstream-service-time: 36
    
    {
      "args": {},
      "headers": {
        "Content-Length": "0",
        "Host": "httpbin:8000",
        "User-Agent": "istio/fortio-0.6.2",
        "X-B3-Sampled": "1",
        "X-B3-Spanid": "824fbd828d809bf4",
        "X-B3-Traceid": "824fbd828d809bf4",
        "X-Ot-Span-Context": "824fbd828d809bf4;824fbd828d809bf4;0000000000000000",
        "X-Request-Id": "1ad2de20-806e-9622-949a-bd1d9735a3f4"
      },
      "origin": "127.0.0.1",
      "url": "http://httpbin:8000/get"
    }
    

可以看到调用后端服务的请求已经成功!接下来,可以测试熔断。

触发熔断器

在 DestinationRule 配置中,定义了 maxConnections: 1 和 http1MaxPendingRequests: 1。 这些规则意味着,如果并发的连接和请求数超过一个,在 istio-proxy 进行进一步的请求和连接时,后续请求或 连接将被阻止。

  1. 发送并发数为 2 的连接(-c 2),请求 20 次(-n 20):

    [root@node1 istio-1.6.5]# kubectl exec -it $FORTIO_POD  -c fortio -- /usr/bin/fortio load -c 2 -qps 0 -n 20 -loglevel Warning http://httpbin:8000/get
    03:59:25 I logger.go:97> Log level is now 3 Warning (was 2 Info)
    Fortio 1.3.1 running at 0 queries per second, 2->2 procs, for 20 calls: http://httpbin:8000/get
    Starting at max qps with 2 thread(s) [gomax 2] for exactly 20 calls (10 per thread + 0)
    03:59:25 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    03:59:25 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    03:59:25 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    03:59:25 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    03:59:25 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    03:59:25 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    Ended after 79.166124ms : 20 calls. qps=252.63
    Aggregated Function Time : count 20 avg 0.0064311497 +/- 0.007472 min 0.000340298 max 0.032824602 sum 0.128622994
    # range, mid point, percentile, count
    >= 0.000340298 <= 0.001 , 0.000670149 , 10.00, 2
    > 0.001 <= 0.002 , 0.0015 , 20.00, 2
    > 0.002 <= 0.003 , 0.0025 , 40.00, 4
    > 0.003 <= 0.004 , 0.0035 , 60.00, 4
    > 0.004 <= 0.005 , 0.0045 , 65.00, 1
    > 0.006 <= 0.007 , 0.0065 , 80.00, 3
    > 0.012 <= 0.014 , 0.013 , 85.00, 1
    > 0.014 <= 0.016 , 0.015 , 90.00, 1
    > 0.016 <= 0.018 , 0.017 , 95.00, 1
    > 0.03 <= 0.0328246 , 0.0314123 , 100.00, 1
    # target 50% 0.0035
    # target 75% 0.00666667
    # target 90% 0.016
    # target 99% 0.0322597
    # target 99.9% 0.0327681
    Sockets used: 8 (for perfect keepalive, would be 2)
    Code 200 : 14 (70.0 %)
    Code 503 : 6 (30.0 %)
    Response Header Sizes : count 20 avg 161.15 +/- 105.5 min 0 max 231 sum 3223
    Response Body/Total Sizes : count 20 avg 668.15 +/- 279.6 min 241 max 852 sum 13363
    All done 20 calls (plus 0 warmup) 6.431 ms avg, 252.6 qps
    
    

    结果:

    Code 200 : 14 (70.0 %)
    Code 503 : 6 (30.0 %)
    
  2. 将并发连接数提高到 3 个:

    [root@node1 istio-1.6.5]# kubectl exec -it $FORTIO_POD  -c fortio -- /usr/bin/fortio load -c 3 -qps 0 -n 30 -loglevel Warning http://httpbin:8000/get
    04:01:42 I logger.go:97> Log level is now 3 Warning (was 2 Info)
    Fortio 1.3.1 running at 0 queries per second, 2->2 procs, for 30 calls: http://httpbin:8000/get
    Starting at max qps with 3 thread(s) [gomax 2] for exactly 30 calls (10 per thread + 0)
    04:01:42 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    04:01:42 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    04:01:42 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    04:01:42 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    04:01:42 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    04:01:42 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    04:01:42 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    04:01:42 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    04:01:42 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    04:01:42 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    04:01:42 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    04:01:42 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    04:01:42 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    04:01:42 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    04:01:42 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    04:01:42 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    04:01:42 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    04:01:42 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    04:01:42 W http_client.go:679> Parsed non ok code 503 (HTTP/1.1 503)
    Ended after 32.153704ms : 30 calls. qps=933.02
    Aggregated Function Time : count 30 avg 0.0019156712 +/- 0.001801 min 0.000270969 max 0.006581956 sum 0.057470135
    # range, mid point, percentile, count
    >= 0.000270969 <= 0.001 , 0.000635485 , 56.67, 17
    > 0.002 <= 0.003 , 0.0025 , 70.00, 4
    > 0.003 <= 0.004 , 0.0035 , 86.67, 5
    > 0.004 <= 0.005 , 0.0045 , 93.33, 2
    > 0.005 <= 0.006 , 0.0055 , 96.67, 1
    > 0.006 <= 0.00658196 , 0.00629098 , 100.00, 1
    # target 50% 0.000908871
    # target 75% 0.0033
    # target 90% 0.0045
    # target 99% 0.00640737
    # target 99.9% 0.0065645
    Sockets used: 20 (for perfect keepalive, would be 3)
    Code 200 : 11 (36.7 %)
    Code 503 : 19 (63.3 %)
    Response Header Sizes : count 30 avg 84.333333 +/- 110.8 min 0 max 230 sum 2530
    Response Body/Total Sizes : count 30 avg 464.66667 +/- 294 min 241 max 851 sum 13940
    All done 30 calls (plus 0 warmup) 1.916 ms avg, 933.0 qps
    

    可以看到,只有 36.7% 的请求成功,其余的均被熔断器拦截:

    Code 200 : 11 (36.7 %)
    Code 503 : 19 (63.3 %)
    
  3. 查询 istio-proxy 状态以了解更多熔断详情:

    [root@node1 istio-1.6.5]# kubectl exec $FORTIO_POD -c istio-proxy -- pilot-agent request GET stats | grep httpbin | grep pending
    cluster.outbound|8000||httpbin.default.svc.cluster.local.circuit_breakers.default.rq_pending_open: 0
    cluster.outbound|8000||httpbin.default.svc.cluster.local.circuit_breakers.high.rq_pending_open: 0
    cluster.outbound|8000||httpbin.default.svc.cluster.local.upstream_rq_pending_active: 0
    cluster.outbound|8000||httpbin.default.svc.cluster.local.upstream_rq_pending_failure_eject: 0
    cluster.outbound|8000||httpbin.default.svc.cluster.local.upstream_rq_pending_overflow: 72
    cluster.outbound|8000||httpbin.default.svc.cluster.local.upstream_rq_pending_total: 59
    

    可以看到 upstream_rq_pending_overflow59,这意味着,目前为止已有 59 个调用被标记为熔断。

清理
  1. 清理规则:

    $ kubectl delete destinationrule httpbin
    
  2. 下线 httpbin 服务和客户端:

    $ kubectl delete deploy httpbin fortio-deploy
    $ kubectl delete svc httpbin
    

3.4.5、可观测性

istio的可观测性体现在:指标度量,日志,分布式追踪,网格可视化等方面

网格可视化

我们可以将istio网格以可视化的方式呈现,基于 Web 的图形用户界面来查看网格和 Istio 配置对象的服务图,使我们的操作更方便(摆脱命令的困扰!!!)

在Istio中可以使用Kiali进行可视化的管理服务网格。Kiali官网:https://www.kiali.io/

Kiali的安装:在demo环境中已经默认安装了kiali,我们可以通过如下命令查看

kubectl -n istio-system get services
kubectl -n istio-system get pod
kubectl -n istio-system get svc kiali

1、要打开 Kiali UI,请在您的 Kubernetes 环境中执行以下命令:

[root@k8-master ~]# istioctl dashboard kiali --address 192.168.200.200
http://localhost:38022/kiali
Failed to open browser; open http://localhost:38022/kiali in your browser.

将流量发送到网格,有三种选择:

  • 在浏览器中访问 http://$GATEWAY_URL/productpage

  • 多次使用以下命令:

$ curl http://$GATEWAY_URL/productpage
  • 如果您在系统中安装了 watch 命令,请通过以下方式连续发送请求,时间间隔为1秒:
$ watch -n 1 curl -o /dev/null -s -w %{http_code} $GATEWAY_URL/productpage

使用该地址打开,注意替换localhost为address地址,登录用户名和密码均为admin

file

图表

file

查看流量分配的百分比:

file

请求统计数据,RPS数据(最小/最大的比值)

file

显示不同的图表类型,有四种类型:

  • App
    • 图形类型将一个应用程序的所有版本聚合到一个图形节点中。 file
  • Versioned App
    • 图类型显示每个应用程序版本的节点,但是特定应用程序的所有版本都组合在一起。 file
  • Workload
    • 图类型显示了服务网格中每个工作负载的节点。 file
  • Service
    • 图类型显示网格中每个服务的节点。 file
路由加权

默认路由规则会平均分配浏览到每个可用节点,通过kiali可以可行可视化的调节:

第一步,查看servers列表:

file

第二步,进入reviews服务:

file

第三步,删除原有路由规则:

file

第四步,创建权重的规则:

file

默认情况:

file

进行调整:

file

保存操作。

第五步,通过watch执行一段时间,观察效果:

file

可以看到,分配到reviews的v1、v2、v3的百分比发生了变化。

查看工作负载

file

入站、出站信息:

file

日志信息:

file

入站指标信息:

file

出站指标信息:

file

3.5、istio实战

0、从资料中找到项目itcast-service-mesh2.zip,导入ide,制作movie.tar

1、将movie.tar分别上传到k8-node1(201主机)k8-master(200主机),然后分别解压

2、在k8-node1主机上,执行build-images.sh脚本,先构建镜像(注意是在node节点上)

3、在k8-master主机上,在movie/movie-istio目录下先进行部署

kubectl apply -f movie.yaml

等待启动

kubectl get service -o wide

#等待所有pod都成为运行状态
kubectl get pod
kubectl get pod -o wide

4、登录neo4j导入初始化数据,访问:http://192.168.200.201:31001/browser/ (访问的地址是node节点的ip)

file

用:neo4jneo4j登录,第一次登录后修改密码为:neo4j123,切记,切记,切记!

5、导入初始数据,从资料中找到电影数据.txt,在neo4j中执行,执行完成后查询

match (n) return n

file

6、创建初始目标规则,执行如下命令

kubectl apply -f destination-rule-all.yaml

7、创建网关,执行如下命令

kubectl apply -f movie-gateway.yaml

8、获取网关访问地址,通过如下命令完成

export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')
export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}')
export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT

echo $GATEWAY_URL

9、根据输出的地址访问,比如:http://192.168.200.201:31557/index

file

进行测试,反复刷新几次,可以看到评分部分,红/黑 进行切换。

10、将流量全部导向评分的 v2 版本,只显示红色评分,则可以执行下面这个规则

kubectl apply -f virtual-service-rating-v2.yaml

再次查看网页的评分显示内容!!!

本文由传智教育博学谷 - 狂野架构师教研团队发布 转载请注明出处!