微服务是用于构建应用程序的架构风格,一个大的系统可由一个或者多个服务组成,微服务架构可将应用拆分成多个核心功能,每个功能都被称为一项服务,可以单独构建和部署,这意味着各项服务在工作和出现故障的时候不会相互影响。简单来说,微服务架构是把一个大的系统按照不同的业务单元分解成多个职责单一的小系统,并利用简单的方法使多个小系统相互协作,组合成一个大系统,各个小的系统是独立部署的,它们之间是松耦合的。
springCloud 来源于 SpringSource ,具有 Spring 社区的强大背景支持,还有 Netflix强大的后盾与技术输出。
为开发者提供了快速构建分布式系统的通用模型的工具,主要是针对 java 的开发框架。
Dubbo 是一个阿里巴巴开源出来的一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,以及 SOA 服务治理方案。其核心包含:
集群容错: 提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持;
自动发现: 基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。
istio 是开源的 Service Mesh(服务网格),Service Mesh 翻译成中文就是服务网格。
作为用于微服务服务聚合层管理的新锐项目,是 Google、IBM、Lyft(海外共享出行公司、Uber 劲敌) 首个共同联合开源的项目,提供了统一的连接,安全,管理和监控微服务的方案。
Istio 是一个与 Kubernetes 紧密结合的适用于云原生场景下用于服务治理的开放平台。
服务治理包括:
连接(Connect)、安全(Secure)、策略执行(Control)和可观察性(Observe)。
在 Kubernetes 环境中,Ingress controller 用于管理进入集群的流量。在 Istio 服务网格中 Istio Ingress Gateway 承担相应的角色,它使用新的配置模型(Gateway 和VirtualServices)完成流量管理的功能。
通过下图做一个总的描述:
1、用户向某端口发出请求。
2、负载均衡器监听端口,并将请求转发到集群中的某个节点上。Istio Ingress Gateway Service会监听集群节点端口的请求。
3、Istio Ingress Gateway Service 将请求交给 Istio Ingress Gateway Pod 处理。IngressGateway Pod 通过 Gateway 和 VirtualService 配置规则处理请求。其中,Gateway 用来配置端口、协议和证书;VirtualService 用来配置一些路由信息(找到请求对应处理的服务 AppService)。
4、Istio Ingress Gateway Pod 将请求转给 App Service。
5、最终的请求会交给 App Service 关联的 App Deployment 处理。
VirtualService 是 Istio 流量治理的一个核心配置,可以说是 Istio 流量治理中最重要、最复杂的。VirtualService 在形式上表示一个虚拟服务,将满足条件的流量都转发到对应的服务后端,这个服务后端可以是一个服务,也可以是在 DestinationRule 中定义的服务的子集。
destination rule 是 istio 流量路由功能的重要组成部分。一个 virtual service 可以看作是如何将流量分发给特定的目的地,然后调用 destination rule 来配置分发到该目的地的流量。destinationrule 在 virtual service 的路由规则之后起作用(即在 virtual service 的 math->route-destination 之后起作用,此时流量已经分发到真实的 service 上),应用于真实的目的地。
可以使用 destination rule 来指定命名的服务子集,例如根据版本对服务的实例进行分组,然后通过 virtual service 的路由规则中的服务子集将控制流量分发到不同服务的实例中。
流量控制流程:
Gateway->VirtaulService->TCP/HTTP Router->DestinationWeight->Subset:Port
到官方网站下载安装istio的压缩包: https://github.com/istio/istio
将下载的软件包上传到k8s控制节点,手动解压。
tar zxvf istio-1.13.1.tar.gz
将解压包下/bin下的istioctl拷贝到/usr/bin
cd /root/istio-1.13.1/bin/
cp -ar istioctl /usr/bin/
用到了如下镜像,可提前到dockerhub拉取
istio/examples-bookinfo-details-v1:1.15.0
istio/examples-bookinfo-productpage-v1:1.16.2
istio/examples-bookinfo-ratings-v1:1.15.0
istio/examples-bookinfo-reviews-v1:1.15.0
istio/examples-bookinfo-reviews-v2:1.15.0
istio/examples-bookinfo-reviews-v3:1.15.0
kennethreitz/httpbin:latest
istio/pilot:1.13.1
istio/proxyv2:1.13.1
istioctl install --set profile=demo -y
看到如下,说明初始化完成:
✔ Istio core installed
✔ Istiod installed
✔ Egress gateways installed
✔ Ingress gateways installed
✔ Installation complete
kubectl get pods -n istio-system
显示如下,说明部署成功
istio会作为k8s api进行工作,在指定名称空间打上标签istio-injection=enabled后,后续在该名称空间下创建的pod会自动注入sidecar来进行流量控制。
以default名称空间举例:
kubectl label namespace default istio-injection=enabled
这是在安装istio时自带的一个demo,下面我们通过安装在线书店来理解istio的工作原理。
该应用由四个单独的微服务构成,这个应用模仿在线书店的一个分类,显示一本书的信息,页面上会显示一本书的描述,书籍的细节(ISBN、页数等),以及关于这本书的一些评论。
Bookinfo 应用中的几个微服务是由不同的语言编写的。这些服务对 istio 并无依赖,但是构成了一个有代表性的服务网格的例子:它由多个服务、多个语言构成,并且 reviews 服务具有多个版本。
要在 Istio 中运行这一应用,无需对应用自身做出任何改变。 只要简单的在 Istio 环境中对服务进行配置和运行,具体一点说就是把 Envoy sidecar 注入到每个 pod 之中。 最终的部署结果将如图所示:
所有的微服务都和 Envoy sidecar 集成在一起,被集成服务所有的出入流量都被 envoy sidecar 所劫持,这样就为外部控制准备了所需的 Hook,然后就可以利用 Istio 控制平面为应用提供服务路由、遥测数据收集以及策略实施等功能。
上面我们已经为 default 命名空间打上标签 istio-injection=enabled ,接下来只需要使用demo自带的yaml文件部署应用即可。
cd istio-1.13.1
vim samples/bookinfo/platform/kube/bookinfo.yaml
修改名为productpage-v1的deployment用到的镜像为 1.16.2 版 ,如下图所示:
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
上面的命令会启动全部的四个服务,其中也包括了 reviews 服务的三个版本(v1、v2 以及 v3)。
kubectl get svc
kubectl get pods
kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
kubectl get gateway # 查看网关
kubectl get svc istio-ingressgateway -n istio-system
如果 EXTERNAL-IP 值已设置,说明环境正在使用外部负载均衡,可以用其为 ingress gateway 提供服务。 如果 EXTERNAL-IP 值为(或持续显示), 说明环境没有提供外部负载均衡,无法使用 ingress gateway。在这种情况下,你可以使用服务的 NodePort(图中32273) 访问网关。
用浏览器打开网址 http://$GATEWAY_URL/productpage,也就是192.168.1.63:32273/productpage 来浏览应用的 Web 页面。如果刷新几次应用的页面,就会看到productpage 页面中会随机展示 reviews 服务的不同版本的效果(红色、黑色的星形或者没有显示)。
sh samples/bookinfo/platform/kube/cleanup.sh
kubectl get virtualservices # 无虚拟服务
kubectl get destinationrules # 无目标路由
kubectl get gateway # 无网关
kubectl get pods # bookinfo相关pod已删
断路器是创建弹性微服务应用程序的重要模式。断路器使应用程序可以适应网络故障和延迟等网络不良影响。
[root@s1 ~]# cd istio-1.13.1
[root@s1 istio-1.13.1]# cat samples/httpbin/httpbin.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: httpbin
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
service: 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
上面yaml文件中定义了一个sa、service、deployment。
kubectl apply -f samples/httpbin/httpbin.yaml #应用该yaml文件
创建一个destination.yaml文件定义目标规则,内容如下:
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: httpbin
spec:
host: httpbin #定义对应后端服务名称
trafficPolicy:
connectionPool: #连接池配置
tcp:
maxConnections: 1 #tcp最大连接数1
http:
http1MaxPendingRequests: 1 #http连接最大等待数1
maxRequestsPerConnection: 1 #连接池中每个连接最多处理1个请求后就关闭
outlierDetection: #异常检测配置
# 下面配置表示1s内发生1次错误则触发服务熔断,驱逐100%的请求3m。
consecutiveGatewayErrors: 1 #连续错误数
interval: 1s #错误扫描间隔
baseEjectionTime: 3m #基本驱逐时间 3 分钟
maxEjectionPercent: 100 #最大驱逐百分比 100%
kubectl apply -f destination.yaml #应用定义的规则
创建一个客户端以将流量发送给 httpbin 服务。该客户端是一个简单的负载测试客户端,Fortio 可以控制连接数,并发数和 HTTP 调用延迟。使用此客户端来“跳闸”在 DestinationRule 中设置的断路器策略。
[root@s1 istio-1.13.1]# kubectl apply -f samples/httpbin/sampleclient/fortio-deploy.yaml
[root@s1 istio-1.13.1]# kubectl get pods
通过 kubectl 执行下面的命令,使用 fortio 客户端工具调用 httpbin做一次请求:
# pod名称写自己实际观察到的
kubectl exec fortio-deploy-5f5f9cd9d8-x4kb9 -c fortio -- /usr/bin/fortio curl http://httpbin:8000/get
我们刚才在 DestinationRule 设置中,指定了 maxConnections: 1 和 http1MaxPendingRequests: 1。这些规则表明,如果超过一个以上的连接并发请求,则 istio-proxy 在为进一步的请求和连接打开路由时,会触发断路器。
现以两个并发连接(-c 2)和发送 20 个请求(-n 20)调用服务,观察情况:
kubectl exec fortio-deploy-5f5f9cd9d8-x4kb9 -c fortio -- /usr/bin/fortio load -c 2 -qps 0 -n 20 -loglevel Warning http://httpbin:8000/get
在生产环境中经常会碰到由于调用方等待下游的响应过长,堆积大量的请求阻塞了自身服务,造成雪崩的情况,通过超时处理来避免由于无限期等待造成的故障,进而增强服务的可用性,Istio 使用虚拟服务来优雅实现超时处理。
下面例子模拟客户端调用 nginx,nginx 将请求转发给 tomcat。nginx 服务设置了超时时间为 2秒,如果超出这个时间就不在等待,返回超时错误。tomcat 服务设置了响应时间延迟 10 秒,任何请求都需要等待 10 秒后才能返回。client 通过访问 nginx 服务去反向代理 tomcat 服务,由于 tomcat服务需要 10 秒后才能返回,但 nginx 服务只等待 2 秒,所以客户端会提示超时错误。
yaml文件内容如下:
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-tomcat
labels:
server: nginx
app: web
spec:
replicas: 1
selector:
matchLabels:
server: nginx
app: web
template:
metadata:
name: nginx
labels:
server: nginx
app: web
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat
labels:
server: tomcat
app: web
spec:
replicas: 1
selector:
matchLabels:
server: tomcat
app: web
template:
metadata:
name: tomcat
labels:
server: tomcat
app: web
spec:
containers:
- name: tomcat
image: docker.io/kubeguide/tomcat-app:v1
imagePullPolicy: IfNotPresent
kubectl apply -f nginx-deployment.yaml
kubectl get pods
yaml文件内容如下:
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
server: nginx
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: tomcat-svc
spec:
selector:
server: tomcat
ports:
- name: http
port: 8080
targetPort: 8080
protocol: TCP
kubectl apply -f nginx-tomcat-svc.yaml
kubectl get svc
yaml文件内容如下:
---
# nginx的虚拟服务
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: nginx-vs #虚拟服务名称
spec:
hosts:
- nginx-svc #虚拟主机名称
http:
- route: #定义路由规则
- destination:
host: nginx-svc #指向nginx service
timeout: 2s #调用超时时间2s
---
# tomcat的虚拟服务
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: tomcat-vs
spec:
hosts:
- tomcat-svc
http:
- fault: #定义故障注入策略
delay:
percentage:
value: 100
fixedDelay: 10s #延时10s响应
route:
- destination:
host: tomcat-svc
进入nginx容器
kubectl exec -it nginx-tomcat-7649c6ff85-bw6st -- sh
修改nginx配置
vi /etc/nginx/conf.d/default.conf
修改完成后如下图所示:
检查配置文件是否有语法错误,如没有则重载nginx。
nginx -t
nginx -s reload
运行一个busybox,访问nginx服务。
kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox -- sh
time wget -q -O - http://nginx-svc
每隔 2 秒,由于 nginx 服务的超时时间到了而 tomcat 未有响应,则提示返回超时错误。
再访问tomcat服务,验证故障注入效果。
time wget -q -O - http://tomcat-svc
Istio 重试机制就是如果调用服务失败,Envoy 代理尝试连接服务的最大次数。而默认情况下,Envoy 代理在失败后并不会尝试重新连接服务,除非我们启动 Istio 重试机制。
下面例子模拟客户端调用 nginx,nginx 将请求转发给 tomcat。tomcat 通过故障注入而中止对外服务,nginx 设置如果访问 tomcat 失败则会重试 3 次。
删除原定义的nginx、tomcat的虚拟服务
kubectl delete -f virtual-tomcat.yaml
重新定义虚拟服务,yaml文件内容如下:
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: nginx-vs
spec:
hosts:
- nginx-svc
http:
- route:
- destination:
host: nginx-svc
retries: #定义重试策略
attempts: 3 #重试次数
perTryTimeout: 2s #每个重试的超时时间
#该设置说明调用 nginx-svc 的 k8s service,在初始调用失败后最多重试 3 次来连接到服务子集,每个重试都有 2 秒的超时。
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: tomcat-vs
spec:
hosts:
- tomcat-svc
http:
- fault:
abort: #模拟服务不可用
percentage:
value: 100
httpStatus: 503 #100%返回503
route:
- destination:
host: tomcat-svc
kubectl apply -f virtual-attempt.yaml #应用虚拟服务
运行一个busybox对nginx服务做请求
kubectl run -it busybox --image busybox:1.28 --restart=Never --rm -- sh
wget -q -O - http://nginx-svc
查看nginx pod里istio-proxy的日志信息
kubectl logs nginx-tomcat-7649c6ff85-bw6st -c istio-proxy