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

Posted 博学谷狂野架构师

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了超详细教程,一文入门Istio架构原理及实战应用相关的知识,希望对你有一定的参考价值。

Istio简介

2.1、istio架构

实际上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内存硬盘
node1192.168.31.106master2核4GB100GB
node2192.168.31.107node2核4GB100GB
node3192.168.31.108node2核4GB100GB

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 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 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

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

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

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 个红色星形图标来显示评分信息。

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

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

3.3.2、部署应用

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

所有的微服务都和 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
    

  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 来控制版本的路由。

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不再切换样式。

按照不同用户身份路由

接下来,您将更改路由配置,以便将来自特定用户的所有流量路由到特定服务版本。在这,来自名为 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: <

    『Python开发实战菜鸟教程』实战篇:一文带你了解人脸识别应用原理及手把手教学实现自己的人脸识别项目

    文章目录

    0x01:引子

    0x02:环境搭建

    0x03:开发实战 

    1.实现人脸检测标记

    2.人脸特征点提取

    3.人脸识别验证

    0x04:后记


    开源GitHub地址--> https://github.com/xiaosongshine/dlib_face_recognition

    推荐补充阅读:『Python开发实战菜鸟教程』工具篇:手把手教学使用VSCode开发Python

    0x01:引子

     

    Dlib是一个深度学习开源工具,基于C++开发,也支持Python开发接口,功能类似于TensorFlow与PyTorch。但是由于Dlib对于人脸特征提取支持很好,有很多训练好的人脸特征提取模型供开发者使用,所以Dlib人脸识别开发很适合做人脸项目开发。

    上面所说的人脸识别开发,主要是指人脸验证,就是输入两张人脸照片,系统会对比输出0或者1,代表判断是否是同一个人。一般的人脸识别开发可以简单分为1.人脸特征建模2.使用人脸特征模型进行验证(其实还应包括人脸对齐等,这些也可以划分到1中)。使用Dlib进行开发时,我们直接可以使用训练好的人脸特征提取模型,主要的工作就变成了如何进行人脸的验证。

    人脸的验证其实就是计算相似度,同一个人的相似度就会大,不同的人就会比较小。可以采用余弦相似度或者欧式距离来计算相似度。其中余弦相似度就是计算角度,欧式距离就是指平方差。都可以用来表示两个特征的相似度(距离)。

     

    0x02:环境搭建

    安装可以参考我的这篇博客:[深度学习工具]·极简安装Dlib人脸识别库,下面说一下需要注意的点::

    此博文针对Windows10安装,其他平台可以仿照这个步骤来安装

    • 安装Miniconda

    使用conda指令来安装Dlib库,使用Miniconda与Anaconda都可以,我习惯用Miniconda,简单占用内存小。
    推荐使用清华源,下载安装,选择合适的平台版本。python==3.6

    • 安装dlib
      注意一定要以管理员身份进入CMD,执行(如果是Linux Mac 就使用 sudo)
    conda install -c conda-forge dlib
    
    • 需要imageio 库,可以使用下述命令安装
    conda install imageio
    

    0x03:开发实战 

     

    1.实现人脸检测标记

    face_test.py

    import dlib
    from imageio import imread
    import glob
    
    
    detector = dlib.get_frontal_face_detector()
    win = dlib.image_window()
    
    path = "f1.jpg"
    img = imread(path)
    dets = detector(img)
    print('检测到了 %d 个人脸' % len(dets))
    for i, d in enumerate(dets):
    	print('- %d:Left %d Top %d Right %d Bottom %d' % (i, d.left(), d.top(), d.right(), d.bottom()))
    
    win.clear_overlay()
    win.set_image(img)
    win.add_overlay(dets)
    dlib.hit_enter_to_continue()
    

    代码很简单,通过imread读取照片,然后进行检测,输出结果为dets的list,有几张人脸就会有几个item, 每个item都有.left(), .top(), .right(), .bottom()四个元素,代表人脸框的四个边界位置。最后通过win.add_overlay(dets)可以将标记的框显示在原图上。

    原始照片


    输出照片

    其实我们就可以使用这个功能做一个简单的应用,用来检测图片或者视频中人脸的个数。

    2.人脸特征点提取

    在实战1的基础上添加人脸特征提取功能。

    import dlib
    from imageio import imread
    import glob
    
    
    detector = dlib.get_frontal_face_detector()
    win = dlib.image_window()
    
    predictor_path = 'shape_predictor_68_face_landmarks.dat'
    predictor = dlib.shape_predictor(predictor_path)
    
    path = "f2.jpg"
    img = imread(path)
    dets = detector(img)
    print('检测到了 %d 个人脸' % len(dets))
    
    
    for i, d in enumerate(dets):
    	print('- %d: Left %d Top %d Right %d Bottom %d' % (i, d.left(), d.top(), d.right(), d.bottom()))
    	shape = predictor(img, d)
    		# 第 0 个点和第 1 个点的坐标
    	print('Part 0: , Part 1: '.format(shape.part(0), shape.part(1)))
    win.clear_overlay()
    win.set_image(img)
    win.add_overlay(dets)
    win.add_overlay(shape)
    dlib.hit_enter_to_continue()
    

    这段代码就是在test.py基础上加入了shape_predictor功能,使之可以在检测出人脸基础上,找到人脸的68个特征点。反映在图中就是蓝色的线。

     

    原始图片

    输出图片

    注意运行这段代码需要这个文件predictor_path = 'shape_predictor_68_face_landmarks.dat',我会放在我的github中,方便大家下载使用。

    3.人脸识别验证

    在第二步的基础上,我们再进一步,实现将人脸提取为特征向量,从而我们就可以对特征向量进行比对来实现人脸的验证,这里采用的是对比欧式距离的方法。

    face_recognition.py

    import dlib
    from imageio import imread
    import glob
    import numpy as np
    
    detector = dlib.get_frontal_face_detector()
    predictor_path = 'shape_predictor_68_face_landmarks.dat'
    predictor = dlib.shape_predictor(predictor_path)
    face_rec_model_path = 'dlib_face_recognition_resnet_model_v1.dat'
    facerec = dlib.face_recognition_model_v1(face_rec_model_path)
    
    
    def get_feature(path):
    	img = imread(path)
    	dets = detector(img)
    	print('检测到了 %d 个人脸' % len(dets))
    	# 这里假设每张图只有一个人脸
    	shape = predictor(img, dets[0])
    	face_vector = facerec.compute_face_descriptor(img, shape)
    	return(face_vector)
    
    def distance(a,b):
    	a,b = np.array(a), np.array(b)
    	sub = np.sum((a-b)**2)
    	add = (np.sum(a**2)+np.sum(b**2))/2.
    	return sub/add
    
    path_lists1 = ["f1.jpg","f2.jpg"]
    path_lists2 = ["赵丽颖照片.jpg","赵丽颖测试.jpg"]
    
    feature_lists1 = [get_feature(path) for path in path_lists1]
    feature_lists2 = [get_feature(path) for path in path_lists2]
    
    print("feature 1 shape",feature_lists1[0].shape)
    
    out1 = distance(feature_lists1[0],feature_lists1[1])
    out2 = distance(feature_lists2[0],feature_lists2[1])
    
    print("diff distance is",out1)
    print("same distance is",out2)
    
    out1 = distance(feature_lists1[0],feature_lists1[1])
    out2 = distance(feature_lists2[0],feature_lists2[1])
    
    

    输出结果

    检测到了 1 个人脸
    检测到了 1 个人脸
    检测到了 1 个人脸
    检测到了 1 个人脸
    
    feature 1 shape (128, 1)
    
    diff distance is 0.254767715912
    same distance is 0.0620976363391

    我们可以看出,每张人脸都被提取为了128维的向量,我们可以理解为128维的坐标(xyz是三维,128维就是有128个轴组成),我们下面需要做的就是计算两个特征的距离,设定好合适的阈值,小于这个阈值则识别为同一个人。代码正确运行需要这个文件face_rec_model_path = 'dlib_face_recognition_resnet_model_v1.dat',我已经放在自己的github中,方便大家使用。

    我们从上面测试的结果可以看出,不同的距离为0.25,同一个人为0.06,阈值就可以先设置为其间的一个值。我这里先设置为0.09,这个阈值也是需要大量数据来计算的,选择的准则为使错误识别为最低。

    下面我们把阈值设置为0.09,来测试系统能否区分出不同的人:在face_recognition.py加入下面代码

    def classifier(a,b,t = 0.09):
    	if(distance(a,b)<=t):
    		ret = True
    	else :
    		ret = False
    	return(ret)
    
    print("f1 is 赵丽颖",classifier(feature_lists1[0],feature_lists2[1]))
    print("f2 is 赵丽颖",classifier(feature_lists1[1],feature_lists2[1]))
    print("赵丽颖照片.jpg is 赵丽颖测试.jpg",classifier(feature_lists2[0],feature_lists2[1]))

    对比图片组1:f1 vs 赵丽颖1

    对比图片组2:f2 vs 赵丽颖1

    对比图片组3:赵丽颖2 vs 赵丽颖1

     

    输出结果

     

    f1 is 赵丽颖 False
    f2 is 赵丽颖 False
    赵丽颖照片.jpg is 赵丽颖测试.jpg True

    从上面可以看出,已基本满足对人脸区分的功能,如果如要实用化则需要继续调优阈值与代码,调优的准则就是选择合适的阈值使错误识别为最低。

     

    0x04:总结

     

    这篇文章带着大家了解人脸识别应用原理及手把手教学如何实现自己的人脸识别项目,如果想更深入了解人脸识别算法及应用,可以参阅笔者往期博文。

    下面是开源地址,完整代码及数据在上面,欢迎Star及Fork:

    项目GitHub地址--> https://github.com/xiaosongshine/dlib_face_recognition

    这个博客对你有用的话欢迎收藏转发,也麻烦可爱又爱学的你能赏个赞,菜小宋更博不易,在这里谢过啦。

    如果你想学习更多开发技巧与AI算法,欢迎搜索关注笔者公众号“简明AI”,和爱学习讨论的小伙伴一起交流学习。

     
     

     

    以上是关于超详细教程,一文入门Istio架构原理及实战应用的主要内容,如果未能解决你的问题,请参考以下文章

    超详细入门精讲数据仓库原理&实战 一步一步搭建数据仓库 内附相应实验代码和镜像数据和脚本

    ❤️超详细PWN新手入门教程❤️《二进制各种漏洞原理实战分析总结》

    『Python开发实战菜鸟教程』实战篇:一文带你了解人脸识别应用原理及手把手教学实现自己的人脸识别项目

    『Python开发实战菜鸟教程』实战篇:一文带你了解人脸识别应用原理及手把手教学实现自己的人脸识别项目

    『Python开发实战菜鸟教程』实战篇:一文带你了解人脸识别应用原理及手把手教学实现自己的人脸识别项目

    『Python开发实战菜鸟教程』实战篇:一文带你了解人脸识别应用原理及手把手教学实现自己的人脸识别项目