目录
一、Service Mesh 服务网格
1、服务网格
2、开源实现
二、Istio服务部署
1、安装Istio
2、安装istio组件
三、传统模式的流量走向
1、场景一
2、资源清单
3、操作实现
四、剖析下默认流量调度机制
1、集群流量调度规则详解
2、总结下
一、Service Mesh 服务网格
1、服务网格
目的是解决系统架构微服务化后的服务间通信和治理问题。提供一种通用的服务治理方案。
Sidecar 在软件系统架构中特指边车模式。这个模式的灵感来源于我们生活中的边三轮:即在两轮摩托车的旁边添加一个边车的方式扩展现有的服务和功能。
这个模式的精髓在于实现了数据面(业务逻辑)和控制面的解耦:原来两轮摩托车的驾驶者集中注意力跑赛道,边车上的领航员专注周围信息和地图,专注导航。
Service Mesh 这个服务网络专注于处理服务和服务间的通讯。其主要负责构造一个稳定可靠的服务通讯的基础设施,并让整个架构更为的先进和 Cloud Native。在工程中,Service Mesh 基本来说是一组轻量级的与应用逻辑服务部署在一起的服务代理,并且对于应用服务是透明的。
2、开源实现
第一代服务网格 linkerd和Envoy
linkerd 使用Scala编写,是业界第一个开源的service mesh方案。作者 William Morgan 是 service mesh 的布道师和践行者。Envoy 基于C++ 11编写,无论是理论上还是实际上,后者性能都比 linkderd 更好。这两个开源实现都是以 sidecar 为核心,绝大部分关注点都是如何做好proxy,并完成一些通用控制面的功能。 但是,当你在容器中大量部署 sidecar 以后,如何管理和控制这些 sidecar 本身就是一个不小的挑战。于是,第二代 Service Mesh 应运而生。
第二代服务网格 Istio
Istio 是 Google 和 IBM 两位巨人联合 Lyft 的合作开源项目。是当前最主流的service mesh方案,也是事实上的第二代 service mesh 标准。
二、Istio服务部署
1、安装Istio
https://istio.io/latest/docs/setup/getting-started/
下载 Istio
下载内容将包含:安装文件、示例和 istioctl 命令行工具。
访问 Istio release 页面下载与您操作系统对应的安装文件。在 macOS 或 Linux 系统中,也可以通过以下命令下载最新版本的 Istio:
$ wget https://github.com/istio/istio/releases/download/1.7.3/istio-1.7.3-linux-amd64.tar.gz
解压并切换到 Istio 包所在目录下。例如:Istio 包名为 istio-1.7.3,则:
$ tar zxf istio-1.7.3-linux-amd64.tar.gz $ ll istio-1.7.3 drwxr-x--- 2 root root 22 Sep 27 08:33 bin -rw-r--r-- 1 root root 11348 Sep 27 08:33 LICENSE drwxr-xr-x 6 root root 66 Sep 27 08:33 manifests -rw-r----- 1 root root 756 Sep 27 08:33 manifest.yaml -rw-r--r-- 1 root root 5756 Sep 27 08:33 README.md drwxr-xr-x 20 root root 330 Sep 27 08:33 samples drwxr-x--- 3 root root 133 Sep 27 08:33 tools
将 istioctl 客户端拷贝到 path 环境变量中
$ cp bin/istioctl /bin/
配置命令自动补全
istioctl 自动补全的文件位于 tools 目录。通过复制 istioctl.bash 文件到您的 home 目录,然后添加下行内容到您的 .bashrc 文件执行 istioctl tab 补全文件:
$ cp tools/istioctl.bash ~ $ source ~/istioctl.bash
2、安装istio组件
https://istio.io/latest/zh/docs/setup/install/istioctl/#display-the-configuration-of-a-profile
使用istioctl直接安装:
$ istioctl install --set profile=demo ✔ Istio core installed ✔ Istiod installed ✔ Egress gateways installed ✔ Ingress gateways installed ✔ Installation complete $ kubectl -n istio-system get po NAME READY STATUS RESTARTS AGE istio-egressgateway-7bf76dd59-n9t5l 1/1 Running 0 77s istio-ingressgateway-586dbbc45d-xphjb 1/1 Running 0 77s istiod-6cc5758d8c-pz28m 1/1 Running 0 84s
istio针对不同的环境,提供了几种不同的初始化部署的profile
# 查看提供的profile类型 $ istioctl profile list 我们用的是demo模式,也就是都安装 # 获取kubernetes的yaml: $ istioctl manifest generate --set profile=demo > istio-kubernetes-manifest.yaml
卸载
$ istioctl manifest generate --set profile=demo | kubectl delete -f -
三、传统模式的流量走向
1、场景一
通过前端服务front-tomcat访问bill-service访问默认会50%随机调度至后端的服务bill-service-dp1和bill-service-dp2。
2、资源清单
front-tomcat-dpl-v1.yaml
apiVersion: apps/v1 kind: Deployment metadata: labels: app: front-tomcat version: v1 name: front-tomcat-v1 namespace: istio-demo spec: replicas: 1 selector: matchLabels: app: front-tomcat version: v1 template: metadata: labels: app: front-tomcat version: v1 spec: containers: - image: consol/tomcat-7.0:latest name: front-tomcat
bill-service-dpl-v1.yaml
apiVersion: apps/v1 kind: Deployment metadata: labels: service: bill-service version: v1 name: bill-service-v1 namespace: istio-demo spec: replicas: 1 selector: matchLabels: service: bill-service version: v1 template: metadata: labels: service: bill-service version: v1 spec: containers: - image: nginx:alpine name: bill-service command: ["/bin/sh", "-c", "echo 'this is bill-service-v1'>/usr/share/nginx/html/index.html;nginx -g 'daemon off;'"]
bill-service-dpl-v2.yaml
apiVersion: apps/v1 kind: Deployment metadata: labels: service: bill-service version: v2 name: bill-service-v2 namespace: istio-demo spec: replicas: 1 selector: matchLabels: service: bill-service version: v2 template: metadata: labels: service: bill-service version: v2 spec: containers: - image: nginx:alpine name: bill-service command: ["/bin/sh", "-c", "echo 'hello, this is bill-service-v2'>/usr/share/nginx/html/index.html;nginx -g 'daemon off;'"]
bill-service-svc.yaml
apiVersion: v1 kind: Service metadata: labels: service: bill-service name: bill-service namespace: istio-demo spec: ports: - name: http port: 9999 protocol: TCP targetPort: 80 selector: service: bill-service type: ClusterIP
3、操作实现
$ kubectl create namespace istio-demo
$ kubectl apply -f front-tomcat-dpl-v1.yaml
$ kubectl apply -f bill-service-dpl-v1.yaml
$ kubectl apply -f bill-service-dpl-v2.yaml
$ kubectl apply -f bill-service-svc.yaml
[root@k8s-master demo]# kubectl -n istio-demo exec front-tomcat-v1-7f8c94c6c8-lfz5m -- curl -s bill-service:9999
this is bill-service-v1
[root@k8s-master demo]# kubectl -n istio-demo exec front-tomcat-v1-7f8c94c6c8-lfz5m -- curl -s bill-service:9999
hello, this is bill-service-v2
四、剖析下默认流量调度机制
1、集群流量调度规则详解
$ kubectl create namespace istio-demo $ kubectl apply -f front-tomcat-dpl-v1.yaml $ kubectl apply -f bill-service-dpl-v1.yaml $ kubectl apply -f bill-service-dpl-v2.yaml $ kubectl apply -f bill-service-svc.yaml [root@k8s-master demo]# kubectl -n istio-demo exec front-tomcat-v1-7f8c94c6c8-lfz5m -- curl -s bill-service:9999 this is bill-service-v1 [root@k8s-master demo]# kubectl -n istio-demo exec front-tomcat-v1-7f8c94c6c8-lfz5m -- curl -s bill-service:9999 hello, this is bill-service-v2
1、集群流量调度规则详解
我们都知道默认访问规则会按照v1和v2的pod各50%的流量分配,那k8s默认的调度机制是怎么实现的呢,现在从网络层面解释下。
curl bill-service:9999-->curl svcip:9999-->查找本地route -n-->没有符合进入0.0.0.0转到10.244.1.1网桥-->10.244.2.1是宿主机上面-->宿主机看kubeproxy组件-->iptables-save | grep svcip找到链路-->iptables-save | grep 链路-->就可以找到对应pod两个地址的random各自50%的规则
1、执行
# bill自带域名解析 [root@k8s-master demo]# kubectl -n istio-demo exec -it bill-service-v1-765cb46975-hmtmd sh / # nslookup bill-service Server: 10.1.0.10 ... Address: 10.1.122.241 [root@k8s-master demo]# kubectl get svc -n istio-demo NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE bill-service ClusterIP 10.1.122.2419999/TCP 66m curl -s bill-service:9999 等同于 curl -s 10.1.122.241:9999
2、路由通过0.0.0.0规则转到10.244.1.1网桥
[root@k8s-master demo]# kubectl -n istio-demo exec -it bill-service-v1-765cb46975-hmtmd sh / # route Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface default 10.244.1.1 0.0.0.0 UG 0 0 0 eth0 10.244.0.0 10.244.1.1 255.255.0.0 UG 0 0 0 eth0 10.244.1.0 * 255.255.255.0 U 0 0 0 eth0 没有找到10.1.122.241规则,就通过0.0.0.0转到10.244.1.1的Gateway
3、宿主机没有维护规则,流量跳转到iptables查看规则
# 这个10.244.1.1实际上是宿主机的地址,也就是说容器此时网络规则,容器内部-->宿主机
[root@k8s-node2 ~]# ip a | grep -e 10.244.1.1
inet 10.244.1.1/24 brd 10.244.1.255 scope global cni0
# 此时宿主机也没有发现相关规则
# 实际上宿主机部署kube-proxy组件,kube-proxy维护了iptables规则,流量虽然没有直接的宿主机route规则,但是流量访问时已经被iptables拦截,我们看下iptable有没有配置相关规则
[root@k8s-node2 ~]# iptables-save | grep 10.1.122.241
-A KUBE-SERVICES ! -s 10.244.0.0/16 -d 10.1.122.241/32 -p tcp -m comment --comment "istio-demo/bill-service:http cluster IP" -m tcp --dport 9999 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.1.122.241/32 -p tcp -m comment --comment "istio-demo/bill-service:http cluster IP" -m tcp --dport 9999 -j KUBE-SVC-PK4BNTKC2JYVE7B2
4、iptables规则链路成功查找到0.5权重的后端地址
# 根据svc地址规则跳转至KUBE-SVC-PK4BNTKC2JYVE7B2链 [root@k8s-node2 ~]# iptables-save | grep 10.1.122.241 -A KUBE-SERVICES -d 10.1.122.241/32 -p tcp -m comment --comment "istio-demo/bill-service:http cluster IP" -m tcp --dport 9999 -j KUBE-SVC-PK4BNTKC2JYVE7B2 # 可以看到0.5权重转发到KUBE-SEP-OIO7GYZLNGRLZLYD,剩下的权重转发到KUBE-SEP-OXS2CP2Q2RMPFLD5链路。我们看下分别对应到后端哪里了 [root@k8s-node2 ~]# iptables-save | grep KUBE-SVC-PK4BNTKC2JYVE7B2 -A KUBE-SVC-PK4BNTKC2JYVE7B2 -m comment --comment "istio-demo/bill-service:http" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-OIO7GYZLNGRLZLYD -A KUBE-SVC-PK4BNTKC2JYVE7B2 -m comment --comment "istio-demo/bill-service:http" -j KUBE-SEP-OXS2CP2Q2RMPFLD5 # 查看KUBE-SEP-OIO7GYZLNGRLZLYD对应的IP [root@k8s-node2 ~]# iptables-save | grep KUBE-SEP-OIO7GYZLNGRLZLYD -A KUBE-SEP-OIO7GYZLNGRLZLYD -s 10.244.1.168/32 -m comment --comment "istio-demo/bill-service:http" -j KUBE-MARK-MASQ # 查看KUBE-SEP-OXS2CP2Q2RMPFLD5对应的IP [root@k8s-node2 ~]# iptables-save | grep KUBE-SEP-OXS2CP2Q2RMPFLD5 -A KUBE-SEP-OXS2CP2Q2RMPFLD5 -s 10.244.2.74/32 -m comment --comment "istio-demo/bill-service:http" -j KUBE-MARK-MASQ # 可以发现,两条链路对应的就是bill-service的两个pod地址 [root@k8s-node2 ~]# kubectl get po -n istio-demo -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES bill-service-v1-765cb46975-hmtmd 1/1 Running 0 89m 10.244.1.168 k8s-node2bill-service-v2-6854775ffc-9n6jv 1/1 Running 0 87m 10.244.2.74 k8s-node1 front-tomcat-v1-7f8c94c6c8-lfz5m 1/1 Running 0 89m 10.244.1.169 k8s-node2
2、总结下
front容器执行curl bill-service:9999操作时,根据域名解析规则,实际是在执行curl -s 10.1.122.241:9999,容器根据本地route -n规则进入0.0.0.0转到10.244.1.1网桥,这个网桥地址位于宿主机上面但是也没有配置相应的route规则;于是我们思考k8s集群网络是由kubeproxy组件配置iptables规则调度的,于是通过iptables-save一步步找到svcip-->0.5-->bill-service-ip的过程。
front容器执行curl bill-service:9999操作时,根据域名解析规则,实际是在执行curl -s 10.1.122.241:9999,容器根据本地route -n规则进入0.0.0.0转到10.244.1.1网桥,这个网桥地址位于宿主机上面但是也没有配置相应的route规则;于是我们思考k8s集群网络是由kubeproxy组件配置iptables规则调度的,于是通过iptables-save一步步找到svcip-->0.5-->bill-service-ip的过程。



