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 | 内存 | 硬盘 |
---|---|---|---|---|---|
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 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 命令行工具。
访问 Istio release 页面下载与您操作系统对应的安装文件。在 macOS 或 Linux 系统中,也可以通过以下命令下载最新版本的 Istio:
$ curl -L https://istio.io/downloadIstio | sh -
可用指定版本:
$ curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.6.5 sh -
切换到 Istio 包所在目录下。例如:Istio 包名为
istio-1.6.5
,则:$ cd istio-1.6.5
安装目录包含如下内容:
samples/
目录下,有示例应用程序bin/
目录下,包含istioctl
的客户端文件。istioctl
工具用于手动注入 Envoy sidecar 代理。
将
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。
安装
demo
配置$ istioctl manifest apply --set profile=demo
选择要安装的组件在
istio-1.6.5/manifests/profiles
中!为了验证是否安装成功,需要先确保以下 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-ingressgateway
的EXTERNAL-IP
将显示为<pending>
状态。请使用服务的NodePort
或 端口转发来访问网关。请确保关联的 Kubernetes pod 已经部署,并且
STATUS
为Running
:[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
. 这个微服务会调用details
和reviews
两个微服务,用来生成页面。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、启动应用服务
- 进入 Istio 安装目录。
Istio 默认自动注入 Sidecar. 请为
default
命名空间打上标签istio-injection=enabled
:$ kubectl label namespace default istio-injection=enabled
使用
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)。
在实际部署中,微服务版本的启动过程需要持续一段时间,并不是同时完成的。
确认所有的服务和 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
要确认 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 来实现这个目标。
为应用程序定义 Ingress 网关:
$ kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
确认网关创建完成:
$ kubectl get gateway NAME AGE bookinfo-gateway 32s
设置访问网关的
INGRESS_HOST
和INGRESS_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}')
设置
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
是包含星级评分功能的版本。
运行以下命令以启用基于用户的路由:
$ kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml
确认规则已创建:
$ 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
在 Bookinfo 应用程序的
/productpage
上,以用户jason
身份登录。刷新浏览器。你看到了什么?星级评分显示在每个评论旁边。
以其他用户身份登录(选择您想要的任何名称)。
刷新浏览器。现在星星消失了。这是因为除了 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...
https://istio.io/v1.6/zh/docs...
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 中设置的熔断策略。
向客户端注入 Istio Sidecar 代理,以便 Istio 对其网络交互进行管理:
$ kubectl apply -f <(istioctl kube-inject -f samples/httpbin/sample-client/fortio-deploy.yaml)
中间稍等一会,让客户端部署成功!!!
登入客户端 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 进行进一步的请求和连接时,后续请求或 连接将被阻止。
发送并发数为 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 %)
将并发连接数提高到 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 %)
查询
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_overflow
值59
,这意味着,目前为止已有 59 个调用被标记为熔断。
清理
清理规则:
$ kubectl delete destinationrule httpbin
下线 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
图表
查看流量分配的百分比:
请求统计数据,RPS数据(最小/最大的比值)
显示不同的图表类型,有四种类型:
App
- 图形类型将一个应用程序的所有版本聚合到一个图形节点中。
- 图形类型将一个应用程序的所有版本聚合到一个图形节点中。
Versioned App
- 图类型显示每个应用程序版本的节点,但是特定应用程序的所有版本都组合在一起。
- 图类型显示每个应用程序版本的节点,但是特定应用程序的所有版本都组合在一起。
Workload
- 图类型显示了服务网格中每个工作负载的节点。
- 图类型显示了服务网格中每个工作负载的节点。
Service
- 图类型显示网格中每个服务的节点。
- 图类型显示网格中每个服务的节点。
路由加权
默认路由规则会平均分配浏览到每个可用节点,通过kiali可以可行可视化的调节:
第一步,查看servers列表:
第二步,进入reviews服务:
第三步,删除原有路由规则:
第四步,创建权重的规则:
默认情况:
进行调整:
保存操作。
第五步,通过watch执行一段时间,观察效果:
可以看到,分配到reviews的v1、v2、v3的百分比发生了变化。
查看工作负载
入站、出站信息:
日志信息:
入站指标信息:
出站指标信息:
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/... (访问的地址是node节点的ip)
用:neo4j
,neo4j
登录,第一次登录后修改密码为:neo4j123
,切记,切记,切记!
5、导入初始数据,从资料中找到电影数据.txt
,在neo4j
中执行,执行完成后查询
match (n) return n
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/...
进行测试,反复刷新几次,可以看到评分部分,红/黑 进行切换。
10、将流量全部导向评分的 v2 版本,只显示红色评分,则可以执行下面这个规则
kubectl apply -f virtual-service-rating-v2.yaml
再次查看网页的评分显示内容!!!
本文由传智教育博学谷 - 狂野架构师教研团队发布,转载请注明出处!
如果本文对您有帮助,欢迎关注和点赞;如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。