k8s之网络策略
部署canal提供网络策略功能
Canal代表了针对云原生应用程序的最佳策略网络解决方案,旨在让用户轻松的将Calico和flannel网络部署在一起作为统一的网络解决方案,将Calico的网络策略执行与Calico和falnnel叠加以及非叠加网络连接选项的丰富功能
换句话说,Calico项目既能独立的为kubernetes集群提供网络解决方案和网络策略,也能与flannel结合一起,由flannel提供网络解决方案。Calico将数据存储与etcd中,它支持选择使用专用的etcd存储,也能够以Kubernetes API Server作为后端存储。
注意:结合flannel工作时,Calico提供的默认配置清单中是以flannel默认使用的10.244.0.0/16为Pod网络,因此,确保kube-controller-manager程序在启动时通过--cluster-cidr选项设置了此网络地址,并且--allocate-node-cidrs的值应该设置为true
安装:官网地址:https://docs.projectcalico.org/getting-started/kubernetes/flannel/flannel
curl https://docs.projectcalico.org/manifests/canal.yaml -O kubectl apply -f canal.yaml
配置网络策略
.spec.PodSelector
顾名思义,它是pod选择器,基于标签选择与Network Policy处于同一namespace下的pod,如果pod被选中,则对其应用Network Policy中定义的规则。此为可选字段,当没有此字段时,表示选中所有pod。
.spec.PolicyTypes
Network Policy定义的规则可以分成两种,一种是入pod的Ingress规则,一种是出pod的Egress规则。本字段可以看作是一个开关,如果其中包含Ingress,则Ingress部分定义的规则生效,如果是Egress则Egress部分定义的规则生效,如果都包含则全部生效。当然此字段也可选,如果没有指定的话,则默认Ingress生效,如果Egress部分有定义的话,Egress才生效。怎么理解这句话,下文会提到,没有明确定义Ingress、Egress部分,它也是一种规则,默认规则而非没有规则。
.spec.ingress与.spec.egress
前者定义入pod规则,后者定义出pod规则,详细参考这里,这里只讲一下重点。上例中ingress与egress都只包含一条规则,两者都是数组,可以包含多条规则。当包含多条时,条目之间的逻辑关系是“或”,只要匹配其中一条就可以。.spec.ingress[].from
也是数组,数组成员对访问pod的外部source进行描述,符合条件的source才可以访问pod,有多种方法,如示例中的ip地址块、名称空间、pod标签等,数组中的成员也是逻辑或的关系。spec.ingress[].from.prots表示允许通过的协议及端口号。
.spec.egress.to
定义的是pod想要访问的外部destination,其它与ingress相同。
管控入站流量
默认禁止所有入pod流量(Default deny all ingress traffic)
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny spec: podSelector: {} policyTypes: - Ingress
默认允许所有入pod流量(Default allow all ingress traffic)
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-all spec: podSelector: {} ingress: - {}
放行特定的入站流量
from字段的值是一个对象列表,他可以嵌套使用ipBlock、namespaceSelector和podSelector字段来定义流量来源,此三个字断匹配Pod资源的方式各有不同,同时使用两个或以上的字断,彼此之间隐含“逻辑或”关系
.ipBlock:根据IP地址或网络地址块选择流量源端点
.namespaceselector:基于集群级别的标签挑选名称空间,他将匹配由此标签选择器选出的所有空间内的所有pod对象;赋予字断以空值来表示挑选所有的名称空间
.podSelector:于Networkpolicy所在的当前名称空间内基于标签选择器挑选Pod资源,赋予字断以空值来表示挑选当前名称空间内的所有Pod对象
.ports:也是一个对象列表,嵌套port和protocol来定义流量的目标端口,即由NetworkPolicy匹配到的当前名称空间内的所有pod资源上的端口
.port:端口号或者在Container上定义的端口名称,为定义时匹配所有端口
.protocol:传输层协议
下面配置清单中的网络策略定义了如何开放myapp pod资源给相应的源站点访问
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-myapp-ingress spec: podSelector:
matchLabels:
app: myapp
policyTypes: ["ingress"] ingress: - from:
- ipBlock:
cidr: 10.244.0.0/16
except:
- 10.244.3.0/24
- podSelector:
matchLabels:
app: myapp
ports:
- protocol: TCP
port: 80
将default名称配置空间中拥有标签“app=myapp”的Pod资源的80/TCP端口开放给10.244.0.0/16网络内除10.244.3.0/24子网中的所有源端点,以及当前名称空间中拥有标签“app=myapp”的所有Pod资源访问,其他未匹配的源端点的流量取决于其他网络策略的定义,若没有任何匹配策略,则默认为允许访问
管控出站流量
networkpoliy.spec中嵌套的Egress字段用于定义入站流量规则,就特定的Pod集合来说,出站流量一样默认处于放行状态,除非在所有入站策略中至少有一条规则能够匹配它。Egress字段的值是一个字段列表,由以下两个字段组成
.to:由当前策略匹配到Pod自愿发起的出站流量的目标地址列表,多个项目之间为“或”关系;若未定义或字段值为空则意味着应用于所有的目标地址(默认为不限制);若给出明确的主机地址列表,则只有目标地址匹配到列表中的主机地址的出站流量被放行。
.ports:出站流量的目标端口列表,多个端口之间为“或”关系;若未定义或字段值为空则意味值应用于所有端口(默认为不限制);若明确给出了端口列表,则只有目标端口匹配到列表中的端口的出出站流量被放行。
默认禁止所有出pod流量(Default deny all egress traffic)
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny spec: podSelector: {} policyTypes: - Egress
默认允许所有出pod流量(Default deny all egress traffic)
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-all spec: podSelector: {} egress: - {} policyTypes: - Egress
放行特定的出站流量
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-tomcat-egress spec: podSelector: matchLabels: app: tomcat policyTypes: ["Egress"] egress: - to: - podSelector:
matchLabels:
app: tomcat
ports:
- protocol: TCP
port: 80
- to:
- podSelector:
matchLabels:
app: mysql
ports:
- protocol: TCP
port: 3306
此配置清单中仅定义了出站规则,将入站流量的默认规则设置为拒绝时,还应该为具有标签“app=tomcat”的Pod对象放行入站流量。
默认禁止所有入出pod流量(Default deny all ingress and all egress traffic)
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny spec: podSelector: {} policyTypes: - Ingress - Egress
隔离名称空间
实践中通常需要彼此哥所有的名称空间,但应该允许他们都能够与kube-system名称空间中国呢的Pod资源进行流量交换,以实现监控和名称解析等各种管理功能。定义出站和入站流量默认均为拒绝的情况下,放行名称空间内不的各pod对象之间的通信,以及与kube-system名称空间内各pod的通信
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: namespace-deny-all
namespace:default spec: podSelector: {} policyTypes: - Ingress - Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: namespace-
namespace: default
spec:
podSelector: {}
policyTypes: ["Ingress","Egress"]
ingress:
- from:
- namespaceSelector:
matchExpressions:
- key: name
operator: In
values: ["default","kube-system"]
egress:
- to:
- namespaceSelector:
matchExpressions:
- key: name
operator: In
values: ["default","kube-system"]
需要注意的是,有些管理员可能会把一些系统附件部署到专有的名称空间中。例如把prometheus监控系统部署到prom名称空间中等,所有这类的具有管理功能的附件所在的名称空间与每一个特定的名称空间的出入流量都应该被放行。
真实用例
下面通过一个真实示例展示Network Policy普通用法
用Deployment创建nginx pod实例并用service暴露
$ kubectl run nginx --image=nginx --replicas=2 deployment "nginx" created $ kubectl expose deployment nginx --port=80 service "nginx" exposed
确认创建结果
$ kubectl get svc,pod NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE svc/kubernetes 10.100.0.1 <none> 443/TCP 46m svc/nginx 10.100.0.16 <none> 80/TCP 33s NAME READY STATUS RESTARTS AGE po/nginx-701339712-e0qfq 1/1 Running 0 35s po/nginx-701339712-o00ef 1/1 Running 0 35s
测试nginx服务连通性
$ kubectl run busybox --rm -ti --image=busybox /bin/sh Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false Hit enter for command prompt / # wget --spider --timeout=1 nginx Connecting to nginx (10.100.0.16:80) / #
通过创建Network Policy对象添加隔离性
kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: name: access-nginx spec: podSelector: matchLabels: run: nginx ingress: - from: - podSelector: matchLabels: access: "true"
只允许包含access: "true"标签的pod访问nginx服务。
创建Network Policy
$ kubectl create -f nginx-policy.yaml
networkpolicy "access-nginx" created
测试隔离性
$ kubectl run busybox --rm -ti --image=busybox /bin/sh Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false Hit enter for command prompt / # wget --spider --timeout=1 nginx Connecting to nginx (10.100.0.16:80) wget: download timed out / #
为pod添加access: "true"标签测试连通性
$ kubectl run busybox --rm -ti --labels="access=true" --image=busybox /bin/sh Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false Hit enter for command prompt / # wget --spider --timeout=1 nginx Connecting to nginx (10.100.0.16:80) / #