在本模块中,我们将部署名为 Online Boutique 的微服务应用程序,试用 Istio 的不同功能。
Online Boutique 是一个云原生微服务演示应用程序。Online Boutique 是一个由 10 个微服务组成的应用。该应用是一个基于 Web 的电子商务应用,用户可以浏览商品,将其添加到购物车,并购买商品。
二.系统环境
服务器版本 | docker软件版本 | Kubernetes(k8s)集群版本 | Istio软件版本 | CPU架构 |
---|---|---|---|---|
CentOS Linux release 7.4.1708 (Core) | Docker version 20.10.12 | v1.21.9 | Istio1.14 | x86_64 |
三.创建Kubernetes(k8s)集群
3.1 创建Kubernetes(k8s)集群
我们需要一套可以正常运行的Kubernetes集群,关于Kubernetes(k8s)集群的安装部署,可以查看博客《Centos7 安装部署Kubernetes(k8s)集群》https://www.cnblogs.com/renshengdezheli/p/16686769.html
3.2 Kubernetes集群环境
Kubernetes集群架构:k8scloude1作为master节点,k8scloude2,k8scloude3作为worker节点
服务器 | 操作系统版本 | CPU架构 | 进程 | 功能描述 |
---|---|---|---|---|
k8scloude1/192.168.110.130 | CentOS Linux release 7.4.1708 (Core) | x86_64 | docker,kube-apiserver,etcd,kube-scheduler,kube-controller-manager,kubelet,kube-proxy,coredns,calico | k8s master节点 |
k8scloude2/192.168.110.129 | CentOS Linux release 7.4.1708 (Core) | x86_64 | docker,kubelet,kube-proxy,calico | k8s worker节点 |
k8scloude3/192.168.110.128 | CentOS Linux release 7.4.1708 (Core) | x86_64 | docker,kubelet,kube-proxy,calico | k8s worker节点 |
四.安装istio
4.1 安装Istio
Istio最新版本为1.15,因为我们Kubernetes集群版本为1.21.9,所以我们选择安装Istio 1.14版本。
[root@k8scloude1 ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8scloude1 Ready control-plane,master 288d v1.21.9
k8scloude2 Ready <none> 288d v1.21.9
k8scloude3 Ready <none> 288d v1.21.9
我们将安装 Istio的demo 配置文件,因为它包含所有的核心组件,启用了跟踪和日志记录,便于学习不同的 Istio 功能。
关于istio的详细安装部署,请查看博客《Istio(二):在Kubernetes(k8s)集群上安装部署istio1.14》https://www.cnblogs.com/renshengdezheli/p/16836404.html
也可以按照如下使用 GetMesh CLI 在Kubernetes集群中安装 Istio 。
下载 GetMesh CLI:
curl -sL https://istio.tetratelabs.io/getmesh/install.sh | bash
安装 Istio:
getmesh istioctl install --set profile=demo
Istio安装完成后,创建一个命名空间online-boutique,新的项目就部署在online-boutique命名空间下,给命名空间online-boutique设置上 istio-injection=enabled
标签,启用sidecar 自动注入。
#创建命名空间online-boutique
[root@k8scloude1 ~]# kubectl create ns online-boutique
namespace/online-boutique created
#切换命名空间
[root@k8scloude1 ~]# kubens online-boutique
Context "kubernetes-admin@kubernetes" modified.
Active namespace is "online-boutique".
#让命名空间online-boutique启用sidecar 自动注入
[root@k8scloude1 ~]# kubectl label ns online-boutique istio-injection=enabled
namespace/online-boutique labeled
[root@k8scloude1 ~]# kubectl get ns -l istio-injection --show-labels
NAME STATUS AGE LABELS
online-boutique Active 16m istio-injection=enabled,kubernetes.io/metadata.name=online-boutique
五.部署online Boutique应用
5.1 部署 Online Boutique 应用
在集群和 Istio 准备好后,我们可以克隆 Online Boutique 应用库了。istio和k8s集群版本如下:
[root@k8scloude1 ~]# istioctl version
client version: 1.14.3
control plane version: 1.14.3
data plane version: 1.14.3 (1 proxies)
[root@k8scloude1 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8scloude1 Ready control-plane,master 283d v1.21.9
k8scloude2 Ready <none> 283d v1.21.9
k8scloude3 Ready <none> 283d v1.21.9
使用git克隆代码仓库:
#安装git
[root@k8scloude1 ~]# yum -y install git
#查看git版本
[root@k8scloude1 ~]# git version
git version 1.8.3.1
#创建online-boutique目录,项目放在该目录下
[root@k8scloude1 ~]# mkdir online-boutique
[root@k8scloude1 ~]# cd online-boutique/
[root@k8scloude1 online-boutique]# pwd
/root/online-boutique
#git克隆代码
[root@k8scloude1 online-boutique]# git clone https://github.com/GoogleCloudPlatform/microservices-demo.git
正克隆到 'microservices-demo'...
remote: Enumerating objects: 8195, done.
remote: Counting objects: 100% (332/332), done.
remote: Compressing objects: 100% (167/167), done.
remote: Total 8195 (delta 226), reused 241 (delta 161), pack-reused 7863
接收对象中: 100% (8195/8195), 30.55 MiB | 154.00 KiB/s, done.
处理 delta 中: 100% (5823/5823), done.
[root@k8scloude1 online-boutique]# ls
microservices-demo
前往 microservices-demo
目录,istio-manifests.yaml,kubernetes-manifests.yaml是主要的安装文件
[root@k8scloude1 online-boutique]# cd microservices-demo/
[root@k8scloude1 microservices-demo]# ls
cloudbuild.yaml CODEOWNERS docs istio-manifests kustomize pb release SECURITY.md src
CODE_OF_CONDUCT.md CONTRIBUTING.md hack kubernetes-manifests LICENSE README.md renovate.json skaffold.yaml terraform
[root@k8scloude1 microservices-demo]# cd release/
[root@k8scloude1 release]# ls
istio-manifests.yaml kubernetes-manifests.yaml
查看所需的镜像,可以在k8s集群的worker节点提前下载镜像
关于gcr.io镜像的下载方式可以查看博客《轻松下载k8s.gcr.io,gcr.io,quay.io镜像 》https://www.cnblogs.com/renshengdezheli/p/16814395.html
[root@k8scloude1 release]# ls
istio-manifests.yaml kubernetes-manifests.yaml
[root@k8scloude1 release]# vim kubernetes-manifests.yaml
#可以看到安装此项目需要13个镜像,gcr.io表示是Google的镜像
[root@k8scloude1 release]# grep image kubernetes-manifests.yaml
image: gcr.io/google-samples/microservices-demo/emailservice:v0.4.0
image: gcr.io/google-samples/microservices-demo/checkoutservice:v0.4.0
image: gcr.io/google-samples/microservices-demo/recommendationservice:v0.4.0
image: gcr.io/google-samples/microservices-demo/frontend:v0.4.0
image: gcr.io/google-samples/microservices-demo/paymentservice:v0.4.0
image: gcr.io/google-samples/microservices-demo/productcatalogservice:v0.4.0
image: gcr.io/google-samples/microservices-demo/cartservice:v0.4.0
image: busybox:latest
image: gcr.io/google-samples/microservices-demo/loadgenerator:v0.4.0
image: gcr.io/google-samples/microservices-demo/currencyservice:v0.4.0
image: gcr.io/google-samples/microservices-demo/shippingservice:v0.4.0
image: redis:alpine
image: gcr.io/google-samples/microservices-demo/adservice:v0.4.0
[root@k8scloude1 release]# grep image kubernetes-manifests.yaml | uniq | wc -l
13
#在k8s集群的worker节点提前下载镜像,以k8scloude2为例
#把gcr.io换为gcr.lank8s.cn,比如gcr.io/google-samples/microservices-demo/emailservice:v0.4.0换为gcr.lank8s.cn/google-samples/microservices-demo/emailservice:v0.4.0
[root@k8scloude2 ~]# docker pull gcr.lank8s.cn/google-samples/microservices-demo/emailservice:v0.4.0
。。。。。。
其他那些镜像就按照此方法下载......
。。。。。。
[root@k8scloude2 ~]# docker pull gcr.lank8s.cn/google-samples/microservices-demo/adservice:v0.4.0
#镜像下载之后,使用sed把kubernetes-manifests.yaml文件中的gcr.io修改为gcr.lank8s.cn
[root@k8scloude1 release]# sed -i 's/gcr.io/gcr.lank8s.cn/' kubernetes-manifests.yaml
#此时kubernetes-manifests.yaml文件中的镜像就全被修改了
[root@k8scloude1 release]# grep image kubernetes-manifests.yaml
image: gcr.lank8s.cn/google-samples/microservices-demo/emailservice:v0.4.0
image: gcr.lank8s.cn/google-samples/microservices-demo/checkoutservice:v0.4.0
image: gcr.lank8s.cn/google-samples/microservices-demo/recommendationservice:v0.4.0
image: gcr.lank8s.cn/google-samples/microservices-demo/frontend:v0.4.0
image: gcr.lank8s.cn/google-samples/microservices-demo/paymentservice:v0.4.0
image: gcr.lank8s.cn/google-samples/microservices-demo/productcatalogservice:v0.4.0
image: gcr.lank8s.cn/google-samples/microservices-demo/cartservice:v0.4.0
image: busybox:latest
image: gcr.lank8s.cn/google-samples/microservices-demo/loadgenerator:v0.4.0
image: gcr.lank8s.cn/google-samples/microservices-demo/currencyservice:v0.4.0
image: gcr.lank8s.cn/google-samples/microservices-demo/shippingservice:v0.4.0
image: redis:alpine
image: gcr.lank8s.cn/google-samples/microservices-demo/adservice:v0.4.0
#istio-manifests.yaml 文件没有镜像
[root@k8scloude1 release]# vim istio-manifests.yaml
[root@k8scloude1 release]# grep image istio-manifests.yaml
创建 Kubernetes 资源:
[root@k8scloude1 release]# pwd
/root/online-boutique/microservices-demo/release
[root@k8scloude1 release]# ls
istio-manifests.yaml kubernetes-manifests.yaml
#在online-boutique命名空间创建k8s资源
[root@k8scloude1 release]# kubectl apply -f /root/online-boutique/microservices-demo/release/kubernetes-manifests.yaml -n online-boutique
检查所有 Pod 都在运行:
[root@k8scloude1 release]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
adservice-9c6d67f96-txrsb 2/2 Running 0 85s 10.244.112.151 k8scloude2 <none> <none>
cartservice-6d7544dc98-86p9c 2/2 Running 0 86s 10.244.251.228 k8scloude3 <none> <none>
checkoutservice-5ff49769d4-5p2cn 2/2 Running 0 86s 10.244.112.148 k8scloude2 <none> <none>
currencyservice-5f56dd7456-lxjnz 2/2 Running 0 85s 10.244.251.241 k8scloude3 <none> <none>
emailservice-677bbb77d8-8ndsp 2/2 Running 0 86s 10.244.112.156 k8scloude2 <none> <none>
frontend-7d65884948-hnmh6 2/2 Running 0 86s 10.244.112.154 k8scloude2 <none> <none>
loadgenerator-77ffcbd84d-hhh2w 2/2 Running 0 85s 10.244.112.147 k8scloude2 <none> <none>
paymentservice-88f465d9d-nfxnc 2/2 Running 0 86s 10.244.112.149 k8scloude2 <none> <none>
productcatalogservice-8496676498-6zpfk 2/2 Running 0 86s 10.244.112.143 k8scloude2 <none> <none>
recommendationservice-555cdc5c84-j5w8f 2/2 Running 0 86s 10.244.251.227 k8scloude3 <none> <none>
redis-cart-6f65887b5d-42b8m 2/2 Running 0 85s 10.244.251.236 k8scloude3 <none> <none>
shippingservice-6ff94bd6-tm6d2 2/2 Running 0 85s 10.244.251.242 k8scloude3 <none> <none>
创建 Istio 资源:
[root@k8scloude1 microservices-demo]# pwd
/root/online-boutique/microservices-demo
[root@k8scloude1 microservices-demo]# ls istio-manifests/
allow-egress-googleapis.yaml frontend-gateway.yaml frontend.yaml
[root@k8scloude1 microservices-demo]# kubectl apply -f ./istio-manifests
serviceentry.networking.istio.io/allow-egress-googleapis created
serviceentry.networking.istio.io/allow-egress-google-metadata created
gateway.networking.istio.io/frontend-gateway created
virtualservice.networking.istio.io/frontend-ingress created
virtualservice.networking.istio.io/frontend created
部署了一切后,我们就可以得到入口网关的 IP 地址并打开前端服务:
[root@k8scloude1 microservices-demo]# INGRESS_HOST="$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')"
[root@k8scloude1 microservices-demo]# echo "$INGRESS_HOST"
192.168.110.190
[root@k8scloude1 microservices-demo]# kubectl get service -n istio-system istio-ingressgateway -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
istio-ingressgateway LoadBalancer 10.107.131.65 192.168.110.190 15021:30093/TCP,80:32126/TCP,443:30293/TCP,31400:30628/TCP,15443:30966/TCP 27d app=istio-ingressgateway,istio=ingressgateway
在浏览器中打开 INGRESS_HOST
,你会看到前端服务,浏览器访问http://192.168.110.190/,如下图所示:
我们需要做的最后一件事是删除 frontend-external
服务。frontend-external
服务是一个 LoadBalancer 服务,它暴露了前端。由于我们正在使用 Istio 的入口网关,我们不再需要这个 LoadBalancer 服务了。
删除frontend-external服务,运行:
[root@k8scloude1 ~]# kubectl get svc | grep frontend-external
frontend-external LoadBalancer 10.102.0.207 192.168.110.191 80:30173/TCP 4d15h
[root@k8scloude1 ~]# kubectl delete svc frontend-external
service "frontend-external" deleted
[root@k8scloude1 ~]# kubectl get svc | grep frontend-external
Online Boutique 应用清单还包括一个负载发生器,它正在生成对所有服务的请求——这是为了让我们能够模拟网站的流量。
六.部署可观察性工具
6.1 部署可观察性工具
接下来,我们将部署可观察性、分布式追踪、数据可视化工具,下面两种方法任选一种;
关于prometheus,grafana,kiali,zipkin更详细的安装方法可以查看博客《Istio(三):服务网格istio可观察性:Prometheus,Grafana,Zipkin,Kiali》https://www.cnblogs.com/renshengdezheli/p/16836943.html
#方法一:
[root@k8scloude1 ~]# kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.14/samples/addons/prometheus.yaml
[root@k8scloude1 ~]# kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.14/samples/addons/grafana.yaml
[root@k8scloude1 ~]# kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.14/samples/addons/kiali.yaml
[root@k8scloude1 ~]# kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.14/samples/addons/extras/zipkin.yaml
#方法二:下载istio安装包istio-1.14.3-linux-amd64.tar.gz安装分析工具
[root@k8scloude1 ~]# ls istio* -d
istio-1.14.3 istio-1.14.3-linux-amd64.tar.gz
[root@k8scloude1 ~]# cd istio-1.14.3/
[root@k8scloude1 addons]# pwd
/root/istio-1.14.3/samples/addons
[root@k8scloude1 addons]# ls
extras grafana.yaml jaeger.yaml kiali.yaml prometheus.yaml README.md
[root@k8scloude1 addons]# kubectl apply -f prometheus.yaml
[root@k8scloude1 addons]# kubectl apply -f grafana.yaml
[root@k8scloude1 addons]# kubectl apply -f kiali.yaml
[root@k8scloude1 addons]# ls extras/
prometheus-operator.yaml prometheus_vm_tls.yaml prometheus_vm.yaml zipkin.yaml
[root@k8scloude1 addons]# kubectl apply -f extras/zipkin.yaml
如果你在安装 Kiali 的时候发现以下错误
No matches for kind "MonitoringDashboard" in version "monitoring.kiali.io/v1alpha1"
请重新运行以上命令。
prometheus,grafana,kiali,zipkin被安装在istio-system命名空间下,我们可以使用 getmesh istioctl dashboard kiali
打开 Kiali界面。
我们使用另外一种方法打开Kiali界面:
#可以看到prometheus,grafana,kiali,zipkin被安装在istio-system命名空间下
[root@k8scloude1 addons]# kubectl get pod -n istio-system
NAME READY STATUS RESTARTS AGE
grafana-6c5dc6df7c-cnc9w 1/1 Running 2 27h
istio-egressgateway-58949b7c84-k7v6f 1/1 Running 8 10d
istio-ingressgateway-75bc568988-69k8j 1/1 Running 6 3d21h
istiod-84d979766b-kz5sd 1/1 Running 14 10d
kiali-5db6985fb5-8t77v 1/1 Running 0 3m25s
prometheus-699b7cc575-dx6rp 2/2 Running 8 2d21h
zipkin-6cd5d58bcc-hxngj 1/1 Running 1 17h
#可以看到kiali这个service的类型为ClusterIP,外部环境访问不了
[root@k8scloude1 addons]# kubectl get service -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
grafana NodePort 10.100.151.232 <none> 3000:31092/TCP 27h
istio-egressgateway ClusterIP 10.102.56.241 <none> 80/TCP,443/TCP 10d
istio-ingressgateway LoadBalancer 10.107.131.65 192.168.110.190 15021:30093/TCP,80:32126/TCP,443:30293/TCP,31400:30628/TCP,15443:30966/TCP 10d
istiod ClusterIP 10.103.37.59 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 10d
kiali ClusterIP 10.109.42.120 <none> 20001/TCP,9090/TCP 7m42s
prometheus NodePort 10.101.141.187 <none> 9090:31755/TCP 2d21h
tracing ClusterIP 10.101.30.10 <none> 80/TCP 17h
zipkin NodePort 10.104.85.78 <none> 9411:30350/TCP 17h
#修改kiali这个service的类型为NodePort,这样外部环境就可以访问kiali了
#把type: ClusterIP 修改为 type: NodePort即可
[root@k8scloude1 addons]# kubectl edit service kiali -n istio-system
service/kiali edited
#现在kiali这个service的类型为NodePort,浏览器输入物理机ip:30754即可访问kiali网页了
[root@k8scloude1 addons]# kubectl get service -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
grafana NodePort 10.100.151.232 <none> 3000:31092/TCP 27h
istio-egressgateway ClusterIP 10.102.56.241 <none> 80/TCP,443/TCP 10d
istio-ingressgateway LoadBalancer 10.107.131.65 192.168.110.190 15021:30093/TCP,80:32126/TCP,443:30293/TCP,31400:30628/TCP,15443:30966/TCP 10d
istiod ClusterIP 10.103.37.59 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 10d
kiali NodePort 10.109.42.120 <none> 20001:30754/TCP,9090:31573/TCP 8m42s
prometheus NodePort 10.101.141.187 <none> 9090:31755/TCP 2d21h
tracing ClusterIP 10.101.30.10 <none> 80/TCP 17h
zipkin NodePort 10.104.85.78 <none> 9411:30350/TCP 17h
k8scloude1机器的地址为192.168.110.130,我们可以在浏览器中打开 http://192.168.110.130:30754
,进入 kiali,kiali首页如下:
在online-boutique命名空间点击Graph,查看服务的拓扑结构
下面是 Boutique 图表在 Kiali 中的样子:
该图向我们展示了服务的拓扑结构,并将服务的通信方式可视化。它还显示了入站和出站的指标,以及通过连接 Jaeger 和 Grafana(如果安装了)的追踪。图中的颜色代表服务网格的健康状况。红色或橙色的节点可能需要注意。组件之间的边的颜色代表这些组件之间的请求的健康状况。节点形状表示组件的类型,如服务、工作负载或应用程序。
七.流量路由
7.1 流量路由
我们已经建立了一个新的 Docker 镜像,它使用了与当前运行的前端服务不同的标头。让我们看看如何部署所需的资源并将一定比例的流量路由到不同的前端服务版本。
在我们创建任何资源之前,让我们删除现有的前端部署(kubectl delete deploy frontend
)
[root@k8scloude1 ~]# kubectl get deploy | grep frontend
frontend 1/1 1 1 4d21h
[root@k8scloude1 ~]# kubectl delete deploy frontend
deployment.apps "frontend" deleted
[root@k8scloude1 ~]# kubectl get deploy | grep frontend
重新创建一个前端deploy,名字还是frontend,但是指定了一个版本标签设置为 original
。yaml文件如下:
[root@k8scloude1 ~]# vim frontend-original.yaml
[root@k8scloude1 ~]# cat frontend-original.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
selector:
matchLabels:
app: frontend
version: original
template:
metadata:
labels:
app: frontend
version: original
annotations:
sidecar.istio.io/rewriteAppHTTPProbers: "true"
spec:
containers:
- name: server
image: gcr.lank8s.cn/google-samples/microservices-demo/frontend:v0.2.1
ports:
- containerPort: 8080
readinessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8080
httpHeaders:
- name: "Cookie"
value: "shop_session-id=x-readiness-probe"
livenessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8080
httpHeaders:
- name: "Cookie"
value: "shop_session-id=x-liveness-probe"
env:
- name: PORT
value: "8080"
- name: PRODUCT_CATALOG_SERVICE_ADDR
value: "productcatalogservice:3550"
- name: CURRENCY_SERVICE_ADDR
value: "currencyservice:7000"
- name: CART_SERVICE_ADDR
value: "cartservice:7070"
- name: RECOMMENDATION_SERVICE_ADDR
value: "recommendationservice:8080"
- name: SHIPPING_SERVICE_ADDR
value: "shippingservice:50051"
- name: CHECKOUT_SERVICE_ADDR
value: "checkoutservice:5050"
- name: AD_SERVICE_ADDR
value: "adservice:9555"
- name: ENV_PLATFORM
value: "gcp"
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
创建deploy
[root@k8scloude1 ~]# kubectl apply -f frontend-original.yaml
deployment.apps/frontend created
#deploy创建成功
[root@k8scloude1 ~]# kubectl get deploy | grep frontend
frontend 1/1 1 1 43s
#pod也正常运行
[root@k8scloude1 ~]# kubectl get pod | grep frontend
frontend-ff47c5568-qnzpt 2/2 Running 0 105s
现在我们准备创建一个 DestinationRule,定义两个版本的前端——现有的(original
)和新的(v1
)。
[root@k8scloude1 ~]# vim frontend-dr.yaml
[root@k8scloude1 ~]# cat frontend-dr.yaml
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: frontend
spec:
host: frontend.online-boutique.svc.cluster.local
subsets:
- name: original
labels:
version: original
- name: v1
labels:
version: 1.0.0
创建DestinationRule
[root@k8scloude1 ~]# kubectl apply -f frontend-dr.yaml
destinationrule.networking.istio.io/frontend created
[root@k8scloude1 ~]# kubectl get destinationrule
NAME HOST AGE
frontend frontend.online-boutique.svc.cluster.local 12s
接下来,我们将更新 VirtualService,并指定将所有流量路由到子集。在这种情况下,我们将把所有流量路由到原始版本original的前端。
[root@k8scloude1 ~]# vim frontend-vs.yaml
[root@k8scloude1 ~]# cat frontend-vs.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: frontend-ingress
spec:
hosts:
- '*'
gateways:
- frontend-gateway
http:
- route:
- destination:
host: frontend.online-boutique.svc.cluster.local
port:
number: 80
subset: original
更新 VirtualService 资源
[root@k8scloude1 ~]# kubectl apply -f frontend-vs.yaml
virtualservice.networking.istio.io/frontend-ingress created
[root@k8scloude1 ~]# kubectl get virtualservice
NAME GATEWAYS HOSTS AGE
frontend ["frontend.default.svc.cluster.local"] 5d14h
frontend-ingress ["frontend-gateway"] ["*"] 14s
#修改frontend这个virtualservice的hosts为frontend.online-boutique.svc.cluster.local
[root@k8scloude1 ~]# kubectl edit virtualservice frontend
virtualservice.networking.istio.io/frontend edited
[root@k8scloude1 ~]# kubectl get virtualservice
NAME GATEWAYS HOSTS AGE
frontend ["frontend.online-boutique.svc.cluster.local"] 5d14h
frontend-ingress ["frontend-gateway"] ["*"] 3m24s
现在我们将 VirtualService 配置为将所有进入的流量路由到 original
子集,我们可以安全地创建新的前端部署。
[root@k8scloude1 ~]# vim frontend-v1.yaml
[root@k8scloude1 ~]# cat frontend-v1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend-v1
spec:
selector:
matchLabels:
app: frontend
version: 1.0.0
template:
metadata:
labels:
app: frontend
version: 1.0.0
annotations:
sidecar.istio.io/rewriteAppHTTPProbers: "true"
spec:
containers:
- name: server
image: gcr.lank8s.cn/tetratelabs/boutique-frontend:1.0.0
ports:
- containerPort: 8080
readinessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8080
httpHeaders:
- name: "Cookie"
value: "shop_session-id=x-readiness-probe"
livenessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8080
httpHeaders:
- name: "Cookie"
value: "shop_session-id=x-liveness-probe"
env:
- name: PORT
value: "8080"
- name: PRODUCT_CATALOG_SERVICE_ADDR
value: "productcatalogservice:3550"
- name: CURRENCY_SERVICE_ADDR
value: "currencyservice:7000"
- name: CART_SERVICE_ADDR
value: "cartservice:7070"
- name: RECOMMENDATION_SERVICE_ADDR
value: "recommendationservice:8080"
- name: SHIPPING_SERVICE_ADDR
value: "shippingservice:50051"
- name: CHECKOUT_SERVICE_ADDR
value: "checkoutservice:5050"
- name: AD_SERVICE_ADDR
value: "adservice:9555"
- name: ENV_PLATFORM
value: "gcp"
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
创建前端部署frontend-v1
[root@k8scloude1 ~]# kubectl apply -f frontend-v1.yaml
deployment.apps/frontend-v1 created
#deploy正常运行
[root@k8scloude1 ~]# kubectl get deploy | grep frontend-v1
frontend-v1 1/1 1 1 54s
#pod正常运行
[root@k8scloude1 ~]# kubectl get pod | grep frontend-v1
frontend-v1-6457cb648d-fgmkk 2/2 Running 0 70s
如果我们在浏览器中打开 INGRESS_HOST
,我们仍然会看到原始版本的前端。浏览器打开http://192.168.110.190/,显示的前端如下:
让我们更新 VirtualService 中的权重,开始将 30% 的流量路由到 v1 的子集。
[root@k8scloude1 ~]# vim frontend-30.yaml
[root@k8scloude1 ~]# cat frontend-30.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: frontend-ingress
spec:
hosts:
- '*'
gateways:
- frontend-gateway
http:
- route:
- destination:
host: frontend.online-boutique.svc.cluster.local
port:
number: 80
subset: original
weight: 70
- destination:
host: frontend.online-boutique.svc.cluster.local
port:
number: 80
subset: v1
weight: 30
更新 VirtualService
[root@k8scloude1 ~]# kubectl apply -f frontend-30.yaml
virtualservice.networking.istio.io/frontend-ingress configured
[root@k8scloude1 ~]# kubectl get virtualservices
NAME GATEWAYS HOSTS AGE
frontend ["frontend.online-boutique.svc.cluster.local"] 5d14h
frontend-ingress ["frontend-gateway"] ["*"] 20m
浏览器访问http://192.168.110.190/,查看前端界面,如果我们刷新几次网页,我们会注意到来自前端 v1 的更新标头,一般显示$75,如下所示:
多刷新几次页面显示$30,如下所示:
我们可以在浏览器中打开 http://192.168.110.130:30754
,进入 kiali界面查看服务的拓扑结构,选择online-boutique命名空间,查看Graph
服务的拓扑结构如下,我们会发现有两个版本的前端在运行:
八.故障注入
8.1 故障注入
我们将为推荐服务引入 5 秒的延迟。Envoy 将为 50% 的请求注入延迟。
[root@k8scloude1 ~]# vim recommendation-delay.yaml
[root@k8scloude1 ~]# cat recommendation-delay.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: recommendationservice
spec:
hosts:
- recommendationservice.online-boutique.svc.cluster.local
http:
- route:
- destination:
host: recommendationservice.online-boutique.svc.cluster.local
fault:
delay:
percentage:
value: 50
fixedDelay: 5s
将上述 YAML 保存为 recommendation-delay.yaml
,然后用 kubectl apply -f recommendation-delay.yaml
创建 VirtualService。
[root@k8scloude1 ~]# kubectl apply -f recommendation-delay.yaml
virtualservice.networking.istio.io/recommendationservice created
[root@k8scloude1 ~]# kubectl get virtualservice
NAME GATEWAYS HOSTS AGE
frontend ["frontend.online-boutique.svc.cluster.local"] 6d13h
frontend-ingress ["frontend-gateway"] ["*"] 23h
recommendationservice ["recommendationservice.online-boutique.svc.cluster.local"] 7s
我们可以在浏览器中打开 INGRESS_HOST
http://192.168.110.190/,然后点击其中一个产品。推荐服务的结果显示在屏幕底部的”Other Products You Might Light“部分。如果我们刷新几次页面,我们会注意到,该页面要么立即加载,要么有一个延迟加载页面。这个延迟是由于我们注入了 5 秒的延迟。
我们可以打开 Grafana(getmesh istioctl dash grafana
)和 Istio 服务仪表板,或者使用如下方法打开Grafana界面:
#查看grafana的端口号
[root@k8scloude1 ~]# kubectl get svc -n istio-system | grep grafana
grafana NodePort 10.100.151.232 <none> 3000:31092/TCP 24d
http://192.168.110.130:31092/打开grafana界面。点击istio-service-dashboard进入istio服务界面
确保从服务列表中选择recommendationsservice
,在 Reporter 下拉菜单中选择 source
,并查看显示延迟的 Client Request Duration,如下图所示:
点击View放大Client Request Duration图表
同样地,我们可以注入一个中止。在下面的例子中,我们为发送到产品目录服务的 50% 的请求注入一个 HTTP 500。
[root@k8scloude1 ~]# vim productcatalogservice-abort.yaml
[root@k8scloude1 ~]# cat productcatalogservice-abort.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: productcatalogservice
spec:
hosts:
- productcatalogservice.online-boutique.svc.cluster.local
http:
- route:
- destination:
host: productcatalogservice.online-boutique.svc.cluster.local
fault:
abort:
percentage:
value: 50
httpStatus: 500
创建VirtualService。
[root@k8scloude1 ~]# kubectl apply -f productcatalogservice-abort.yaml
virtualservice.networking.istio.io/productcatalogservice created
[root@k8scloude1 ~]# kubectl get virtualservice
NAME GATEWAYS HOSTS AGE
frontend ["frontend.online-boutique.svc.cluster.local"] 6d13h
frontend-ingress ["frontend-gateway"] ["*"] 23h
productcatalogservice ["productcatalogservice.online-boutique.svc.cluster.local"] 8s
recommendationservice ["recommendationservice.online-boutique.svc.cluster.local"] 36m
如果我们刷新几次产品页面,我们应该得到如下图所示的错误信息。
请注意,错误信息说,失败的原因是故障过滤器中止。如果我们打开 Grafana(getmesh istioctl dash grafana
),我们也会注意到图中报告的错误。
删除productcatalogservice这个VirtualService:
[root@k8scloude1 ~]# kubectl delete virtualservice productcatalogservice
virtualservice.networking.istio.io "productcatalogservice" deleted
[root@k8scloude1 ~]# kubectl get virtualservice
NAME GATEWAYS HOSTS AGE
frontend ["frontend.online-boutique.svc.cluster.local"] 6d14h
frontend-ingress ["frontend-gateway"] ["*"] 23h
recommendationservice ["recommendationservice.online-boutique.svc.cluster.local"] 44m
九.弹性
9.1 弹性
为了演示弹性功能,我们将在产品目录服务部署中添加一个名为 EXTRA_LATENCY
的环境变量。这个变量会在每次调用服务时注入一个额外的休眠。
通过运行 kubectl edit deploy productcatalogservice
来编辑产品目录服务部署。
[root@k8scloude1 ~]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
adservice 1/1 1 1 6d14h
cartservice 1/1 1 1 6d14h
checkoutservice 1/1 1 1 6d14h
currencyservice 1/1 1 1 6d14h
emailservice 1/1 1 1 6d14h
frontend 1/1 1 1 24h
frontend-v1 1/1 1 1 28h
loadgenerator 1/1 1 1 6d14h
paymentservice 1/1 1 1 6d14h
productcatalogservice 1/1 1 1 6d14h
recommendationservice 1/1 1 1 6d14h
redis-cart 1/1 1 1 6d14h
shippingservice 1/1 1 1 6d14h
[root@k8scloude1 ~]# kubectl edit deploy productcatalogservice
deployment.apps/productcatalogservice edited
这将打开一个编辑器。滚动到有环境变量的部分,添加 EXTRA_LATENCY
环境变量。
...
spec:
containers:
- env:
- name: EXTRA_LATENCY
value: 6s
...
保存并推出编辑器。
如果我们刷新http://192.168.110.190/页面,我们会发现页面需要 6 秒的时间来加载(那是由于我们注入的延迟)。
让我们给产品目录服务添加一个 2 秒的超时。
[root@k8scloude1 ~]# vim productcatalogservice-timeout.yaml
[root@k8scloude1 ~]# cat productcatalogservice-timeout.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: productcatalogservice
spec:
hosts:
- productcatalogservice.online-boutique.svc.cluster.local
http:
- route:
- destination:
host: productcatalogservice.online-boutique.svc.cluster.local
timeout: 2s
创建 VirtualService。
[root@k8scloude1 ~]# kubectl apply -f productcatalogservice-timeout.yaml
virtualservice.networking.istio.io/productcatalogservice created
[root@k8scloude1 ~]# kubectl get virtualservice
NAME GATEWAYS HOSTS AGE
frontend ["frontend.online-boutique.svc.cluster.local"] 6d14h
frontend-ingress ["frontend-gateway"] ["*"] 24h
productcatalogservice ["productcatalogservice.online-boutique.svc.cluster.local"] 10s
recommendationservice ["recommendationservice.online-boutique.svc.cluster.local"] 76m
如果我们刷新页面http://192.168.110.190/,我们会注意到一个错误信息的出现:
rpc error: code = Unavailable desc = upstream request timeout
could not retrieve products
该错误表明对产品目录服务的请求超时了。原因为:我们修改了服务,增加了 6 秒的延迟,并将超时设置为 2 秒。
让我们定义一个重试策略,有三次尝试,每次尝试的超时为 1 秒。
[root@k8scloude1 ~]# vim productcatalogservice-retry.yaml
[root@k8scloude1 ~]# cat productcatalogservice-retry.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: productcatalogservice
spec:
hosts:
- productcatalogservice.online-boutique.svc.cluster.local
http:
- route:
- destination:
host: productcatalogservice.online-boutique.svc.cluster.local
retries:
attempts: 3
perTryTimeout: 1s
[root@k8scloude1 ~]# kubectl apply -f productcatalogservice-retry.yaml
virtualservice.networking.istio.io/productcatalogservice configured
[root@k8scloude1 ~]# kubectl get virtualservice
NAME GATEWAYS HOSTS AGE
frontend ["frontend.online-boutique.svc.cluster.local"] 6d14h
frontend-ingress ["frontend-gateway"] ["*"] 24h
productcatalogservice ["productcatalogservice.online-boutique.svc.cluster.local"] 10m
recommendationservice ["recommendationservice.online-boutique.svc.cluster.local"] 86m
由于我们在产品目录服务部署中留下了额外的延迟,我们仍然会看到错误。
让我们打开 Zipkin 中的追踪,看看重试策略的作用。使用 getmesh istioctl dash zipkin
来打开 Zipkin 仪表盘。或者使用如下方法打开zipkin界面
#查看zipkin端口为30350
[root@k8scloude1 ~]# kubectl get svc -n istio-system | grep zipkin
zipkin NodePort 10.104.85.78 <none> 9411:30350/TCP 23d
浏览器输入http://192.168.110.130:30350/打开zipkin界面。
点击 + 按钮,选择 serviceName
和 frontend.online-boutique
。为了只得到至少一秒钟的响应(这就是我们的 perTryTimeout
),选择 minDuration
,在文本框中输入 1s。点击RUN QUERY
搜索按钮,显示所有追踪。
点击 Filter 按钮,从下拉菜单中选择 productCatalogService.online-boutique
。你应该看到花了 1 秒钟的 trace。这些 trace 对应于我们之前定义的 perTryTimeout
。
点击SHOW
详细信息如下:
运行 kubectl delete vs productcatalogservice
删除 VirtualService。
[root@k8scloude1 ~]# kubectl get virtualservice
NAME GATEWAYS HOSTS AGE
frontend ["frontend.online-boutique.svc.cluster.local"] 6d15h
frontend-ingress ["frontend-gateway"] ["*"] 24h
productcatalogservice ["productcatalogservice.online-boutique.svc.cluster.local"] 37m
recommendationservice ["recommendationservice.online-boutique.svc.cluster.local"] 113m
[root@k8scloude1 ~]# kubectl delete virtualservice productcatalogservice
virtualservice.networking.istio.io "productcatalogservice" deleted
[root@k8scloude1 ~]# kubectl get virtualservice
NAME GATEWAYS HOSTS AGE
frontend ["frontend.online-boutique.svc.cluster.local"] 6d15h
frontend-ingress ["frontend-gateway"] ["*"] 24h
recommendationservice ["recommendationservice.online-boutique.svc.cluster.local"] 114m