基于canel的网络策略
背景描述:
我们的k8s集群使用flannel cni插件,由于flannel 不支持 networkpolicy, 所以我们研究了其他的支持网络策略的cni,calico 和canal
为什么是canal:
刚开始去研究了 calico ,发现calico支持 ipip 和bgp两种策略, 由于我们IT当前不支持BGP网络, 而IPIP模式对于calico而言,意义不是很大,所以决定部署更为简单的canal
什么是canal:
Canal是Flannel和Calico联合发布的一个统一网络插件,提供CNI网络插件,并支持network policy
Colico网络插件工作于192.168.0.0/16网络并且每一个节点分配一个节点网络,例如node1是192.168.0.0/16网络,node2是192.168.1.0/16网络
flanel无法提供网络策略,所以在flanel之上安装colico。在flanel提供的网络基础之上在额外提供Colico,此处的Colico只服务与网络策略,
官网提供的安装方式:https://projectcalico.docs.tigera.io/getting-started/kubernetes/flannel/flannel
Colico部署有两种方式:
使用一套独立的etcd
使用kubernetes的etcd,不能直接操作etcd而是需要通过kubernetes API Server调用etcd
使用 Kubernetes API 数据存储进行安装(推荐)
一、确保 Kubernetes 控制器管理器设置了以下标志:
--cluster-cidr=<your-pod-cidr>和--allocate-node-cidrs=true.
提示:在 kubeadm 上,您可以传递--pod-network-cidr=<your-pod-cidr> 给 kubeadm 来设置两个 Kubernetes 控制器标志。
二、下载 Kubernetes API 数据存储的 flannel 网络清单。
curl https://projectcalico.docs.tigera.io/manifests/canal.yaml -O
三、如果您使用的是 pod CIDR 10.244.0.0/16,请跳到下一步。如果您在 kubeadm 中使用不同的 pod CIDR,则无需更改 - Calico 将根据运行配置自动检测 CIDR。对于其他平台,请确保取消注释清单中的 CALICO_IPV4POOL_CIDR 变量并将其设置为与您选择的 pod CIDR 相同的值。
四、发出以下命令来安装 Calico。
kubectl apply -f canal.yaml
五、验证是否成功安装canel
kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
canal-426md 3/3 Running 0 13s
canal-srhh7 3/3 Running 0 13s
canal-2gzvq 3/3 Running 0 13s
与flanel一样是一个DaemonSet控制器,每个节点都需要部署一个canal Pod,所以当前有多少个节点就会存在多少个canal Pod
kubernetes中的网络控制策略:
NetworkPolicy是kubernetes对pod的隔离手段,可以看到,NetworkPolicy实际上只是宿主机上的一系列iptables规则。
Egress:表示出站流量,就是pod作为客户端访问外部服务,pod地址作为源地址(客户端),服务端作为目标地址进行通信。通常来说客户端端口是随机的,而服务端地址是固定的。策略可以定义目标地址或者目标端口
Ingress:表示入站流量,pod地址和服务作为服务端(目标地址)提供外部访问。pod地址作为目标地址,客户端是源地址。策略可以定义源地址目标端口
podSelector:规则生效在那个pod上,可以配置单个pod或者一组pod。可以定义单方向。空 podSelector选择命名空间中的所有Pod。
kubectl explain networkpolicy.spec讲解:
egress: 出站流量规则 可以根据ports和to去定义规则。ports下可以指定目标端口和协议。to(目标地址):目标地址分为ip地址段、pod、namespace,
ingress: 入站流量规则 可以根据ports和from。ports下可以指定目标端口和协议。from(来自那个地址可以进来):地址分为ip地址段、pod、namespace
policyTypes:指定那个规则 那个规则生效,同时指定Egress和Ingress,意味着同时生效,不指定就是全部生效。
podSelector:定义NetworkPolicy的限制范围。直白的说就是规则应用到哪个pod上,哪个Pod就生效。podSelector: {},留空就是定义对当前namespace下的所有pod生效。没有定义白名单的话 默认就是Deny ALL (拒绝所有)
kubectl explain networkpolicy.spec.egress.to: #to表示目标地址
podSelector: 指定一组Pod,控制两组Pod之间的通信,源可以是一组Pod,目标也可以是一组Pod
ipBlock: IP地址串,可以是一个IP地址范围,也可以是一个准确的IP
namespaceSelector:名称空间选择器,指定一个名称空间且这个名称空间范围内的所有Pod都可以访问
设置to可以是三种情况中的一个,也可以三种交叉使用
kubectl explain networkpolicy.spec.ingress:
from:指定那些地址可以访问,可以是一个地址范围也可以是一个具体地址
ports:目标端口,也就是自己开放的端口
举例:
事先创建两个namespace (dev,prod)
在dev的namespace下定义一个入站流量拒绝的规则:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-policy
spec:
podSelector: {} #留空意味着对整个namespace生效
policyTypes:
- Ingress
policyTypes指定了Ingress而Ingress没有定义任何规则,也就是说拒绝所有入站流量,没有指定Egress也就是说不控制Egress,而不控制Egress默认都是允许出站的。
以上没有指定某个名称空间,执行时在后面执行文件后面指定namespace,然后这个yaml就在指定的namespace下面创建对象或者服务,这样可以更灵活的使用yaml。
kubectl apply -f network-policy.yaml -n dev
在dev和prod的namespace下个各自创建一个pod
apiVersion: v1
kind: Pod
metadata:
name: pod-1
labels:
name: myapp
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
kubectl apply -f policy-pod.yaml -n dev
kubectl apply -f policy-pod.yaml -n prod
查看是否创建成功
kubectl get pod -o wide -n prod
NAME READY STATUS RESTARTS AGE IP NODE
pod-1 1/1 Running 0 3h 10.244.2.3 k8s-node02
kubectl get pod -owide -n dev
NAME READY STATUS RESTARTS AGE IP NODE
pod-1 1/1 Running 0 3h 10.244.2.2 k8s-node02
curl 10.244.2.3
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
curl 10.244.2.2 不通
允许所有Ingress入站请求:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-policy
spec:
podSelector: {} #留空意味着对整个namespace生效
ingress:
- {}
policyTypes:
- Ingress
验证是否成功:
curl 10.244.2.2
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
放行特定的入站访问流量:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-myapp-policy
spec:
podSelector:
matchLabels:
app: myapp #选择app=myapp 的标签放行
ingress:
- from:
- ipBlock: #地址段
cidr: 10.244.0.0/16 #允许这个地址段访问
except: #排除一下地址不可以访问
- 10.244.1.2/32
ports:
- port: 80 只运行访问80端口
protocol: TCP
kubectl apply -f alloy-pod.yaml -n dev
任何在dev这个名称空间中拥有标签app且标签值为myapp的都允许对其80端口进行访问。
在prod的namespace下定义一个出站流量拒绝的规则:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-policy
spec:
podSelector: {} #留空意味着对整个namespace生效
policyTypes:
- Egress
kubectl apply -f policy-pod.yaml -n prod
上方在prod里面创建的有Pod所以直接使用已创建的prod就好
kubectl exec -it pod-1 -n prod -- /bin/sh
ping 10.244.2.3 不通
允许所有Egress出站请求:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-policy
spec:
podSelector: {} #留空意味着对整个namespace生效
Egress:
- {}
policyTypes:
- Egress
kubectl apply -f policy-pod.yaml -n prod
验证是否成功:
ping 10.244.2.3
Pinging 10.244.2.3 [10.244.2.3]with 32 bytes of data:
Reply from 10.244.2.3: bytes=32 time=8ms TTL=45
完整的NetworkPolicy对象:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
该规则只在default 的namespace下,携带role:db标签的pod生效。限制请求的类型包括Ingress和Egress。
Kubernetes会拒绝任何访问被隔离pod的请求,除非这个请求来自以下“白名单”里的对象。并且访问的是被隔离pod的6379端口。
default Namespace里的,携带了role=fronted标签的pod可以访问
任何Namespace里的,携带了project=myproject标签的pod可以访问
任何源地址数据172.17.0.0/16网段,且不属于172.17.1.0/24网段的请求
Kubernetes会拒绝被隔离pod对外发起任何请求,除非请求的目的地址属于10.0.0.0/24网段,并且访问的是该网段地址的5978端口。
仅登录用户可评论,点击 登录