目录
一、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、集群流量调度规则详解
我们都知道默认访问规则会按照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、执行<kubectl -n istio-demo exec front-tomcat-v1-7f8c94c6c8-lfz5m -- curl -s bill-service:9999>操作时,因为容器内默认dns解析,实际上是在curl后端服务svc地址。
# 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.241 <none> 9999/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-node2 <none> <none>
bill-service-v2-6854775ffc-9n6jv 1/1 Running 0 87m 10.244.2.74 k8s-node1 <none> <none>
front-tomcat-v1-7f8c94c6c8-lfz5m 1/1 Running 0 89m 10.244.1.169 k8s-node2 <none> <none>
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的过程。