本章概述
- kubernetes网络组件flannel
- kubernetes网络组件calico
- kubernetes NetworkPolicy(网络策略)
- 通过网络策略限制通信案例
16.1 kubernetes网络组件flannel
官网:https://coreos.com/flannel/docs/latest/
文档:https://coreos.com/flannel/docs/latest/kubernetes.html
由CoreOS开源的针对k8s的网络服务,其目的为解决k8s集群中各主机上的pod相互通信的问题,其借助于etcd维护网络IP地址分配,并为每一个node服务器分配一个不同的IP地址段。(注意:k8s集群使用flannel组件,每个node节点的网段必须不同)
Flannel 网络模型 (backend后端)
Flannel目前有三种方式实现 UDP/VXLAN/host-gw:
UDP:早期版本的Flannel使用UDP封装完成报文的跨越主机转发,其安全性及性能略有不足。
VXLAN:Linux 内核在在2012年底的v3.7.0之后加入了VXLAN协议支持,因此新版本的Flannel也由UDP转换为VXLAN,VXLAN本质上是一种tunnel(隧道)协议,用来基于3层网络实现虚拟的2层网络,目前flannel 的网络模型已经是基于VXLAN的叠加(覆盖)网络,目前推荐使用vxlan作为其网络模型。
Host-gw:也就是Host GateWay,通过在node节点上创建到达各目标容器地址的路由表而完成报文的转发,因此这种方式要求各node节点本身必须处于同一个局域网(二层网络)中,因此不适用于网络变动频繁或比较大型的网络环境,但是其性能较好。
公有云不支持BGP协议,无法建立路由表,使用flannel网络模型,无法使用calico
私有云常用calico网络模型,也可以使用flannel网络模型,此次部署的K8S集群使用的网络模型为calico+IPIP模式
Flannel 组件的解释:
Cni0:网桥设备,每创建一个pod都会创建一对 veth pair,其中一端是pod中的eth0,另一端是Cni0网桥中的端口(网卡),Pod中从网卡eth0发出的流量都会发送到Cni0网桥设备的端口(网卡)上,Cni0 设备获得的ip地址是该节点分配到的网段的第一个地址。
Flannel.1: overlay网络的设备,用来进行vxlan报文的处理(封包和解包),不同node之间的pod数据流量都从overlay设备以隧道的形式发送到对端。
Flannel的系统文件及目录:
root@k8s-node2:~# find / -name flannel #运行环境
/run/flannel
/usr/bin/flannel
/var/lib/cni/flannel
root@k8s-node2:~# cat /run/flannel/subnet.env #子网信息
FLANNEL_NETWORK=172.31.0.0/16
FLANNEL_SUBNET=172.31.2.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true
CNI信息:
注意:不要随意改动
root@k8s-node2:~# cat /var/lib/cni/flannel/a77f70994d452ea66c06f0cec194d937dacac1b69c07d31b478f844f216e84c7
{"hairpinMode":true,"ipMasq":false,"ipam":{"routes":[{"dst":"172.31.0.0/16"}],"subnet":"172.31.2.0/24","type":"host-local"},"isDefaultGateway":true,"isGateway":true,"mtu":1450,"name":"cbr0","type":"bridge"}
路由表:
root@k8s-node2:~# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.7.254 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
172.31.0.0 172.31.0.0 255.255.255.0 UG 0 0 0 flannel.1
172.31.1.0 172.31.1.0 255.255.255.0 UG 0 0 0 flannel.1
172.31.2.0 0.0.0.0 255.255.255.0 U 0 0 0 cni0
172.31.3.0 172.31.3.0 255.255.255.0 UG 0 0 0 flannel.1
192.168.0.0 0.0.0.0 255.255.248.0 U 0 0 0 eth0
查看当前集群flannel配置文件
注意:不要随意改动
kubectl edit configmap kube-flannel-cfg -n kube-system
如果在公有云使用flannel vxlan网络模型,会监听8472端口,因此安全组要开启8472端口
下面截图中,8472端口的进程显示为”-”,这是因为8472端口是内核打开的UDP端口,由内核进行监听,并不是由某个服务进程在监听,用来封装和解封装报文。
Flannel VXLAN架构图
1、flannel网络模型的k8s集群每创建一个容器就会创建一个虚拟网卡,该网卡是一对,一端在网桥cni0上(即vethxxxxxxxx),另一端在容器内(即eth0)。因此每个容器内的eth0都会在宿主机网桥cni0都存在一个对应的虚拟网卡vethxxxxxxxx。
2、如果两个容器在同一个node上,可以直接通过网桥cni0基于mac地址进行转发
3、如果两个容器在不同的node上,请求报文经过虚拟网卡vethxxxxxxxx转发给网桥cni0
4、cni0将报文转发给flannel.1,此时内核将报文进行封装,然后转发给宿主机eth0,由eth0转发出去
5、另一个node通过宿主机eth0接收到报文后,内核将报文解封装,经过flannel.1--cni0--vethxxxxxxxx,最终将报文转发给对应的容器。
报文转发过程:
pod(eh0)-->网桥虚拟网卡vethxx-->cni0-flannel.1-->vxlan(内核封装overlay)-eth0(源宿主机,源端口为UDP 随机端口,目的端口为目的主机UDP 8472) -->对端主机eth0(UDP 8472) -->flannel.1-->cni0-->网桥虚拟网卡vethxx-->eth0(pod)
cni0是网桥,类似于二层设备,用于同一个node上不同容器之间进行通讯
flannel.1,用于封装vxlan报文,实现不同node之间的报文转发
Flannel vlxan网络模型下的k8s集群内不同node上容器之间通信,是通过封装三层报文,修改二层mac地址实现不同node之间的容器通信。
如何获取到每个node节点上网卡的mac地址信息:
node在加入集群时,会在etcd进行注册,可以从etcd获取每个node的mac地址信息
16.2 kubernetes网络组件calico
calico官网:http://www.projectcalico.org
calico是一个纯三层的网络解决方案,为容器提供多node间的访问通信,calico将每一个node节点都当做一个路由器(router),各节点通过BGP(Broder Gateway Protocol)边界路由协议学习并在node节点生成路由规则,从而将不同node上的pod链接起来进行通信。
查看calico网络模型下的路由表:
calicoctl node status #在master1节点172.31.7.101上查看路由表
可以看到master节点上有去其他任何一个主机的路由
calico简介:
calico网络通过3层路由技术(如静态路由或BGP路由分配)或2层地址学习来感知工作负载IP地址,它们可以将未封装的流量路由到作为最终目的地的端点主机。因此可以在工作负载之间发送流程,而无需底层网络知道工作负载IP地址。但是,并非所有网络都能够路由工作负载IP地址,例如:公有云环境、跨VPC子网编辑的AWS以及无法通过BGP、calico对应到underlay网络或无法轻松配置静态路由的其他场景。
calico封装类型:
calico支持两种类型的封装:VXLAN和IP-in-IP,VXLAN支持在没有IP的某些环境中使用(例如公有云环境),VXLAN的数据报头较大,因此开销相对较高。这两种封装之间的差异是calico的VXLAN实现不使用BGP,而calico的IP-in-IP是在calico节点之间使用BGP协议实现跨子网。
BGP是一个去中心化的协议,它通过自动学习和维护路由表实现网络的可用性,但并不是所有网络都支持BGP。为了实现更大规模的跨网络管理,calico还支持IP-in-IP的叠加模型,简称IPIP,IPIP可以实现跨不同网段建立路由通信,但是会存在安全性问题,其在内核内置可以通过calico的配置文件设置是否启用IPIP,在公司内部如果K8S的node节点没有跨网段,建议关闭IPIP。
IPIP是一种将各node的路由之间做一个tunnel隧道,再把两个网络连接起来的模式。启用IPIP模式时,calico将在各node上创建一个名为“tunl0”的虚拟网络接口。
BGP模式则直接使用物理机作为虚拟路由器,不载创建额外的tunnel。(即使用IPIP,需要开启IPIP模式,会创建tunnel)
calico核心组件:
Felix:calico的agent,是daemonset容器,运行在每一台node节点上,其主要是维护路由规则,会报当前节点状态以确保pod的跨主机通信。
BGP client:每台node都运行,其主要负责监听node节点上有felix生成的路由信息,然后通过BGP协议广播至其他剩余的node节点,从而相互学习路由实现pod通信
Route Reflector:集中式的路由反射器,calico v3.3开始支持,当calico BGP客户端将路由从其FIB(Forward Information dataBase,转发信息库)通过到Route Reflector时,Route Reflector会将这些路由通告给部署集群中的其他节点,Route Reflector专门用于管理BGP网络路由规则,不会产生pod数据通信。该组件不是必需的,而且是单点,启用后一旦出现问题,k8s集群内的node节点之间将无法通信,因此一般不会启用该组件。
架构图:
如何修改集群网络模式:
vim /etc/kubeasz/clusters/k8s-cluster1/hosts
如果将网络模型更改为flannel,则还需要调整文件/etc/kubeasz/roles/flannel/templates/kube-flannel.yaml.j2
如何关闭IPIP模式:
vim /etc/kubeasz/clusters/k8s-cluster1/ config.yml
CALICO_IPV4POOL_IPIP: "Always" #always开启IPIP模式,可以跨子网访问;off关闭IPIP模式
calico存在CrossSubnet模式,即node节点跨子网开启IPIP模式后,如果node节点不跨子网就使用直接路由,不开启IPIP
部署方式参考链接有道云笔记:https://note.youdao.com/ynoteshare/index.html?id=9d9bb8c33aa7a196ec4f024fe484cb78&type=note&_time=1654409523318
calico部署过程参考官网文档:https://projectcalico.docs.tigera.io/getting-started/
也可以通过calico官网提供的yaml文件进行部署,yaml文件链接:https://projectcalico.docs.tigera.io/manifests/calico.yaml
报文访问转发流程:
1、容器将报文转发给虚拟网卡calixxx
2、虚拟网卡calixxx将报文转发给tun0
3、tun0直接将该报文转发给eth0
4、由于是calico IPIP网络模型,node直到目标主机路由,将报文转发给目标node的eth0
5、目标主机eth0接收报文,将报文转发给tun0,再转发给calixxx,然后转发给容器的eth0
报文转发过程:
eth0(容器)-->cali71be67429f9-->tun0(直接转发) -->eth0(IPinIP,源主机) -->eth0(目的主机) -->tun0-->calid941116c5b6-->eth0(容器)
16.3 kubernetes NetworkPolicy(网络策略)
官网链接:https://kubernetes.io/zh/docs/concepts/services-networking/network-policies/
基于NetworkPolicy在三层(网络层)或四层(传输层)控制拒绝或允许请求流量。
允许或拒绝特定的pod请求目的namespace中的目的pod的所有或指定端口。
允许或拒绝特定的namespace请求目的namespace中的所有或特定的pod所有或指定端口。
允许或拒绝特定的源IP范围或IP地址请求目的pod的所有或特定端口。
环境准备:
1.kubernetes 1.23.5,calico网络组件, 2个node节点或以上。
2.两个namespace,linux和python,分别代表不同项目的Pod。
3.每个namespace 运行多个pod,且pod可以运行在不同的node主机。
4.测试环境为每个namespace分别运行一个nginx和一个tomcat pod,用于测试不同主机的Pod运行在同一个ns的场景、以及跨ns的访问通信及访问限制。
为了能够便于在演示时查看iptables规则,将当前集群三个node节点的网络模式由ipvs更改为iptables
vim /var/lib/kube-proxy/kube-proxy-config.yaml
kind: KubeProxyConfiguration
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
clientConnection:
kubeconfig: "/etc/kubernetes/kube-proxy.kubeconfig"
clusterCIDR: "10.200.0.0/16"
conntrack:
maxPerCore: 32768
min: 131072
tcpCloseWaitTimeout: 1h0m0s
tcpEstablishedTimeout: 24h0m0s
healthzBindAddress: 0.0.0.0:10256
hostnameOverride: "172.31.7.111"
metricsBindAddress: 0.0.0.0:10249
mode: "iptables" #由ipvs模式修改为iptables模式
修改完成后重启node节点,使配置生效
16.3.1 环境准备
1、创建namespace
kubectl create ns linux
kubectl create ns python
2、给namespace打标签,对namespace基于网络策略进行限制,用label来匹配namespace
kubectl label ns linux nsname=linux
kubectl label ns python nsname=python
16.3.2 linux namespace下nginx转发tomcat
linux ns部署nginx和tomcat,并让nginx可以将来自于/app的请求转发至当前namespace的tomcat pod。
1、创建linux namespace下的tomcat容器
(1)编辑tomcat yaml文件:
vim linux-tomcat.yaml
tomcat.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: linux-tomcat-app1-deployment-label
name: linux-tomcat-app1-deployment
namespace: linux
spec:
replicas: 1
selector:
matchLabels:
app: linux-tomcat-app1-selector
template:
metadata:
labels:
app: linux-tomcat-app1-selector
spec:
containers:
- name: linux-tomcat-app1-container
image: tomcat:7.0.109-jdk8-openjdk
#command: ["/apps/tomcat/bin/run_tomcat.sh"]
#imagePullPolicy: IfNotPresent
imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
---
kind: Service
apiVersion: v1
metadata:
labels:
app: linux-tomcat-app1-service-label
name: linux-tomcat-app1-service
namespace: linux
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
nodePort: 30006
selector:
app: linux-tomcat-app1-selector
(2)创建tomcat容器
kubectl apply -f linux-tomcat.yaml
(3)进入tomcat容器,为tomcat添加访问页面
kubectl exec -it xxx bash
cd /usr/local/tomcat/webapp
mkdir app
echo "<h1>linux app test webpage<h1>" > app/index.html
2、创建linux namespace下的nginx容器
(1)编写yaml文件
vim linux-nginx.yaml
nginx.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: linux-nginx-deployment-label
name: linux-nginx-deployment
namespace: linux
spec:
replicas: 1
selector:
matchLabels:
app: linux-nginx-selector
template:
metadata:
labels:
app: linux-nginx-selector
spec:
containers:
- name: linux-nginx-container
image: nginx:1.20.2-alpine
#command: ["/apps/tomcat/bin/run_tomcat.sh"]
#imagePullPolicy: IfNotPresent
imagePullPolicy: Always
ports:
- containerPort: 80
protocol: TCP
name: http
- containerPort: 443
protocol: TCP
name: https
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
---
kind: Service
apiVersion: v1
metadata:
labels:
app: linux-nginx-service-label
name: linux-nginx-service
namespace: linux
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
nodePort: 30008
- name: https
port: 443
protocol: TCP
targetPort: 443
nodePort: 30443
selector:
app: linux-nginx-selector
(2)创建nginx容器
kubectl apply -f linux-nginx.yaml
(3)进入nginx容器,修改nginx配置文件,将动态请求转发给tomcat
vim /etc/nginx/conf.d/default.conf #在server{}配置中添加以下配置,将访问/app的请求转发给当前namespace后端tomcat(这里写tomcat service全称,tomcat service会将请求转发给后端tomcat)
location /app {
proxy_pass http://linux-tomcat-app1-service.linux.svc.magedu.local;
}
(4)重新加载nginx配置文件
nginx -s reload
3、访问验证:
浏览器访问172.31.7.112:30008/app(nginx容器在172.31.7.112上)
通过访问nginx的/app,nginx将请求转发给tomcat,获取tomcat测试页内容,可以看到返回的是linux namespace下tomcat的测试页面结果
16.3.3 python namespace下nginx转发tomcat
python ns部署nginx和tomcat,并让nginx可以将来自于/app的请求转发至当前namespace的tomcat pod。
1、创建python namespace下的tomcat容器:
(1)编写yaml文件
vim python-tomcat.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: python-tomcat-app1-deployment-label
name: python-tomcat-app1-deployment
namespace: python
spec:
replicas: 1
selector:
matchLabels:
app: python-tomcat-app1-selector
template:
metadata:
labels:
app: python-tomcat-app1-selector
spec:
nodeName: 172.31.7.113 #为了便于演示效果,指定tomcat容器部署的node节点
containers:
- name: python-tomcat-app1-container
image: tomcat:7.0.109-jdk8-openjdk
#command: ["/apps/tomcat/bin/run_tomcat.sh"]
#imagePullPolicy: IfNotPresent
imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
---
kind: Service
apiVersion: v1
metadata:
labels:
app: python-tomcat-app1-service-label
name: python-tomcat-app1-service
namespace: python
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
nodePort: 30015
selector:
app: python-tomcat-app1-selector
(2)创建tomcat容器
kubectl apply -f python-tomcat.yaml
(3)创建tomcat容器
kubectl apply -f linux-tomcat.yaml
(4)进入tomcat容器,为tomcat添加访问页面
kubectl exec -it xxx bash
cd /usr/local/tomcat/webapp
mkdir app
echo "<h1>linux app test webpage<h1>" > app/index.html
2、创建python namespace下的nginx容器:
(1)编写yaml文件
vim python-nginx.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: python-nginx-deployment-label
name: python-nginx-deployment
namespace: python
spec:
replicas: 1
selector:
matchLabels:
app: python-nginx-selector
template:
metadata:
labels:
app: python-nginx-selector
project: python
spec:
containers:
- name: python-nginx-container
image: nginx:1.20.2-alpine
#command: ["/apps/tomcat/bin/run_tomcat.sh"]
#imagePullPolicy: IfNotPresent
imagePullPolicy: Always
ports:
- containerPort: 80
protocol: TCP
name: http
- containerPort: 443
protocol: TCP
name: https
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
---
kind: Service
apiVersion: v1
metadata:
labels:
app: python-nginx-service-label
name: python-nginx-service
namespace: python
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
nodePort: 30014
- name: https
port: 443
protocol: TCP
targetPort: 443
nodePort: 30453
selector:
app: python-nginx-selector
project: python #一个或多个selector,至少能匹配目标pod的一个标签
(2)创建nginx容器
kubectl apply -f python-nginx.yaml
(3)进入nginx容器,修改nginx配置文件,将动态请求转发给tomcat
vim /etc/nginx/conf.d/default.conf #在server{}配置中添加以下配置,将访问/app的请求转发给当前namespace后端tomcat(这里写tomcat service全称,tomcat service会将请求转发给后端tomcat)
location /app {
proxy_pass http://python-tomcat-app1-service.python.svc.magedu.local;
}
重新加载nginx配置文件
nginx -s reload
3、访问验证:
浏览器访问:172.31.7.111:30014/app/index.jsp(nginx容器再172.31.7.111上)
通过访问nginx的/app,nginx将请求转发给tomcat,获取tomcat测试页内容,返回的是python namespace下tomcat的测试页面结果
16.3.4 不同namespace下nginx访问tomcat
验证:linux namespace下的nginx是否可以将请求转发给python namespace下的tomcat
1、修改linux namespace下的nginx配置文件
(1)进入linux namespace下的nginx容器,修改配置文件
vim /etc/nginx/conf.d/default.conf #在server{}配置中添加以下配置,将访问linux namespace下/app的请求转发给python namespace后端tomcat(这里写tomcat service全称,tomcat service会将请求转发给后端tomcat)
location /app {
proxy_pass http://python-tomcat-app1-service.python.svc.magedu.local;
}
(2)重新加载nginx配置文件
nginx -s reload
2、访问验证:
浏览器访问:172.31.7.112:30008/app/index.jsp(linux namespace下的nginx容器在172.31.7.112上)
通过访问nginx的/app,nginx将请求转发给tomcat,获取tomcat测试页内容,可以看到,访问linux namespace下的nginx地址,返回的是python namespace下tomcat的测试页面结果,说明不同的namespace下的容器可以相互通信。
不同namespace下的容器可以相互通信,这是不安全的。因此,我们可以通过网络策略来限制不同namespace下的pod进行通信
在default、linux、python三个namespace手动创建测试容器,用来测试
kubectl run net-test-centos-pod1 --image=centos:7.9.2009 sleep 10000000 -n linux
kubectl run net-test-centos-pod1 --image=centos:7.9.2009 sleep 10000000 -n python
kubectl run net-test-centos-pod1 --image=centos:7.9.2009 sleep 10000000
16.4 通过网络策略限制通信案例
16.4.1 示例1:ingress-以pod为限制单位、只允同namespace含有特定标签的源pod访问目标pod的所有端口
ingress:对入口流量进行限制,针对目标pod进行限制
1、网络策略:
(1)只允许当前namespace的pod之间互相访问,禁止跨namespace的访问,其他namespace无法访问当前namespace
(2)只允许当前namespace中含有特定标签的pod访问目标pod,不带标签即使在同一个namespace也无法访问
(3)不允许从宿主机访问目标pod
示例:
(1)编写yaml文件
vim case1-ingress-podSelector.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tomcat-access--networkpolicy #指定网络策略名称
namespace: python #指定网络策略所在的namespace,必须和目标pod在同一namespace
spec:
policyTypes:
- Ingress #对入口流量进行限制
podSelector:
matchLabels:
app: python-tomcat-app1-selector #指定目标pod标签,对匹配到的目的Pod应用以下规则
ingress: #入栈规则,如果指定目标端口就是匹配全部端口和协议,协议TCP, UDP, or SCTP
- from:
- podSelector:
matchLabels:
#app: python-nginx-selector #如果存在多个matchLabel条件,如果存在多个matchLabel条件,是and的关系,即要同时满足条件A、条件B、条件X
project: "pythonxx" #指定匹配的namespace为pythonxx
yaml文件指定规则为:允许python namespace下标签为project:python的源pod访问目标pod,其他pod均拒绝
(2)创建网络策略
kubectl apply -f case1-ingress-podSelector.yaml
(3)查看网络策略
kubectl get networkpolicies -n python
kubectl describe networkpolicies tomcat-access--networkpolicy -n python
2、验证:
(1)在其他主机172.31.7.109上访问python namespace下的tomcat服务。
注意:这里要访问的目标pod为tomcat,而源pod则是nginx,因此要检测nginx容器是否满足网络策略的限制,nginx容器的标签为python,网络策略中限制的是pythonxx,因此nginx容器无法将请求转发给tomcat容器
(2)在同一个namespace下的其他不带pythonxx标签的pod访问tomcat
获取tomcat地址和pod名称
进入同namespace下的测试容器进行curl测试,同样无法访问,这是calico拒绝访问
(3)查看calico规则
由于目标pod在172.31.7.113上,因此需要在pod所在宿主机172.31.7.113上查看calico规则
calicoctl get networkpolicy -n python
calicoctl get networkpolicy -n python knp.default.tomcat-access--networkpolicy -o yaml
16.4.2 示例2:ingress-以pod加端口为限制单位、只允同namespace含有特定标签的源pod访问目标pod的指定端口
1、网络策略:
(1)只允许当前namespace的pod之间互相访问,禁止跨namespace的访问,其他namespace无法访问当前namespace
(2)只允许当前namespace中含有特定标签的pod访问目标pod,不带标签即使在同一个namespace也无法访问
(3)不允许从宿主机访问目标pod
(4)只允许指定的源pod访问同namespace目标pod的指定端口
示例:
(1)编写yaml文件
vim case2-ingress-podSelector-ns-SinglePort.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tomcat-access--networkpolicy
namespace: python
spec:
policyTypes:
- Ingress
podSelector:
matchLabels:
app: python-tomcat-app1-selector
ingress:
- from:
- podSelector:
matchLabels:
#app: python-nginx-selector #指定访问源的匹配条件,如果存在多个matchLabel条件,是and的关系,即要同时满足条件A、条件B、条件X
project: "python"
ports: #入栈规则,如果指定目标端口就是匹配全部端口和协议,协议TCP, UDP, or SCTP
- protocol: TCP
port: 8080 #允许通过TCP协议访问目标pod的8080端口,但是其它没有允许的端口将全部禁止访问
#port: 80
yaml文件指定规则为:允许python namespace下标签为project:python的源pod访问目标pod,其他pod均拒绝,并且只允许访问8080端口,其他端口不允许访问
(2)创建网络策略
kubectl apply -f case2-ingress-podSelector-ns-SinglePort.yaml
此时可以正常访问tomcat容器
注意:这里要访问的目标pod为tomcat,而源pod则是nginx,因此要检测nginx容器是否满足网络策略的限制,nginx容器的标签为python,且访问tomcat的是8080端口,正好符合网络策略的限制条件。
如果将网络策略中限制的端口由8080更改为80,重新加载yaml文件
再次进行访问测试,nginx将无法访问tomcat容器,这是因为只允许80端口访问,而tomcat服务默认为8080,因此无法访问tomcat
16.4.3 示例3:ingress-允许同namespace的所有pod访问当前namespace的目标pod多个指定端口
1、网络策略:
(1)只允许当前namespace的pod之间互相访问,禁止跨namespace的访问,其他namespace无法访问当前namespace
(2)同namespace的其它pod可以访问目的pod的多个指定的端口
示例
编写yaml文件
vim case3-ingress-podSelector-ns-MultiPort.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tomcat-access-networkpolicy
namespace: python
spec:
policyTypes:
- Ingress
podSelector: #目标pod
matchLabels:
app: python-tomcat-app1-selector
ingress:
- from:
- podSelector: #匹配源pod,matchLabels: {}为不限制源pod即允许所有pod,写法等同于resources(不加就是不限制)
matchLabels: {}
ports: #入栈规则,如果指定目标端口就是匹配全部端口和协议,协议TCP, UDP, or SCTP
- protocol: TCP
port: 8080 #允许通过TCP协议访问目标pod的8080端口,但是其它没有允许的端口将全部禁止访问
#port: 80
- protocol: TCP
port: 3306
- protocol: TCP
port: 6379
规则为:允许python namespace下的所有pod之间访问目标pod,但只可以访问8080/3306/6379这三个端口,禁止访问目标pod的其他端口
注意:如果不添加ports字段,则默认允许所有端口,一旦加上ports字段,则必须写明允许访问的端口,否则将无法访问目标pod的对应服务
该示例与示例2类似,只是限制了多个端口,因此这里不再举例
16.4.4 示例4:ingress-允许同namespace的所有pod访问当前namespace的目标pod所有端口
1、网络策略:
(1)只允许当前namespace的pod之间互相访问,禁止跨namespace的访问,其他namespace无法访问当前namespace
(2)不允许从宿主机访问目标pod
(3)同namespace的其它pod可以访问目的pod的任何端口
示例:
(1)编写yaml文件
vim case4-ingress-podSelector-ns.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tomcat-access--networkpolicy
namespace: python
spec:
policyTypes:
- Ingress
podSelector: #目标pod
matchLabels: {} #匹配所有目标pod
ingress:
- from:
- podSelector: #匹配源pod,matchLabels: {}为不限制源pod即允许所有pod,写法等同于resources(不加就是不限制)
matchLabels: {}
yaml文件指定的规则为:允许python namespace下的所有pod之间访问目标pod的任意端口
(2)创建网络策略
kubectl apply -f case4-ingress-podSelector-ns.yaml
2、验证:
(1)在同namespace中的pod中访问tomcat,可以正常访问
(2)在其他主机172.31.7.109则不能访问tomcat(不能跨namespace,且宿主机也不能访问pod)
16.4.5 示例5:ingress-ipBlock白名单
1、网络策略:
(1)只要在白名单范围内没有被except指定禁止的源pod IP,都允许访问。
(2)在只设置了ipBlock匹配的前提下,其它namespace 中没有在except范围的pod 也可以访问目标pod,及linux ns中的pod只要不在except地址范围内,也可以访问python ns中的pod。
示例:
(1)编写yaml文件
vim case5-ingress-ipBlock.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tomcat-access--networkpolicy
namespace: python
spec:
policyTypes:
- Ingress
podSelector: #目标pod
matchLabels:
app: python-tomcat-app1-selector
ingress:
- from:
# - podSelector: #匹配源pod,matchLabels: {}为不限制源pod即允许所有pod,写法等同于resources(不加就是不限制)
# matchLabels: {}
- ipBlock:
cidr: 10.200.0.0/16 #白名单,允许访问的地址范围,没有允许的将禁止访问目标pod
except: #指定白名单中不被允许的ip地址,排除白名单中部分ip访问目标pod
- 10.200.219.0/24 #在以上范围内禁止访问的源IP地址
- 10.200.229.0/24 #在以上范围内禁止访问的源IP地址
- 10.200.36.67/32 #在以上范围内禁止访问的源IP地址
ports: #入栈规则,如果指定目标端口就是匹配全部端口和协议,协议TCP, UDP, or SCTP
- protocol: TCP
port: 8080 #允许通过TCP协议访问目标pod的8080端口,但是其它没有允许的端口将全部禁止访问
#port: 80
- protocol: TCP
port: 3306
- protocol: TCP
port: 6379
yaml文件指定的规则为:只要ip地址不在except访问内,任何namespace中的任意pod都可以访问目标pod的8080,3306,6379
(2)创建网络策略
kubectl apply -f case5-ingress-ipBlock.yaml
2、验证:
(1)将python namespace下的nginx包含在except范围内
查看python namespace下的nginx地址为10.200.36.67
(2)修改yaml文件(这里之贴出修改部分)
except: #指定白名单中不被允许的ip地址,排除白名单中部分ip访问目标pod
- 10.200.219.0/24 #在以上范围内禁止访问的源IP地址
- 10.200.229.0/24 #在以上范围内禁止访问的源IP地址
- 10.200.36.67/32 #在以上范围内禁止访问的源IP地址
(3)重新加载yaml文件,然后在同namespace下的nginx容器访问tomcat容器进行测试,发现无法正常访问。这是因为nginx地址在网络策略限制范围内,因此无法访问目标pod
(4)在同namespace下测试容器进行测试,发现可以正常访问,这是因为测试容器地址不在网络策略限制范围内,因此可以正常访问
(5)删除策略,恢复正常
kubectl delete -f case5-ingress-ipBlock.yaml
16.4.6 示例6:ingress-namespace Selector-ns选择器
1、网络策略:
(1)被明确允许的namespace中的pod可以访问目标pod,没有明确声明允许的namespace将禁止访问
(2)没有明确声明允许的话,即使同一个namespace也禁止访问,比如只允许了linux和python两个ns,那么default中的pod将无法访问。
2、使用场景:
A、B两个项目有关联,允许A项目访问B项目中的容器
示例:
(1)编写yaml文件
vim case6-ingress-namespaceSelector.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tomcat-access--networkpolicy
namespace: python
spec:
policyTypes:
- Ingress
podSelector: #目标pod
matchLabels: {} #允许访问python namespace 中的所有pod
ingress:
- from:
- namespaceSelector:
matchLabels:
nsname: linux #只允许指定的namespace访问
- namespaceSelector:
matchLabels:
nsname: python #只允许指定的namespace访问
ports: #入栈规则,如果指定目标端口就是匹配全部端口和协议,协议TCP, UDP, or SCTP
- protocol: TCP
port: 8080 #允许通过TCP协议访问目标pod的8080端口,但是其它没有允许的端口将全部禁止访问
#port: 80
- protocol: TCP
port: 3306
- protocol: TCP
port: 6379
yaml文件指定规则为:允许linux和python这两个namespace下的pod访问目标pod的8080,3306,6379,其他pod禁止访问
(2)创建网络策略
kubectl apply -f case6-ingress-namespaceSelector.yaml
3、验证
(1)进入default namespace的测试容器,访问tomcat,发现无法访问
(2)进入python或linux namespace下的nginx,访问tomcat,可以正常访问
16.4.7 示例7:Egress-podSelector-Pod出口方向目的IP及目的端口限制-只允许访问指定的目的地址范围及端口
egress:对出口流量进行限制,针对源pod进行限制
1、网络策略:
(1)基于Egress白名单,定义ns中匹配成功的pod可以访问ipBlock指定的地址和ports指定的端口。
(2)匹配成功的pod访问未明确定义在Egress的白名单的其它IP的请求,将拒绝。
(3)没有匹配成功的源pod,主动发起的出口访问请求不受影响。
示例:
(1)编写yaml文件
vim case7-Egress-ipBlock.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-access-networkpolicy
namespace: python
spec:
policyTypes:
- Egress
podSelector: #目标pod选择器
matchLabels: #基于label匹配目标pod
app: python-tomcat-app1-selector #匹配python namespace中app的值为python-tomcat-app1-selector的pod,然后基于egress中的指定网络策略进行出口方向的网络限制
egress:
- to:
- ipBlock:
cidr: 10.200.0.0/16 #允许匹配到的pod出口访问的目的CIDR地址范围
- ipBlock:
cidr: 172.31.7.106/32 #允许匹配到的pod出口访问的目的主机
ports:
- protocol: TCP
port: 80 #允许匹配到的pod访问目的端口为80的访问
- protocol: TCP
port: 53 #允许匹配到的pod访问目的端口为53 即DNS的解析
- protocol: UDP
port: 53 #允许匹配到的pod访问目的端口为53 即DNS的解析
yaml文件指定规则为:允许访问python namespace中app值为python-tomcat-app1-selector的目标pod,且该pod的地址范围为10.200.0.0/16和172.31.7.106/32,目标pod端口为TCP 的80端口,TCP和UDP的53端口
注意:如果配置Egress,对源pod的出口流量和端口进行限制,一定要开启53端口,因为53端口是K8S集群的dns使用端口,如果不开启该端口,容器将无法进行dns解析
(2)创建网络策略
kubectl apply -f case7-Egress-ipBlock.yaml
(3)修改yaml文件(这里只贴出修改部分)
vim case7-Egress-ipBlock.yaml
ports:
- protocol: TCP
port: 80 #允许匹配到的pod访问目的端口为80的访问
# - protocol: TCP
# port: 53 #允许匹配到的pod访问目的端口为53 即DNS的解析
# - protocol: UDP
# port: 53 #允许匹配到的pod访问目的端口为53 即DNS的解析
重新加载yaml文件
2、验证
(1)进入tomcat容器,ping 百度域名,发现无法解析,这是因为关闭了53端口,导致无法进行dns解析
(2)开启53端的网络策略,可以解析百度域名地址,但仍无法访问,这是因为百度域名不匹配出口策略
16.4.8 示例8:Egress-podSelector-Pod出口方向目的Pod限制-只允许访问指定的pod及端口
基于podSelector选择器,限制源pod能够访问的目的pod
1、网络策略:
匹配成功的源pod只能访问指定的目的pod的指定端口
示例:
(1)编写yaml文件
vim case8-Egress-PodSelector.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-access-networkpolicy
namespace: python
spec:
policyTypes:
- Egress
podSelector: #目标pod选择器
matchLabels: #基于label匹配目标pod
app: python-nginx-selector #匹配python namespace中app的值为python-tomcat-app1-selector的pod,然后基于egress中的指定网络策略进行出口方向的网络限制
egress:
- to:
- podSelector: #匹配pod,matchLabels: {}为不限制源pod即允许所有pod,写法等同于resources(不加就是不限制)
matchLabels:
app: python-tomcat-app1-selector #指定tomcat的label
ports:
- protocol: TCP
port: 8080 #允许80端口的访问
- protocol: TCP
port: 53 #允许DNS的解析
- protocol: UDP
port: 53
yaml文件指定规则为:只能访问pod 标签为python-tomcat-app1-selector的pod,且只能访问目标pod的8080端口(53端口用来做dns解析)
(2)创建网络策略
kubectl apply -f case8-Egress-PodSelector.yaml
2、验证
(1)进入nginx容器进行测试:
可以正常访问tomcat
注意:如果此时在nginx容器访问tomcat的service地址,也可以正常访问
但是却无法访问外网,这是因为网络策略指定nginx容器只能访问的目标pod的是tomcat,因此不能访问其他内容
16.4.9 示例9:Egress-namespaceSelector
1、网络策略:
(1)限制匹配成功的源pod可以访问的目标namespace。
(2)不能访问指定的namespace以外的其它namespace及外网。
(3)比如允许指定的源pod访问linux和python ns中的8080、3306、6379等端口,但是无法访问其它ns及外网
示例:
(1)编写yaml文件
vim case9-Egress-namespaceSelector.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-access-networkpolicy
namespace: python
spec:
policyTypes:
- Egress
podSelector: #目标pod选择器
matchLabels: #基于label匹配目标pod
app: python-nginx-selector #匹配python namespace中app的值为python-tomcat-app1-selector的pod,然后基于egress中的指定网络策略进行出口方向的网络限制
egress:
- to:
- namespaceSelector:
matchLabels:
nsname: python #指定允许访问的目的namespace
- namespaceSelector:
matchLabels:
nsname: linux #指定允许访问的目的namespace
ports:
- protocol: TCP
port: 8080 #允许80端口的访问
- protocol: TCP
port: 53 #允许DNS的解析
- protocol: UDP
port: 53
yaml文件指定规则为:指定源pod可以访问的目标namespace中的pod,且端口为8080(53端口用于dns解析)
该示例类似示例6,这里不再举例验证
文章评论