k8s网络CNI之flannel

k8s网络通信模型

  • Container to Container:同一pod内的多容器通信,lo
  • Pod to Pod:Pod IP <--> Pod IP
  • Service to Pod: PodIP <--> ClusterIP,跨网段的,依靠iptables或ipvs实现的
  • 集群外部客户端 与 Service:例如ingress

常见CNI插件(Container,Network,Interface)

  • Flannel,提供叠加网络,基于linux TUN/TAP,使用UDP封装IP报

    文来创建叠加网络,并借助etcd维护网络分配情况,要注意,flannel不支持网络策略的制定,所以如需网络策略制定需采用Canal插件
  • Calico,基于BGP的三层网络,支持网络策略实现网络的访问控制。在每台机器上运行一个vRouter,利用内核转发数据包,并借助iptables实现防火墙等功能
  • Canal,由Flannel和Calico联合发布的一个统一网络插件,支持网络策略
  • Weave Net,多主机容器的网络方案,支持去中心化的控制平面,数据平面上,通过UDP封装实现L2 Overlay
  • Contiv,思科方案,直接提供多租户网络,支持L2(VLAN)、L3(BGP)、Overlay(VXLAN)
  • OpenContrail,Juniper开源
  • kube-router,K8s网络一体化解决方案,可取代kube-proxy实现基于ipvs的Service,支持网络策略、完美兼容BGP的高级特性

重点了解Flannel, Calico, Canal, kube-router

插件通信一般的解决方案

  • 虚拟网桥:

  • 多路复用:MacVLAN

  • 硬件交换:SR-IOV ,在硬件上虚拟出多个网卡,供容器使用,性能最好

网络插件的应用

放至宿主机/etc/cni/net.d/下,即可加载使用

[root@node1 net.d]# cat 10-flannel.conflist
{
"name": "cbr0",
"plugins": [
{
"type": "flannel", #插件类型
"delegate": {
"hairpinMode": true,
"isDefaultGateway": true
}
},
{
"type": "portmap",
"capabilities": {
"portMappings": true #是否支持端口映射
}
}
]
}

Flannel插件

flannel原理说明

    现在,我们来简单看一下,如果上方Machine A中IP地址为10.1.15.2/24的容器要与下方Machine B中IP地址为10.1.16.2/24的容器进行通信,封包是如何进行转发的。从上文可知,每个主机的flanneld会将自己与所获取subnet的关联信息存入etcd中,例如,subnet 10.1.15.0/24所在主机可通过IP 192.168.0.100访问,subnet 10.1.16.0/24可通过IP 192.168.0.200访问。反之,每台主机上的flanneld通过监听etcd,也能够知道其他的subnet与哪些主机相关联。如下图,Machine A上的flanneld通过监听etcd已经知道subnet 10.1.16.0/24所在的主机可以通过Public 192.168.0.200访问,而且熟悉docker桥接模式的同学肯定知道,目的地址为10.1.16.2/24的封包一旦到达Machine B,就能通过cni0网桥转发到相应的pod,从而达到跨宿主机通信的目的。

    因此,flanneld只要想办法将封包从Machine A转发到Machine B就OK了,而上文中的backend就是用于完成这一任务。不过,达到这个目的的方法是多种多样的,所以我们也就有了很多种backend。在这里我们举例介绍的是最简单的一种方式`hostgw`:因为`Machine A和Machine B处于同一个子网内`,它们原本就能直接互相访问。因此最简单的方法是:在Machine A中的容器要访问Machine B的容器时,我们可以将Machine B看成是网关,当有封包的目的地址在subnet 10.1.16.0/24范围内时,就将其直接转发至B即可。而这通过下图中那条红色标记的路由就能完成,对于Machine B同理可得。由此,在满足仍有subnet可以分配的条件下,我们可以将上述方法扩展到任意数目位于同一子网内的主机。而任意主机如果想要访问主机X中subnet为S的容器,只要在本主机上添加一条目的地址为R,网关为X的路由即可。

flannel配置参数

Network,全局CIDR格式的IPv4网络,字符串格式,必选
SubnetLen,子网,默认为24位
SubnetMin,分配给节点的起始子网
SubnetMax,分配给节点的最大子网
Backend,flannel要使用的后端

flannel初始配置

[root@master bin]# cat /run/flannel/subnet.env
FLANNEL_NETWORK=10.244.0.0/16
FLANNEL_SUBNET=10.244.0.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true

flannel后端实现原理

flannel支持的后端

  • VxLAN:
  • host-gw:
  • UDP:

host-gw

    hostgw是最简单的backend,它的原理非常简单,直接添加路由,将目的主机当做网关,直接路由原始封包。例如,我们从etcd中监听到一个EventAdded事件:subnet为10.1.15.0/24被分配给主机Public IP 192.168.0.100,hostgw要做的工作非常简单,在本主机上添加一条目的地址为10.1.15.0/24,网关地址为192.168.0.100,输出设备为上文中选择的集群间交互的网卡即可。对于EventRemoved事件,删除对应的路由即可。

VxLAN

如上图所示,当主机B加入flannel网络时,和其他所有backend一样,它会将自己的subnet 10.1.16.0/24和Public IP 192.168.0.101写入etcd中,和其他backend不一样的是,它还会将vtep设备flannel.1的mac地址也写入etcd中。

之后,主机A会得到EventAdded事件,并从中获取上文中B添加至etcd的各种信息。这个时候,它会在本机上添加三条信息:

  1. 路由信息:所有通往目的地址10.1.16.0/24的封包都通过vtep设备flannel.1设备发出,发往的网关地址为10.1.16.0,即主机B中的flannel.1设备。
  2. fdb信息:MAC地址为MAC B的封包,都将通过vxlan首先发往目的地址192.168.0.101,即主机B
  3. arp信息:网关地址10.1.16.0的地址为MAC B

虚拟网络数据帧添加到VxLAN首部后,封装在物理网络UDP报文中,到达目地主机后,去掉物理网络报文头部及VxLAN首部,再将报文交付给目的终端

VxLAN后端使用隧道网络转发会导致一定和流量开销,VxLAN DirectRouting模式,通过添加必要的路由信息使用节点的二层网络直接发送Pod通信报文,仅在跨IP网络时,才启用隧道方式。这样,在不跨IP网络时,性能基本接近二层物理网络

k8s网络策略之canal

canal安装

wget https://docs.projectcalico.org/v3.9/manifests/canal.yaml
kubectl apply -f canal.yaml

NetworkPolicy相关术语

kubectl explain networkpolicy.spec讲解:

  • egress 出站流量规则 可以根据ports和to去定义规则。ports下可以指定目标端口和协议。to(目标地址):目标地址分为ip地址段、pod、namespace
  • ingress 入站流量规则 可以根据ports和from。ports下可以指定目标端口和协议。from(来自那个地址可以进来):地址分为ip地址段、pod、namespace
  • podSelector 定义NetworkPolicy的限制范围。直白的说就是规则应用到那个pod上。podSelector: {},留空就是定义对当前namespace下的所有pod生效。没有定义白名单的话 默认就是Deny ALL (拒绝所有)
  • policyTypes 指定那个规则 那个规则生效,不指定就是默认规则。

实验

创建两个namespace

kubectl create namespace dev
kubectl create namespace prod

创建pod并启动pod

[root@master my-yaml]# mkdir networkpolicy
[root@master my-yaml]# cd networkpolicy/
[root@master my-yaml]# vim pod-a.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod1
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1 [root@master networkpolicy]# kubectl apply -f ingress-default.yaml -n dev
networkpolicy.networking.k8s.io/deny-all-ingress created
[root@master networkpolicy]# kubectl get pod -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod1 1/1 Running 0 5m37s 10.244.1.2 node3 <none> <none>

管理入站流量详解

kubectl explain networkpolicy.spec.ingress

拒绝所有入站流量的规则:

[root@master networkpolicy]# vim ingress-default.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
spec:
podSelector: {} #未定义任何ingress规则,就不允许任何人访问(类似白名单)
policyTypes:
- Ingress
[root@master networkpolicy]# kubectl apply -f deny-all.yaml -n dev #指定对dev名称空间下的pod生效
networkpolicy.networking.k8s.io/deny-all-policy created
[root@node1 networkpolicy]# kubectl get netpol -n dev #查看dev名称空间下的策略
NAME POD-SELECTOR AGE
deny-all-ingress <none> 3s

测试拒绝所有入站流量:

[root@node1 networkpolicy]# curl 10.244.1.2
。。。。。 #无响应 [root@node1 networkpolicy]# kubectl apply -f pod-a.yaml -n prod #在prod下创建pod
pod/pod1 created
[root@node1 networkpolicy]# kubectl get pod -n prod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod1 1/1 Running 0 29s 10.244.1.3 node3 <none> <none>
[root@node1 networkpolicy]# curl 10.244.1.3
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
# 由上述实验可看出,针对做了访问限制的dev名称空间下的pod是无法访问的,而没进行限制的prod下的pod可以正常访问

允许所有入站流量的规则及测试:

[root@master networkpolicy]# vim ingress-allow.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-ingress
spec:
podSelector: {} # 匹配所有Pod
ingress:
- {} # 定义为空, 表示允许访问
policyTypes: ["Ingress"] [root@master networkpolicy]# kubectl apply -f ingress-allow.yaml -n dev
networkpolicy.networking.k8s.io/allow-all-ingress created
[root@master networkpolicy]# curl 10.244.1.2 # 再次访问测试,能正常访问了
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>

放入特定入站流量

# 为pod打标签
[root@master networkpolicy]# kubectl label pod app1 -n dev app=myapp
pod/myapp labeled
[root@master manifests]# kubectl get pod -n dev --show-labels
NAME READY STATUS RESTARTS AGE LABELS
myapp 1/1 Running 0 29m app=myapp
[root@master networkpolicy]# vim allow-someport.yaml #制定一个放行规则
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-myapp-ingress
spec:
podSelector: # 该规则只在当前的namespace下,携带app: myapp标签的pod生效。限制请求的类型包括Ingress和Egress
matchLabels:
app: myapp
policyTypes: ["Ingress"]
ingress:
- from:
- ipBlock: # 网络地址块
cidr: 10.244.0.0/16 # 允许某个网段访问
except: # 排除某个网段或ip访问(只拒绝掉10.244.1.5)
- 10.244.1.5/32
- podSelector: # 携带了app: myapp标签的pod可以访问
matchLabels:
app: myapp
ports: #定义允许本机的哪个端口(实例中只允许访问80端口)
- protocol: TCP
port: 80 [root@master networkpolicy]# curl 10.244.1.2
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[root@master networkpolicy]# curl 10.244.1.2:443
。。。。。。。。 # 请求80端口正常,但443会被直接阻断

管理出站流量

拒绝所有出站流量

[root@master networkpolicy]# vim egress-default.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-egress
spec:
podSelector: {}
## egress: 如果需要放行所有出站流量,增加这条即可
##- {}
policyTypes: ["Egress"] [root@master networkpolicy]# kubectl apply -f egress-default.yaml -n prod
networkpolicy.networking.k8s.io/deny-all-egress created
[root@node1 networkpolicy]# kubectl exec -it pod1 -n prod -- /bin/sh
/ #ping 10.244.1.2
PING 10.244.1.2 (10.244.1.2): 56 data bytes
^C
--- 10.244.1.2 ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss
# 由此可见在该名称空间下的pod内部ping其他名称空间的pod是Ping不通的

放行特定的出站流量

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-tomcat-egress
spec:
podSelector:
matchLabels:
app: tomcat
policyTypes: ["Egress"]
egress:
- to:
- podSelector:
matchLabels:
app: nginx
- ports:
- protocol: TCP
port: 80
- to:
- podSelector:
matchLabels:
app: mysql
ports:
- protocol: TCP
port: 3306

一般网络策略:

  • 名称空间:

    • 拒绝所有出站,入站
    • 放行所有出站目标为本名称空间内的Pod

隔离名称空间

隔离名称空间,应该放行与kube-system名称空间中Pod的通信,以实现监控和名称解析等各种管理功能

kubectl explain networkpolicy.spec.ingress.from.namespaceSelector.matchExpressions
kubectl explain networkpolicy.spec.egress.to.namespaceSelector.matchExpressions
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: namespace-deny-all
namespace: default
spec:
policyTypes: ["Ingress","Egress"]
podSelector: {}
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: namespace-
namespace: default
spec:
policyTypes: ["Ingress","Egress"]
podSelector: {}
ingress:
- from:
- namespaceSelector:
matchExpressions:
- key: name
operator: In
values: ["default","kube-system"]
egress:
- to:
- namespaceSelector:
matchExpressions:
- key: name
operator: In
values: ["default","kube-system"]

十四,K8s集群网络flannel及canal策略的更多相关文章

  1. RabbitMQ (十四) 普通集群

    上篇文章把单机集群搭建好了,可以开始验证普通集群的相关功能了. 我们首先在管理后台(15672,15673 都可以)添加一个用户,并用新用户登录,添加一个虚拟主机 由于是在一台机器上模拟集群,所以我们 ...

  2. K8s二进制部署单节点 etcd集群,flannel网络配置 ——锥刺股

    K8s 二进制部署单节点 master    --锥刺股 k8s集群搭建: etcd集群 flannel网络插件 搭建master组件 搭建node组件 1.部署etcd集群 2.Flannel 网络 ...

  3. Kubernetes实战指南(三十四): 高可用安装K8s集群1.20.x

    @ 目录 1. 安装说明 2. 节点规划 3. 基本配置 4. 内核配置 5. 基本组件安装 6. 高可用组件安装 7. 集群初始化 8. 高可用Master 9. 添加Node节点 10. Cali ...

  4. k8s集群Canal的网络控制 原

    1 简介 直接上干货 public class DispatcherServlet extends HttpServlet { private Properties contextConfigProp ...

  5. Kubernetes(k8s)集群部署(k8s企业级Docker容器集群管理)系列之flanneld网络介绍及部署(三)

    0.前言 整体架构目录:ASP.NET Core分布式项目实战-目录 k8s架构目录:Kubernetes(k8s)集群部署(k8s企业级Docker容器集群管理)系列目录 一.flanneld介绍 ...

  6. 使用kubectl管理k8s集群(二十九)

    前言 在搭建k8s集群之前,我们需要先了解下kubectl的使用,以便在集群部署出现问题时进行检查和处理.命令和语法记不住没有关系,但是请记住主要的语法和命令以及帮助命令的使用. 在下一篇,我们将讲述 ...

  7. 使用Kubeadm创建k8s集群之部署规划(三十)

    前言 上一篇我们讲述了使用Kubectl管理k8s集群,那么接下来,我们将使用kubeadm来启动k8s集群. 部署k8s集群存在一定的挑战,尤其是部署高可用的k8s集群更是颇为复杂(后续会讲).因此 ...

  8. Kubernetes(k8s)集群部署(k8s企业级Docker容器集群管理)系列之部署master/node节点组件(四)

    0.前言 整体架构目录:ASP.NET Core分布式项目实战-目录 k8s架构目录:Kubernetes(k8s)集群部署(k8s企业级Docker容器集群管理)系列目录 1.部署master组件 ...

  9. 二十,基于K8S集群的PaaS简介

    目录 一.概述 二.生产环境部署k8s,接下来我们描述一下在真正生产环境中我们部署k8s应该部署成什么样子 一.概述 1.通过以往的学习应该可以了解到k8s 和以往提到的devops概念更容易落地了. ...

随机推荐

  1. Delphi ActionList详解

    一个友好的用户界面,必须具有下拉菜单,弹出菜单,工具条和快捷键.同样一个功能,程序员可能要提供几种操作方式,如文本拷贝,菜单命令&Copy,快捷键Ctrl+C,工具条上的拷贝按钮,都是程序员提 ...

  2. vue中表格el-table-column数据翻译字段

    <el-table-column prop="isstate" label="状态"></el-table-column> 以上是显示后 ...

  3. Kaggle初体验之泰坦尼特生存预测

    Kaggle初体验之泰坦尼特生存预测 学习完了决策树的ID3.C4.5.CART算法,找一个试手的地方,Kaggle的练习赛泰坦尼特很不错,记录下 流程     首先注册一个账号,然后在顶部菜单栏Co ...

  4. javaweb期末项目-项目结构

    相关链接: 项目结构:https://www.cnblogs.com/formyfish/p/10828672.html 需求分析:https://www.cnblogs.com/formyfish/ ...

  5. 【ARM-Linux开发】Linux环境下使用eclipse开发C++动态链接库程序

    Linux环境下使用eclipse开发C++动态链接库程序 Linux中也有类似windows中DLL的变成方法,只不过名称不同而已.在Linux中,动态链接叫做Standard Object,生成的 ...

  6. 在windows系统电脑上同时安装python2.x和python3.x版本

    在同一个电脑机子(windows系统)上安装同时安装python2.x和python3.x版本. 一.python2.x和python3.x安装 步骤1:在python官网(https://www.p ...

  7. 关于Dev-c++运行时与Windows不兼容问题

    问题描述. 解决方案 1.鼠标右键点击图标,进入属性. 2.点击上方的兼容性. 3.在兼容模式中勾选以兼容模式运行这个程序并选择windows7. 4.再点击以管理员身份运行此程序. 5.点击应用. ...

  8. (5.3.2)数据库迁移——SSIS包批量导出

    SSIS连接出错 原因 :    ssms 工具 不是 admin 权限 打开的  SSIS包批量导出代码 use msdb go IF OBJECT_ID('msdb.dbo.usp_ExportS ...

  9. vue 简易学习

    好记性不如烂笔头 最近公司新出一个框架,采用的是前后端分离的开发方式,后端用的是springboot+mybatis(还有额外的zk.缓存.日志等待),前端采用的是vue+es6,由于以前对vue只知 ...

  10. 【LOJ】#3083. 「GXOI / GZOI2019」与或和

    LOJ#3083. 「GXOI / GZOI2019」与或和 显然是先拆位,AND的答案是所有数字为1的子矩阵的个数 OR是所有的子矩阵个数减去所有数字为0的子矩阵的个数 子矩阵怎么求可以记录每个位置 ...