文章目录
- 一、K8S集群通信的网络模型和网络模型
-
- 1 K8S网络模型和实现方案
- 2 pod 内容器通信
- 3 pod与pod通信
-
- 3.1 pod在同一主机
- 3.2 pod 在不同的主机下
- 4 pod 与service通信
- 5 service 如何找到服务?
- 6 外网与service通信
- 二、k8s与网络插件集成(flannel calico canal kube-router romana cni-genie)
-
- 1 flannel
- 2 calico
- 本实验的使用及k8s一个etcd集群
- 建议使用一个单独的集群
-
- 3 canal
- 4 kube-router
- 5 romana
- 6 CNI-Genie
- 7 组件小结
-
-
- 总结:
-
一、K8S集群通信的网络模型和网络模型
1 K8S网络模型和实现方案
k8s集群中的每一个Pod(最小调度单位)都有自己的IP地址,即ip-per-pod模型。 在ip-per-pod每个模型pod为了保持集群中的独特性,我们不需要在每个集群中都显式 Pod 之间创建链接, 从容器端口到主机端口的映射不需要处理。从端口分配、命名、服务发现、 从负载平衡、应用配置和迁移的角度来看,Pod 可视为独立虚拟机或物理主机。 如下图所示,两个容器从表面上看docker网络与k8s网络中与client通信形式。
k8s为了保持核心功能的简化(模块化)和适应不同业务用户的网络环境,是一个庞大的分布式系统,k8s通过CNI(Container Network Interface)即集成各种网络方案的容器网络接口。这些网络方案必须符合要求k8s网络模型要求:
注:只针对那些支持: Pods
运行在主机网络中的平台(如:Linux):
这有点像美团吗?外包配送业务(CNI)对于三方公司(实现计划),我不在乎骑手通过哪种飞机炮(网络)送餐,只要符合及时、不泄漏(模型要求)等相关规则,这是一个合格的分销。
CNI 做两件事,容器创建时的网络分配,和当容器被删除时释放网络资源。 常用的 CNI 实现方案有 Flannel、Calico、Weave各种云制造商根据自己的网络推出CNI华为的插件 CNI-Genie、阿里云Terway。
2 pod 内容器通信
Pod内容器很简单,在同一个 Pod 内部,所有容器共享存储,网络使用相同 IP 地址和端口空间可以通过localhost
发现对方。Pod 使用中间容器 Infra,Infra 在 Pod 首先创建,其他容器通过 Join Network Namespace 的方式与 Infra 容器相连。
我们有一个pod包含busybox、nginx这两个容器
kubectl get pod -n training NAME READY STATUS RESTARTS AGE pod-localhost-765b965cfc-8sh76 2/2 Running 0 2m56s
在busybox中使用telnet连接nginx容器的 80端口看看。
kubectl exec -it pod-localhost-765b965cfc-8sh76 -c container-si1nrb -n training -- /bin/sh # telnet localhost 80 Connected to localhost
一个pod有多个容器可以通过-c指定进入的容器名(通过describe通过容器名称),显然是通过localhost可以轻松访问同一个pod中的nginx容器80端口。这通常部署在许多密切相关的应用程序中pod中。
3 pod与pod通信
3.1 pod在同一主机
我们通过node两个选择器pod调度到同一个node中
... nodeSelector: kubernetes.io/hostname: node2 ...
两个容器分别获得一个IP地址,也通过IP双方网络地址正常交换。
# kubectl get pod -o wide -n training NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-to-pod-64444686ff-w7c4g 1/1 Running 0 6m53s 100.82.98.206 node2 <none> <none> pod-to-pod-busybox-7b9db67bc6-tl27c 1/1 Running 0 5m3s 100.82.98.250 node2 <none> <none> # kubectl exec -it pod-to-pod-busybox-7b9db67bc6-tl27c -n training -- /bin/sh /# telnet 100.82.98.206 80 Connected to 100.82.98.206
同一主机网络的pod以及我们以前学到的东西docker bridge相似,通过linux在网桥上添加虚拟设备 连接容器和主机命名空间。 在k8s只是用灰色部分代替CNI方案实现。
3.2 pod 在不同的主机下
此时pod分布如下
kubectl get pod -o wide -n training NAME ` READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-to-pod-64444686ff-w7c4g 1/1 Running 0 104m 100.82.98.206 node2 <none> pod-to-pod-busybox-node2-6476f7b7f9-mqcw9 1/1 Running 0 42s 100.91.48.208 node3 <none> # kubectl exec -it pod-to-pod-busybox-node2-6476f7b7f9-mqcw9 -n training -- /bin/sh / # telnet 100.82.98.206 80 Connected to 100.82.98.206
pod不同主机的通信依赖于不同主机的通信
4 pod 与service通信
我们知道在k8s中容器随时可能被摧毁,pod的IP显然不是持久的,会随着扩展或缩小应用规模、或者应用程序崩溃以及节点重启等而消失和出现。service 设计就是来处理这个问题。service可以管理一组 Pod 的状态,允许我们跟踪一组随时间动态变化的 Pod IP 地址。而客户端只需要知道service这个不变的虚拟IP就可以了。
我们先来看看典型的service与pod使用,我们创建了一个service,标签选择器为app:nginx,将会路由到app=nginx标签的Pod上。
# kubectl get service -n training
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
training-service ClusterIP 10.96.229.238 <none> 8881/TCP 10m
Service对外暴露的端口8881,这样在集群的中的pod即可通过8881访问到与service 绑定的label为app=nginx的pod
kubectl run -it --image nginx:alpine curl --rm /bin/sh
/ # curl 10.96.229.238:8881
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
...
其实大多数时候在自动化部署服务时并不知道service ip,所以另一种常见方式通过DNS进行域名解析后,可以使用
5 service 是如何做到服务发现的?
Endpoints是k8s中的一种资源对象,k8s通过Endpoints监控到Pod的IP,service又关联Endpoints从而实现Pod的发现。大致如下图所示,service的发现机制我们会在后面文章中做深入了解。
6 外网与service通信
其实所谓外网通信也是service的表现形式。 service几种类型和不同用途。
我们先来看NodePort:
我们在service中指定type: NodePort创建出的service将会包含一个在所有node 开放的端口30678,这样我们访问任意节点IP:30678即可访问到我们的pod
# kubectl get service -n training
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
training-service NodePort 10.96.229.238 <none> 8881:30678/TCP 55m
# curl 192.168.1.86:30678
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
....
LoadBalancer类型和它名字一样,为负载均衡而生。它的结构如下图所示, LoadBalancer本身不是属于Kubernetes的组件,如果使用云厂商的容器服务。通常会提供一套他们的负载均衡服务比如阿里云ACK的SLB、华为云的ELB等等。Service是基于四层TCP和UDP协议转发的,而k8s 另外一种资源对象Ingress可以基于七层的HTTP和HTTPS协议转发,可通过域名和路径做到更细粒度的划分,这是后话。
二、k8s与各网络插件集成(flannel calico canal kube-router romana cni-genie)
通用说明 如果多次换不同网络插件实验,每次实验前先把
rm -rf /etc/cni/net.d/*
1 flannel
# 创建flannel目录下载相关文件
mkdir flannel && cd flannel
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# 修改配置
# 此处的ip配置要与kubeadm的pod-network参数配置的一致
net-conf.json: |
{
"Network": "192.168.0.0/16",
"Backend": {
"Type": "vxlan"
}
}
# 修改镜像
image: registry.cn-shanghai.aliyuncs.com/gcr-k8s/flannel:v0.10.0-amd64
# 如果Node有多个网卡的话,参考flannel issues 39701,
# https://github.com/kubernetes/kubernetes/issues/39701
# 目前需要在kube-flannel.yml中使用--iface参数指定集群主机内网网卡的名称,
# 否则可能会出现dns无法解析。容器无法通信的情况,需要将kube-flannel.yml下载到本地,
# flanneld启动参数加上--iface=<iface-name>
containers:
- name: kube-flannel
image: registry.cn-shanghai.aliyuncs.com/gcr-k8s/flannel:v0.10.0-amd64
command:
- /opt/bin/flanneld
args:
- --ip-masq
- --kube-subnet-mgr
- --iface=eth1
# 启动
kubectl apply -f kube-flannel.yml
# 查看
kubectl get pods --namespace kube-system
kubectl get svc --namespace kube-system
2 calico
配置启动etcd集群
本次实验使用与k8s一个etcd集群
生境环境建议使用单独的一套集群
配置启动calico
# 创建calico目录下载相关文件
mkdir calico && cd calico
wget https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/rbac.yaml
wget https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/calico.yaml
# 如果启用了RBAC(默认k8s集群启用),配置RBAC
kubectl apply -f rbac.yaml
# 修改calico.yaml文件中名为calico-config的ConfigMap中的etcd_endpoints参数为自己的etcd集群
etcd_endpoints: "http://11.11.11.111:2379,http://11.11.11.112:2379,http://11.11.11.113:2379"
# 修改镜像为国内镜像
sed -i 's@image: quay.io/calico/@image: registry.cn-shanghai.aliyuncs.com/gcr-k8s/calico-@g' calico.yaml
# 启动
kubectl apply -f calico.yaml
# 查看
kubectl get pods --namespace kube-system
kubectl get svc --namespace kube-system
参考文档
https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/calico#installing-with-the-etcd-datastore
3 canal
# 创建flannel目录下载相关文件
mkdir canal && cd canal
wget https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/canal/rbac.yaml
wget https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/canal/canal.yaml
# 修改配置
# 此处的ip配置要与kubeadm的pod-network参数配置的一致
net-conf.json: |
{
"Network": "192.168.0.0/16",
"Backend": {
"Type": "vxlan"
}
}
# 修改calico镜像
sed -i 's@image: quay.io/calico/@image: registry.cn-shanghai.aliyuncs.com/gcr-k8s/calico-@g' canal.yaml
# 修改flannel镜像
image: registry.cn-shanghai.aliyuncs.com/gcr-k8s/flannel:v0.10.0-amd64
# 如果Node有多个网卡的话,参考flannel issues 39701,
# https://github.com/kubernetes/kubernetes/issues/39701
# 目前需要在kube-flannel.yml中使用--iface参数指定集群主机内网网卡的名称,
# 否则可能会出现dns无法解析。容器无法通信的情况,需要将kube-flannel.yml下载到本地,
# flanneld启动参数加上--iface=<iface-name>
containers:
- name: kube-flannel
image: registry.cn-shanghai.aliyuncs.com/gcr-k8s/flannel:v0.10.0-amd64
command: [ "/opt/bin/flanneld", "--ip-masq", "--kube-subnet-mgr", "--iface=eth1" ]
# 启动
kubectl apply -f rbac.yaml
kubectl apply -f canal.yaml
# 查看
kubectl get pods --namespace kube-system
kubectl get svc --namespace kube-system
4 kube-router
# 本次实验重新创建了集群,使用之前测试其他网络插件的集群环境没有成功
# 可能是由于环境干扰,实验时需要注意
# 创建kube-router目录下载相关文件
mkdir kube-router && cd kube-router
wget https://raw.githubusercontent.com/cloudnativelabs/kube-router/master/daemonset/kubeadm-kuberouter.yaml
wget https://raw.githubusercontent.com/cloudnativelabs/kube-router/master/daemonset/kubeadm-kuberouter-all-features.yaml
# 以下两种部署方式任选其一
# 1. 只启用 pod网络通信,网络隔离策略 功能
kubectl apply -f kubeadm-kuberouter.yaml
# 2. 启用 pod网络通信,网络隔离策略,服务代理 所有功能
# 删除kube-proxy和其之前配置的服务代理
kubectl apply -f kubeadm-kuberouter-all-features.yaml
kubectl -n kube-system delete ds kube-proxy
# 在每个节点上执行
docker run --privileged --net=host registry.cn-hangzhou.aliyuncs.com/google_containers/kube-proxy-amd64:v1.10.2 kube-proxy --cleanup
# 查看
kubectl get pods --namespace kube-system
kubectl get svc --namespace kube-system
5 romana
# 创建flannel目录下载相关文件
mkdir romana && cd romana
wget https://raw.githubusercontent.com/romana/romana/master/containerize/specs/romana-kubeadm.yml
# 修改镜像
sed -i 's@gcr.io/@registry.cn-hangzhou.aliyuncs.com/@g' romana-kubeadm.yml
sed -i 's@quay.io/romana/@registry.cn-shanghai.aliyuncs.com/gcr-k8s/romana-@g' romana-kubeadm.yml
# 启动
kubectl apply -f romana-kubeadm.yml
# 查看
kubectl get pods --namespace kube-system
kubectl get svc --namespace kube-system
6 CNI-Genie
# CNI-Genie是华为开源的网络组件,可以使k8s同时部署多个网络插件
# 在k8s集群中安装calico组件
# 在k8s集群中安装flannel组件
# 在k8s集群中安装Genie组件
mkdir CNI-Genie && cd CNI-Genie
wget https://raw.githubusercontent.com/Huawei-PaaS/CNI-Genie/master/conf/1.8/genie.yaml
sed -i 's@image: quay.io/cnigenie/v1.5:latest@image: registry.cn-shanghai.aliyuncs.com/gcr-k8s/cnigenie-v1.5:latest@g' genie.yaml
kubectl apply -f genie.yaml
# 查看
kubectl get pods --namespace kube-system
kubectl get svc --namespace kube-system
# 测试
cat >nginx-calico.yml<<EOF
apiVersion: v1
kind: Pod
metadata:
name: nginx-calico
labels:
app: web
annotations:
cni: "calico"
spec:
containers:
- name: nginx
image: nginx:alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
EOF
cat >nginx-flannel.yml<<EOF
apiVersion: v1
kind: Pod
metadata:
name: nginx-flannel
labels:
app: web
annotations:
cni: "flannel"
spec:
containers:
- name: nginx
image: nginx:alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
EOF
kubectl apply -f nginx-calico.yml
kubectl apply -f nginx-flannel.yml
# 查看
kubectl get pods -o wide
# 测试网络通信
kubectl exec nginx-calico -i -t -- ping -c4 1.1.1.1
kubectl exec nginx-flannel -i -t -- ping -c4 1.1.1.1
# 由于先启动的flannel,然后k8s创建了coredns,所以使用flannel cni的能正常使用dns
# 使用calico cni无法使用正常dns
# 测试dns
kubectl exec nginx-calico -i -t -- ping -c4 www.baidu.com
kubectl exec nginx-flannel -i -t -- ping -c4 www.baidu.com
7 组件小结
kube-router性能损失最小,时延最小,其他网络插件性能差距不大。除了flannel没有网络隔离策略,其他均支持网络隔离策略。CNI-Genie是一个可以让k8s使用多个cni网络插件的组件,暂时不支持隔离策略。 理论结果: kube-router > calico > canal = flannel = romana
总结:
不写了,睡觉,狗命要紧,未完 待续