NetworkPolicy网络策略以及举例说明
网络策略(NetworkPolicy)是一种关于pod间及pod与其他网络端点间所允许的通信规则的规范。NetworkPolicy 资源使用标签选择pod,并定义选定pod所允许的通信规则。
前提
网络策略通过网络插件来实现,所以用户必须使用支持 NetworkPolicy 的网络解决方案 - 简单地创建资源对象,而没有控制器来使它生效的话,是没有任何作用的。
网络插件:
- Calico
- Romana
- Weave 网络
隔离和非隔离的Pod
默认情况下,Pod是非隔离的,它们接受任何来源的流量。Pod可以通过相关的网络策略进行隔离。一旦命名空间中 NetworkPolicy 配置选择了特定的Pod,该Pod会拒绝网络策略所不允许的连接。 (命名空间下其他未被网络策略所选择的Pod会继续接收所有的流量)
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
除非选择支持网络策略的网络解决方案,否则上面的例子没有任何效果。
必填字段: 与所有其他的Kubernetes配置一样,NetworkPolicy 需要 apiVersion、 kind和 metadata 。
spec: NetworkPolicy spec 中包含了在一个命名空间中定义特定网络策略所需的所有信息.
podSelector: 每个 NetworkPolicy 都包括一个 podSelector ,它对该策略所应用的一组Pod进行选择。因为 NetworkPolicy 目前只支持定义 ingress 规则,这里的 podSelector 本质上是为该策略定义 "目标pod" 。示例中的策略选择带有 "role=db" 标签的pod。空的 podSelector 选择命名空间下的所有pod。
policyTypes: 每个 NetworkPolicy 都包含一个 policyTypes 列表,其中包含 Ingress 或 Egress 或两者兼具。policyTypes 字段表示给定的策略是应用于 进入所选 Pod 的入站流量还是来自所选 Pod 的出站流量,或两者兼有。 如果 NetworkPolicy 未指定 policyTypes 则默认情况下始终设置 Ingress; 如果 NetworkPolicy 有任何出口规则的话则设置 Egress。
ingress: 每个 NetworkPolicy 包含一个 ingress 规则的白名单列表。(其中的)规则允许同时匹配 from 和 ports 部分的流量。示例策略中包含一条简单的规则: 它匹配一个单一的端口,来自两个来源中的一个, 第一个通过 namespaceSelector 指定,第二个通过 podSelector 指定。
egress: 每个 NetworkPolicy 包含一个 egress 规则的白名单列表。每个规则都允许匹配 to 和 port 部分的流量。该示例策略包含一条规则,该规则将单个端口上的流量匹配到 10.0.0.0/24 中的任何目的地。
所以,示例网络策略:
1.隔离 "default" 命名空间下标签是 "role=db" 的pod (如果它们不是已经被隔离的话)。
2.(Ingress 规则)允许以下 Pod 连接到 "default" 名字空间下的带有 "role=db" 标签的所有 Pod 的 6379 TCP 端口:
- "default" 命名空间下带有 "role=frontend" 标签的所有 Pod
- 带有 "project=myproject" 标签的所有命名空间中的 Pod
- IP 地址范围为 172.17.0.0–172.17.0.255 和 172.17.2.0–172.17.255.255(即,除了 172.17.1.0/24 之外的所有 172.17.0.0/16)
3.(Egress 规则)允许从带有 "role=db" 标签的命名空间下的任何 Pod 到 CIDR 10.0.0.0/24 下 5978 TCP 端口的连接。
选择器 to 和 from 的行为
可以在 ingress from 部分或 egress to 部分中指定四种选择器:
podSelector: 这将在与 NetworkPolicy 相同的命名空间中选择特定的 Pod,应将其允许作为入口源或出口目的地。
namespaceSelector: 这将选择特定的命名空间,应将所有 Pod 用作其输入源或输出目的地。
namespaceSelector 和 podSelector: 一个指定 namespaceSelector 和 podSelector 的 to/from 条目选择特定命名空间中的特定 Pod。注意使用正确的YAML语法;
下面的策略,在 from 数组中仅包含一个元素,只允许来自标有 role = client 的 Pod 且该 Pod 所在的命名空间中标有user=alice的连接。
...
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
podSelector:
matchLabels:
role: client
...
这项策略,在 from 数组中包含两个元素,允许来自本地命名空间中标有 role = client 的 Pod 的连接,或来自任何命名空间中标有user = alice的任何Pod的连接。
...
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
- podSelector:
matchLabels:
role: client
...
ipBlock: 这将选择特定的 IP CIDR 范围以用作入口源或出口目的地。 这些应该是群集外部 IP,因为 Pod IP 存在时间短暂的且随机产生。
群集的入口和出口机制通常需要重写数据包的源 IP 或目标 IP。在发生这种情况的情况下,不确定在 NetworkPolicy 处理之前还是之后发生,并且对于网络插件,云提供商,Service 实现等的不同组合,其行为可能会有所不同。
在进入的情况下,这意味着在某些情况下,您可以根据实际的原始源 IP 过滤传入的数据包,而在其他情况下,NetworkPolicy 所作用的 源IP 则可能是 LoadBalancer 或 Pod的节点等。
对于出口,这意味着从 Pod 到被重写为集群外部 IP 的 Service IP 的连接可能会或可能不会受到基于 ipBlock 的策略的约束。
默认策略
默认情况下,如果命名空间中不存在任何策略,则所有进出该命名空间中的Pod的流量都被允许。以下示例使您可以更改该命名空间中的默认行为。
默认拒绝所有入口流量
创建选择所有容器但不允许任何进入这些容器的入口流量的 NetworkPolicy 来为命名空间创建 "default" 隔离策略。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny # 没有设置命令空间则默认命令空间为default
spec:
podSelector: {} # 空的 podSelector 选择命名空间下的所有pod
policyTypes: # 入口网络策略
- Ingress
# 未设置进入条件,也就是不允许任何进入
这样可以确保即使容器没有选择其他任何 NetworkPolicy,也仍然可以被隔离。此策略不会更改默认的出口隔离行为。
默认允许所有入口流量
如果要允许所有流量进入某个命名空间中的所有 Pod(即使添加了导致某些 Pod 被视为“隔离”的策略),则可以创建一个策略来明确允许该命名空间中的所有流量。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
spec:
podSelector: {}
ingress: # 未设置进入来源的限制条件
- {}
policyTypes: # 入口网络策略
- Ingress
默认拒绝所有出口流量
您可以通过创建选择所有容器但不允许来自这些容器的任何出口流量的 NetworkPolicy 来为命名空间创建 "default" egress 隔离策略。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {} # 该命名空间下的所有pod
policyTypes: # 出口网络策略
- Egress
# 未设置出口条件,也就是不允许任何出口流量
这样可以确保即使没有被其他任何 NetworkPolicy 选择的 Pod 也不会被允许流出流量。此策略不会更改默认的 ingress 隔离行为。
默认允许所有出口流量
如果要允许来自命名空间中所有 Pod 的所有流量(即使添加了导致某些 Pod 被视为“隔离”的策略),则可以创建一个策略,该策略明确允许该命名空间中的所有出口流量。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
spec:
podSelector: {}
egress:
- {}
policyTypes:
- Egress
默认拒绝所有入口和所有出口流量
可以为命名空间创建 "default" 策略,以通过在该命名空间中创建以下 NetworkPolicy 来阻止所有入站和出站流量.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
这样可以确保即使没有被其他任何 NetworkPolicy 选择的 Pod 也不会被允许进入或流出流量。
SCTP 支持
Kubernetes 支持 SCTP 作为 NetworkPolicy 定义中的协议值作为 alpha 功能提供。要启用此功能,集群管理员需要在 apiserver 上启用 SCTPSupport 功能门,例如 “--feature-gates=SCTPSupport=true,...”。启用功能门后,用户可以将 NetworkPolicy 的 protocol 字段设置为 SCTP。 Kubernetes 相应地为 SCTP 关联设置网络,就像为 TCP 连接一样。
CNI插件必须在 NetworkPolicy 中将 SCTP 作为 protocol 值支持。
NetworkPolicy网络策略入门例子
首先需要有一个支持网络策略的 Kubernetes 集群。已经有许多支持 NetworkPolicy 的网络提供商,包括:
- Calico
- Romana
- Weave 网络
注意:以上列表是根据产品名称按字母顺序排序,而不是按推荐或偏好排序。下面示例对于使用了上面任何提供商的 Kubernetes 集群都是有效的
创建一个nginx deployment 并且通过服务将其暴露
为了查看 Kubernetes 网络策略是怎样工作的,可以从创建一个nginx deployment 并且通过服务将其暴露开始
$ kubectl run nginx --image=nginx --replicas=2
deployment "nginx" created
$ kubectl expose deployment nginx --port=80
service "nginx" exposed
在 default 命名空间下运行了两个 nginx pod,而且通过一个名字为 nginx 的服务进行了暴露
$ 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
测试服务能够被其它的 pod 访问
从其它的 pod 访问这个新的 nginx 服务。为了验证它,从 default 命名空间下的其它 pod 来访问该服务。请您确保在该命名空间下没有执行孤立动作。
启动一个 busybox 容器,然后在容器中使用 wget 命令去访问 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)
/ #
限制访问 nginx 服务
想限制 nginx 服务,只让那些拥有标签 access: true 的 pod 访问它,那么您可以创建一个只允许从那些 pod 连接的 NetworkPolicy:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: access-nginx
spec:
podSelector:
matchLabels:
run: nginx
ingress:
- from:
- podSelector:
matchLabels:
access: "true"
为服务指定策略
使用 kubectl 工具根据上面的 nginx-policy.yaml 文件创建一个 NetworkPolicy:
$ kubectl create -f nginx-policy.yaml
networkpolicy "access-nginx" created
当访问标签没有定义时测试访问服务
如果您尝试从没有设定正确标签的 pod 中去访问 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)
wget: download timed out
/ #
定义访问标签后再次测试
创建一个拥有正确标签的 pod,您将看到请求是被允许的:
$ 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)
/ #