如果出现无法载图的情况,请检查与github的连通性
概述 Istio是一个开源的服务网格,为kubernetes和其他平台上的微服务架构提供统一的、灵活的网络通信和管理方式。
具有 代理注入,服务发现,负载均衡,流量管理,故障恢复和安全性功能 注入Envoy代理到没一个微服务的pod中; 将流量动态转发到可用的实例,支持多种服务发现机制; 根据不同需求进行流量分发与负载均衡; 支持流量切分,A/B测试,金丝雀发布;
功能:
1.快速失败返回:目标服务不可用时不再尝试等待请求,而是快速返回错误,避免长时间等待 2.熔断:在服务的通信中防止故障扩散,不会影响到整个应用程序 3.恢复:先使用一小部分流量,如果正常了会逐步关闭熔断
Istio架构与组件 控制节点组件为istiod,istiod包括Pilot、citadel、galley: 1.Pilot从服务注册中心获取服务和实例信息,并为Envoy生成配置。Envoy根据Pilot的信息,完成具体流量的转发
2.citadel负责Istio的身份和凭据管理;用于为服务生成和分发TLS证书
3.galley是Istio的配置管理组件,负责验证、分发配置给其他组件。当有配置信息出现变化时,同步给其他组件。
数据节点组件Envoy Pilot-agent: 4.Envoy是Istio的代理容器,如果开启了Istio,在创建服务时会创建代理容器,与朱容器属于同个pod,代理进出pod的流量,并根据外部请求规则作用于主容器中
5.ingressgateway入口网关,作为整个网络的入口,所有外部请求都集中到入口网关,然后将其引导到内部服务
6.egressgateway出口网关,作为整个网络的出口
功能与原理 1.自动注入 创建pod时自动调用sidecar代理服务,自动将sidecar代理容器注入到pod中
2.流量拦截 通过设置iptables规则,envoy会拦截业务容器的入口和出口流量。 留出frontend服务的流量会被frontend服务侧的sidecar拦截,当流量到达forecast时,inbound流量被forecast服务侧的sidecar拦截
3.服务发现 服务发起方envoy调用控制组件Pilot的发现接口,得到forecast服务的各项实例地址
4.负载均衡
5.流量治理 envoy从Pilot中获取流量治理规则,根据不同特征,将不同流量分发到forecast服务的不同版本
6.访问安全 在frontend的envoy与forecast的envoy访问时,会进行加密
7.服务监测 frontend服务与forecast服务的访问都会连接mixer上报访问数据,mixer将数据转发给对应的监控后端
8.策略执行 通过mixer来控制服务之间的访问,进行速率控制等操作
9.外部访问 外部访问入口gateway,通过gateway访问frontend
Istio部署,开启与关闭 环境 k8s版本 1.28 Istio版本 1.21 安装需要的镜像: docker.io/istio/pilot:1.21.0 docker.io/istio/proxyv2:1.21.0 可以直接拉取也可以在github上下载
安装 1 2 3 4 5 6 7 8 9 10 11 12 tar xf istio-1.21.0-linux-amd64.tar.gz cd istio-1.21.0/cp bin/istioctl /bin/istioctl install --set profile=demo -y 安装模式profile=demo:适应生产环境,安装3个pod profile=default:最小配置,仅包含istiod与ingressgateway(一般测试用 profile=minimal:最小化安装,仅包含istiod(一般测试用 istioctl manifest generate --set profile=demo | kubectl delete -f -
关闭istio自动注入 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 kubectl get ns --show-labels NAME STATUS AGE LABELS default Active 35d istio-injection=enabled,kubernetes.io/metadata.name=default devlopment Active 8d kubernetes.io/metadata.name=devlopment istio-system Active 7d2h kubernetes.io/metadata.name=istio-system jenkins-k8s Active 9d kubernetes.io/metadata.name=jenkins-k8s kube-node-lease Active 35d kubernetes.io/metadata.name=kube-node-lease kube-public Active 35d kubernetes.io/metadata.name=kube-public kube-system Active 35d kubernetes.io/metadata.name=kube-system letsencrypt-staging Active 5d22h kubernetes.io/metadata.name=letsencrypt-staging monitor-sa Active 31d kubernetes.io/metadata.name=monitor-sa 因为default ns下有istio-injection=enabled, 默认在defaultns下创建pod,就会自动注入代理容器 kubectl label ns default istio-injection-
Istio使用——以bookinfo应用为例 bookinfo在线书店,是istio自带的一个案例 分为四个单独的微服务: 1.productpage会调用details和reviews两个微服务用来生成界面 2.details包含书籍信息 3.review包含书籍评论 4.ratings包含书籍评级信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 kubectl label ns default istio-injection=enabled cd /root/Istio/istio-1.21.0/samples/bookinfo/platform/kubekubectl apply -f bookinfo.yaml /root/Istio/istio-1.21.0/samples/bookinfo/networking kubectl apply -f bookinfo-gateway.yaml kubectl get gateway NAME AGE bookinfo-gateway 35s kubectl get virtualservice NAME GATEWAYS HOSTS AGE bookinfo ["bookinfo-gateway" ] ["*" ] 54s kubectl get svc -n istio-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE istio-egressgateway ClusterIP 10.102.255.76 <none> 80/TCP,443/TCP 64m istio-ingressgateway LoadBalancer 10.107.22.5 <pending> 15021:31606/TCP,80:32510/TCP,443:32060/TCP,31400:32635/TCP,15443:31893/TCP 64m istiod ClusterIP 10.105.99.16 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 64m 浏览器访问 http://apiserver:32510/productpage
Istio灰度发布 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 创建两个pod,分别打上不同的标签 labels: app: v1 apply: canary labels: app: v2 apply: canary apiVersion: v1 kind: Service metadata: name: canary labels: apply: canary spec: selector: apply: canary ports: - protocol: TCP port: 80 targetPort: 80 apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: canary-gateway spec: selector: istio: ingressgateway servers: - port: number: 80 name: http protocol: HTTP hosts: - "*" apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: canary spec: hosts: - "*" gateways: - canary-gateway http: - route: - destination: host: canary.default.svc.cluster.local subset: v1 weight: 90 - destination: host: canary.default.svc.cluster.local subset: v2 weight: 10 apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: canary spec: host: canary.default.svc.cluster.local subsets: - name: v1 labels: app: v1 - name: v2 labels: app: v2 逐渐修改weight比例,将流量逐步向v2转移
熔断 所需镜像:docker.io/kong/httpbin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 /root/istio/istio-1.21.0/samples/httpbin kubectl apply -f httpbin.yaml 所用镜像:docker.io/kong/httpbin cat > fuse-policy.yaml <<EOF apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: httpbin spec: host: httpbin #绑定httpbin的service trafficPolicy: #策略 connectionPool: #熔断连接池,设置了两个 tcp: #限制tcp链接的数量 maxConnections: 1 #httpbin的最多并发1个连接 http: #限制http的连接数 http1MaxPendingRequests: 1 #每个连接最大挂起请求数 maxRequestsPerConnection: 1 #每个连接最大处理请求数 outlierDetection: consecutiveGatewayErrors: 1 #错误1次网关错误即异常 interval: 1s #探测间隔 baseEjectionTime: 3m maxEjectionPercent: 100 #100%拒绝连接 EOF kubectl apply -f fuse-policy.yaml /root/istio/istio-1.21.0/samples/httpbin/sample-client kubectl apply -f fortio-deploy.yaml kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE fortio ClusterIP 10.102.153.6 <none> 8080/TCP 28h httpbin ClusterIP 10.97.84.16 <none> 8000/TCP 28h kubectl get pods NAME READY STATUS RESTARTS AGE fortio-deploy-77fd47587d-mrfl9 2/2 Running 0 27h httpbin-86b8ffc5ff-7mjmn 2/2 Running 0 28h 所用镜像:fortio/fortio:latest_release kubectl exec fortio-deploy-77fd47587d-mrfl9 -c fortio \ -- /usr/bin/fortio curl http://httpbin:8000/get 返回状态码200,正常 kubectl exec fortio-deploy-77fd47587d-mrfl9 -c fortio \ -- /usr/bin/fortio load -c 2 -qps 0 -n 20 -loglevel Warning \ http://httpbin:8000/get -c 2: 指定并发连接数为 2。这表示在测试期间,将会模拟 2 个并发请求。 -qps 0: 指定每秒请求数为 0。这表示在测试期间,将以最大速率发送请求,即不限制每秒请求数。 -n 20: 指定总请求数为 20。这表示在测试期间,将发送总共 20 个请求 ... Code 200 : 14 (70.0 %) Code 503 : 6 (30.0 %) ...
超时 在生产环境中经常会碰到由于调用方等待下游的响应过长,堆积大量的请求阻塞了自身服务,造成雪崩的情况,通过通过超时处理来避免由于无限期等待造成的故障,进而增强服务的可用性,Istio 使用虚拟服务来优雅实现超时处理。
配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 nginx-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx 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:1.14-alpine imagePullPolicy: IfNotPresent tomcat-deployment.yaml 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 nginx-tomcat-svc.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 virtual-tomcat.yaml 虚拟服务 apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: nginx-vs spec: hosts: - nginx-svc http: - route: - destination: host: nginx-svc timeout : 2s --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: tomcat-vs spec: hosts: - tomcat-svc http: - fault: delay: percentage: value: 100 fixedDelay: 10s route: - destination: host: tomcat-svc
应用案例pod文件 nginx-deployment.yaml tomcat-deployment.yaml nginx-tomcat-svc.yaml
创建虚拟服务virtual-tomcat.yaml: 设置应用到nginx的svc,请求超时时间2s 设置应用到tomcat的svc,调用请求时,延迟10s
这种情况下一定会报错,用这种方法来手动模拟故障
进入容器修改nginx配置文件,将流量代理到svc上,流量会通过定义好的虚拟服务进入 在虚拟服务中添加相应规则,就可以防止下游响应时间过长的问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 kubectl get pods NAME READY STATUS RESTARTS AGE fortio-deploy-77fd47587d-mrfl9 2/2 Running 4 (54m ago) 30h httpbin-86b8ffc5ff-7mjmn 2/2 Running 4 (54m ago) 31h nginx-67dffc45d-nf2rh 2/2 Running 4 (54m ago) 63m tomcat-659d5845d4-5fcpx 2/2 Running 4 (54m ago) 63m kubectl exec -it nginx-67dffc45d-nf2rh -- sh location / { proxy_pass http://tomcat-svc:8080; proxy_http_version 1.1; }
测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 测试 kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox -- sh time wget -q -O - http://nginx-svc wget: server returned error: HTTP/1.1 504 Gateway Timeout Command exited with non-zero status 1 real 0m 2.00s user 0m 0.00s sys 0m 0.00s time wget -q -O - http://tomcat-svc:8080 ...超时
重试 Istio 重试机制就是如果调用服务失败,Envoy 代理尝试连接服务的最大次数。而默认情况下,Envoy 代理在失败后并不会尝试重新连接服务,除非我们启动 Istio 重试机制。
(默认情况下不会开启重试功能)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 kubectl delete -f virtual-tomcat.yaml 写一个用来重试的virtualservice ... - route: - destination: host: nginx-svc retries: attempts: 3 perTryTimeout: 2s ... http: - fault: abort: percentage: value: 100 httpStatus: 503 route: - destination: host: tomcat-svc ... kubectl apply -f virtual-attempt.yaml kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox -- sh wget -q -O - http://nginx-svc wget: server returned error: HTTP/1.1 503 Service Unavailable 查看日志: kubectl logs -f nginx-67dffc45d-nf2rh -c istio-proxy
补充————熔断、压测与性能评估原则 最佳实践 假设k8s集群有100个节点,每个节点是100vCPU、100g内存,基于deployment部署了3个pod,运行的服务是web服务,三个pod跑在不同的节点上,每个pod最多占用6g内存6vcpu,每个pod最多的请求数是100万,三个pod前端有个四层代理,通过istio熔断机制作用在三个pod前端的四层代理上,那熔断参数值如何设置?
1.maxConnections:
假设每个 Pod 最多支持 6 个 vCPU,可以设置 maxConnections 为 80(稍微小于节点的 CPU 核心数,考虑到其他系统进程的资源使用)。
2.http1MaxPendingRequests:
假设你的应用在正常负载情况下,每秒请求数在 1000 到 5000 之间,可以设置 http1MaxPendingRequests 为 500,以确保连接不会积压过多的请求。
3.maxRequestsPerConnection:
假设你的应用的响应时间在 10 毫秒左右,你可以设置 maxRequestsPerConnection 为 100,这样每个连接可以处理 100 个请求后再关闭。
请注意,以上数值仅供参考,实际设置需要根据你的应用特性和性能测试结果来确定。压力测试是一个迭代的过程,你可能需要多次测试和优化,找到最适合你应用的参数设置。
同时,还需要考虑 Istio 熔断参数的设置。你可以根据之前提到的测试结果和分析,根据实际情况设置 consecutiveGatewayErrors 和 interval 等参数,以实现对代理层的熔断保护。
参数设置 最终的参数设置是一个动态平衡的过程,需要结合多方面因素综合考虑。建议在测试环境中进行实际的压力测试和性能评估,以找到最优的参数配置,确保你的应用在高负载下能够稳定运行。
maxConnections:TCP 连接数的最大值。它限制了单个 Pod 上的 TCP 连接数量。这个值需要根据你的 Web 服务的并发量和每个请求的连接数来确定。
http1MaxPendingRequests:HTTP1 的最大挂起请求数。当超过这个数值时,新的请求将被拒绝,直到有请求处理完成。这个值也要根据你的 Web 服务的并发量和 HTTP1 的特性来确定。
maxRequestsPerConnection:每个连接的最大请求数。当超过这个数值时,连接将被关闭,新的请求将使用新的连接。这个值可以用于限制长时间保持的连接。
outlierDetection:异常检测参数。这个参数用于检测异常的流量,并触发熔断机制。以下是 outlierDetection 参数的两个属性:
consecutiveGatewayErrors:连续网关错误数。当连续出现这么多次网关错误时,熔断将会触发。
interval:检测的时间间隔。在这个时间间隔内进行异常检测。
针对具体的数值,取决于你的应用实际情况和性能测试的结果。一般来说,你需要进行压力测试和性能评估,观察系统在不同负载下的表现,然后逐步调整熔断参数,找到适合你应用的最佳数值。
压测和性能评估步骤 进行压力测试和性能评估是确保应用在不同负载下能够正常运行的关键步骤。这些测试有助于发现系统的瓶颈、性能问题和资源需求,以便做出相应的优化和调整。下面是进行压力测试和性能评估的一般步骤:
1.确定测试目标和场景:
确定要测试的具体目标,例如检查服务的响应时间、并发连接数、吞吐量等。
设计不同负载场景,包括正常负载和峰值负载,以及可能的异常情况。
2.配置测试环境:
创建与生产环境尽可能相似的测试环境。这包括硬件、网络、操作系统、Kubernetes集群等。
3.选择合适的工具:
选择适合的应用和测试需求的性能测试工具。一些常见的工具包括Apache JMeter、Vegeta、wrk、Siege等。
4.设置测试参数:
针对不同的测试场景,设置合理的压力测试参数,包括请求频率、并发用户数、连接数等。
5.执行压力测试:
运行压力测试工具,模拟不同负载场景,收集性能数据。
6.监控系统指标:
在测试过程中,监控系统的各项指标,包括CPU利用率、内存使用、网络流量、响应时间等。
7.分析结果:
根据测试结果,分析系统在不同负载下的表现。发现瓶颈、性能问题和资源瓶颈。
8.优化和调整:
根据分析结果,进行优化和调整。可能需要调整Kubernetes资源配额、调整服务配置、进行代码优化等。
9.重复测试:
如果进行了优化和调整,需要再次进行压力测试,以验证改进效果。
10.容灾测试(可选):
在一定负载下,模拟节点故障或服务失效等情况,验证集群的容错能力和自愈能力。
11.综合评估:
结合所有测试结果,综合评估系统的性能和稳定性,确保满足预期的负载和性能要求。
注意事项:
在进行压力测试时,确保测试环境和生产环境隔离,以免对生产系统造成影响。
选择适当的负载测试场景,覆盖典型的使用情况和预期的峰值负载。
记录测试结果和分析过程,方便后续回溯和对比。
压力测试应该在非高峰期进行,以免影响正常用户的体验。