Kubernetes 的命名空间主要用于组织和隔离资源,但默认情况下,不同命名空间中的 Pod 之间是可以相互通信的。为了实现更严格的网络隔离,同一套k8s需要根据不同的命名空间进行网络环境隔离,例如开发(dev01)测试(test01)环境。Network Policies 是 Kubernetes 提供的一种机制,用于控制 Pod 间的网络流量。你可以为每个命名空间定义 Network Policies 来限制 Pod 之间的通信。
二、相关解释它是pod选择器,基于标签选择与Network Policy处于同一namespace下的pod,如果pod被选中,则对其应用Network Policy中定义的规则。此为可选字段,当没有此字段时,表示选中所有pod。
Network Policy定义的规则可以分成两种,一种是入pod的Ingress规则,一种是出pod的Egress规则。本字段可以看作是一个开关,如果其中包含Ingress,则Ingress部分定义的规则生效,如果是Egress则Egress部分定义的规则生效,如果都包含则全部生效。当然此字段也可选,如果没有指定的话,则默认Ingress生效,如果Egress部分有定义的话,Egress才生效。怎么理解这句话,下文会提到,没有明确定义Ingress、Egress部分,它也是一种规则,默认规则而非没有规则。
spec.ingress
和 spec.egress
字段分别用于定义允许进入 Pod 的流量规则和允许离开 Pod 的流量规则。下面详细解释这两个字段的结构和包含的子项。
spec.ingress
结构
spec: ingress: - from: - podSelector: matchLabels: {} # 选择具有特定标签的 Pod - namespaceSelector: matchLabels: {} # 选择具有特定标签的命名空间 - ipBlock: cidr: 0.0.0.0/0 # CIDR 地址范围 except: - 10.0.0.0/8 # 排除的 CIDR 地址范围 - ports: - protocol: TCP # 协议类型 port: 80 # 具体端口 endPort: 8080 # 如果是端口范围,则需要指定结束端口
spec.egress
结构
spec: egress: - to: - podSelector: matchLabels: {} # 选择具有特定标签的 Pod - namespaceSelector: matchLabels: {} # 选择具有特定标签的命名空间 - ipBlock: cidr: 0.0.0.0/0 # CIDR 地址范围 except: - 10.0.0.0/8 # 排除的 CIDR 地址范围 - ports: - protocol: TCP # 协议类型 port: 80 # 具体端口 endPort: 8080 # 如果是端口范围,则需要指定结束端口
示例
假设你有一个 NetworkPolicy,它允许 Pod 接收来自 CIDR 地址范围 192.168.1.0/24
的流量,并允许 Pod 发送流量到 CIDR 地址范围 10.0.0.0/8
,同时只允许通过 TCP 协议的端口 80 和 443 进行通信。
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-traffic namespace: my-namespace spec: podSelector: {} ingress: - from: - ipBlock: cidr: 192.168.1.0/24 - ports: - protocol: TCP port: 80 - protocol: TCP port: 443 egress: - to: - ipBlock: cidr: 10.0.0.0/8 - ports: - protocol: TCP port: 80 - protocol: TCP port: 443 policyTypes: - Ingress - Egress
注意事项
my-namespace
命名空间中的所有 Pod。192.168.1.0/24
和 10.0.0.0/8
通常用于私有网络。创建测试使用的3个命名空间sub1,sub2,sub3。
如果后面的网络策略使用到namespaceSelector,在创建命名空间时需要带label,也可在需要时手动添加label。
kubectl create ns sub1 --labels ns=sub1 kubectl create ns sub2 --labels ns=sub2 kubectl create ns sub3 --labels ns=sub2
如果使用的是私有仓库,注意ns要创建docker-secret。
kubectl create secret docker-registry my-registry-secret --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD -n namespace
2.1、sub1创建sub1-pod1和sub1-pod1-nodeport,sub1-pod2;
2.2、sub2创建sub2-pod1和sub2-pod1-nodeport,sub2-pod2;
2.3、sub3创建sub3-pod1;
apiVersion: apps/v1 kind: Deployment metadata: name: sub1-pod1 namespace: sub1 spec: selector: matchLabels: app: sub1pod1 replicas: 1 template: metadata: labels: app: sub1pod1 spec: containers: - name: my-test01-01 image: swr.cn-east-3.myhuaweicloud.com/k8s-imgs/account-platform-admin:dev01-084e7d9 imagePullPolicy: IfNotPresent imagePullSecrets: - name: default-secret imagePullSecrets: - name: swr-secret --- apiVersion: v1 kind: Service metadata: name: sub1-pod1-nodeport namespace: sub1 spec: type: NodePort selector: app: sub1pod1 ports: - protocol: TCP port: 80 targetPort: 8103 nodePort: 32700 --- apiVersion: apps/v1 kind: Deployment metadata: name: sub1-pod2 namespace: sub1 spec: selector: matchLabels: app: sub1pod2 replicas: 1 template: metadata: labels: app: sub1pod2 spec: containers: - name: my-test01-02 image: swr.cn-east-3.myhuaweicloud.com/k8s-imgs/account-platform-admin:dev01-084e7d9 imagePullPolicy: IfNotPresent imagePullSecrets: - name: default-secret imagePullSecrets: - name: swr-secret --- apiVersion: apps/v1 kind: Deployment metadata: name: sub2-pod1 namespace: sub2 spec: selector: matchLabels: app: sub2pod1 replicas: 1 template: metadata: labels: app: sub2pod1 spec: containers: - name: my-test02-01 image: swr.cn-east-3.myhuaweicloud.com/k8s-imgs/account-platform-admin:dev01-084e7d9 imagePullPolicy: IfNotPresent imagePullSecrets: - name: default-secret imagePullSecrets: - name: swr-secret --- apiVersion: v1 kind: Service metadata: name: sub2-pod1-nodeport namespace: sub2 spec: type: NodePort selector: app: sub2pod1 ports: - protocol: TCP port: 80 targetPort: 8103 nodePort: 32701 --- apiVersion: apps/v1 kind: Deployment metadata: name: sub2-pod2 namespace: sub2 spec: selector: matchLabels: app: sub2pod2 replicas: 1 template: metadata: labels: app: sub2pod2 spec: containers: - name: my-test02-02 image: swr.cn-east-3.myhuaweicloud.com/k8s-imgs/account-platform-admin:dev01-084e7d9 imagePullPolicy: IfNotPresent imagePullSecrets: - name: default-secret imagePullSecrets: - name: swr-secret --- apiVersion: apps/v1 kind: Deployment metadata: name: sub3-pod1 namespace: sub3 spec: selector: matchLabels: app: sub3pod1 replicas: 1 template: metadata: labels: app: sub3pod1 spec: containers: - name: my-test03-01 image: swr.cn-east-3.myhuaweicloud.com/k8s-imgs/account-platform-admin:dev01-084e7d9 imagePullPolicy: IfNotPresent imagePullSecrets: - name: default-secret imagePullSecrets: - name: swr-secret
查看创建的资源
在应用网络策略之前测试各pod之间、pod和外网之间是否可以通信。
sub1-pod1 ping sub1-pod2、sub2-pod1、sub3-pod1、qq.com
外部节点ping sub1-pod1-nodeport、sub2-pod1-nodeport
取k8s集群任一节点ip 10.34.106.14
总结:通过以上测试证明未加网络策略之前pod之间,pod外网之间都是互通的。
策略描述:在sub1中创建策略,使sub1中pod之间无法通信且和其他命名空间pod也无法通信,只能进出外网。
测试流程:
4.1、sub1-pod1、sub1-pod2、sub2-pod1三者之间互ping不通;
4.2、sub1-pod1、sub1-pod2可以ping通外网(包含域名),外网也能和sub1-pod1-nodeport通信;
本k8s集群pod cidr为:10.243.0.0/16
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: pod-policy namespace: sub1 spec: podSelector: {} ingress: - from: - ipBlock: cidr: 0.0.0.0/0 except: - 10.243.0.0/16 egress: - to: - ipBlock: cidr: 0.0.0.0/0 except: - 10.243.0.0/16 policyTypes: - Egress - Ingress
解释:
podSelector
: {}
表示选择命名空间中的所有 Pod。ingress
: 定义了进入命名空间的流量控制规则。
from
: 表示允许来自哪些来源的流量。ipBlock
: 表示允许来自除了 10.243.0.0/16
CIDR 地址范围之外的所有 IP 地址的流量。egress
: 定义了离开命名空间的流量控制规则。
to
: 表示允许流向哪些目的地的流量。ipBlock
: 表示允许流向除了 10.243.0.0/16
CIDR 地址范围之外的所有 IP 地址的流量。policyTypes
: 指定 NetworkPolicy 控制的流量类型,这里包括 Ingress
和 Egress
。效果:
10.243.0.0/16
。10.243.0.0/16
。测试:
创建策略
sub1-pod1 ping sub1-pod2和sub2-pod1 (不通)
sub2-pod1 ping sub1-pod1和sub1-pod2(不通)
sub1-pod1 ping 外网ip(通)
sub1-pod1 ping 域名(不通)-- 因为域名解析服务dns在kube-system空间,而sub1屏蔽了所有空间,下面示例可解决。
外部访问sub1-pod1-nodeport(通)
取k8s集群任一节点ip 10.34.106.14
策略描述:在sub2中创建策略,使sub2中pod之间可以通信但和其他命名空间pod无法通信,也能进出外网。
测试流程:
5.1、sub2-pod1和sub2-pod2之间互ping可通;
5.2、sub2-pod1、sub2-pod2和sub3-pod1之间互ping不通;
5.3、sub2-pod1、sub2-pod2可以ping通外网(包含域名),外网也能和sub2-pod1-nodeport通信;
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: sub2 namespace: sub2 spec: podSelector: {} egress: - to: - ipBlock: cidr: 0.0.0.0/0 except: - 10.243.0.0/16 - namespaceSelector: # 如果不想给命名空间加label,可以换成 - podSelector: {} # 允许来自同一命名空间中的所有 Pod 的流量 matchLabels: ns: sub2 ingress: - from: - ipBlock: cidr: 0.0.0.0/0 except: - 10.243.0.0/16 - namespaceSelector: # 如果不想给命名空间加label,可以换成 - podSelector: {} # 允许来自同一命名空间中的所有 Pod 的流量 matchLabels: ns: sub2 policyTypes: - Egress - Ingress
解释
podSelector
: {}
表示选择命名空间中的所有 Pod。ingress
: 定义了进入命名空间的流量控制规则。
from
: 表示允许来自哪些来源的流量。ipBlock
: 表示允许来自除了 10.243.0.0/16
CIDR 地址范围之外的所有 IP 地址的流量。namespaceSelector
: 表示允许来自具有标签 ns=sub2
的命名空间中的 Pod 的流量。from
字段中的 podSelector: {}
表示允许来自同一命名空间中的所有 Pod 的流量。egress
: 定义了离开命名空间的流量控制规则。
to
: 表示允许流向哪些目的地的流量。ipBlock
: 表示允许流向除了 10.243.0.0/16
CIDR 地址范围之外的所有 IP 地址的流量。namespaceSelector
: 表示允许流向具有标签 ns=sub2
的命名空间中的 Pod 的流量。podSelector: {}
表示允许流向同一命名空间中的所有 Pod 的流量。policyTypes
: 指定 NetworkPolicy 控制的流量类型,这里包括 Ingress
和 Egress
。效果
10.243.0.0/16
和来自其他命名空间的流量,如果使用namespaceSelector则允许进入命名空间具有标签 ns=sub2中的pod,如果使用podSelector: {}
表示允许来自同一命名空间中的所有 Pod 的流量
。10.243.0.0/16
和流向其他命名空间的流量,如果使用namespaceSelector则允许流向命名空间具有标签 ns=sub2中的pod,如果使用podSelector: {}
表示允许流向同一命名空间中的所有 Pod 的流量
。
创建策略
sub2-pod1 ping sub2-pod2(通)
sub2-pod1 ping sub3-pod1(不通)
sub3-pod1 ping sub2-pod1、sub2-pod2(不通)
sub2-pod1 ping 外网ip(通)
sub2-pod1 ping 域名(不通)-- 因为域名解析服务dns在kube-system空间,而sub1屏蔽了所有空间,下面示例可解决。
外部 访问sub2-pod1-nodeport(通)
取k8s集群任一节点ip 10.34.106.14
实际应用中某些命名空间中的pod可能和其他命名空间中的pod有调用关系,还可能用到一些系统命名空间中的服务(如DNS服务),所以不能将某个命名空间完全和其他所有命名空间隔离,只需要将确定没有业务调用的命名空间隔离。
策略描述:更新第5步sub2中创建的策略,使sub2中的pod除了不能和sub3中的pod通信外,和其他所有地址都可通信。
测试流程:
6.1、sub2-pod1和sub2-pod2互ping可通;
6.2、sub2-pod1和kube-system命名空间中的coredns-pod之间互ping可通;
6.3、sub2-pod1和sub3-pod1互ping不通;
6.4、sub2-pod1可以ping通外网(域名),外网也能和sub2-pod1-nodeport通信;
由于没有直接阻止具有某个label的命名空间配置,所有只能间接通过放行具有某些labels的命名空间以达到阻止的目的。
label设置比较灵活,可根据实际情况配置,有一下几种方式可供参考:
1、可以将放行的所有命名空间配置一个统一的label,这样只需要在配置中放行具有这个label的命名空间即可;
2、也可给每个命名空间配置一个label,这样需要在配置中放行各个不同label的命名空间;
3、可以将通用的系统命名空间设置一个统一的label,给业务命名空间配置不同的label;
本例采用第2种,给所有需要放行的命名空间配置不同的label;
命名空间加label
kubectl label ns kube-system ns=kube-system kubectl label ns kuboard ns=kuboard kubectl label ns kube-public ns=kube-public
网络隔离配置
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: ns-policy-2 namespace: sub2 spec: podSelector: {} ingress: - from: - podSelector: {} - ipBlock: cidr: 0.0.0.0/0 except: - 10.243.0.0/16 - from: - namespaceSelector: matchLabels: ns: kube-system - from: - namespaceSelector: matchLabels: ns: kuboard - from: - namespaceSelector: matchLabels: ns: kube-public egress: - to: - podSelector: {} - ipBlock: cidr: 0.0.0.0/0 except: - 10.243.0.0/16 - to: - namespaceSelector: matchLabels: ns: kube-system - to: - namespaceSelector: matchLabels: ns: kuboard - to: - namespaceSelector: matchLabels: ns: kube-public policyTypes: - Egress - Ingress
解释
podSelector
: {}
表示选择命名空间中的所有 Pod。policyTypes
: Ingress
和 Egress
表示同时控制进入和离开命名空间的流量。ingress
: from
字段中的 podSelector: {}
表示允许来自同一命名空间中的所有 Pod 的流量;ipBlock
表示允许来自除了 Kubernetes 内部网络 CIDR 地址范围10.243.0.0/16egress
: to
字段中的 podSelector: {}
表示允许流向同一命名空间中的所有 Pod 的流量;ipBlock
表示允许流向除了 Kubernetes 内部网络 CIDR 地址范围10.243.0.0/16from
和 to
: 使用 namespaceSelector
允许放行具有标签 ns=kube-system、ns=kuboardns、ns=kube-public
的命名空间中的 Pod 的流量,间接阻止了其他命名空间的流量。测试
创建策略
sub2-pod1 ping sub2-pod2(通)
sub2-pod1 ping kube-system命名空间中的coredns-pod(通)
sub2-pod1 ping sub3-pod1(不通)
sub2-pod1可以ping通外网、域名(通)
外部 访问sub2-pod1-nodeport(通)
取k8s集群任一节点ip 10.34.106.14