深入理解Kubernetes网络策略

【编者的话】当我们逐渐向着微服务、云原生迈进的时候,传统静态的、相对简单的网络安全策略开始显得吃力。 Kubernetes 的 Network Policy 特性正是来解决这个问题的。在刚刚出炉不久的1.7版本中,该特性也被扶正成为GA。让我们来一起看看 Network Policy 是什么,能为我们做什么,以及是如何实现的。

【3 天烧脑式基于Docker的CI/CD实战训练营 | 北京站】本次培训围绕基于Docker的CI/CD实战展开,具体内容包括:持续集成与持续交付(CI/CD)概览;持续集成系统介绍;客户端与服务端的 CI/CD 实践;开发流程中引入 CI、CD;Gitlab 和 CI、CD 工具;Gitlab CI、Drone 的使用以及实践经验分享。

CNI

Kubernetes 对网络做了较好的抽象。它将对网络的需求交给外部的组件完成,也就是 CNI driver。

Pod 的网络必须满足以下三个需求:

  1. 所有 Pod 之间无需 NAT 即可互通
  2. 主机和 Pod 之间无需 NAT 即可互通
  3. Pod 自省的 IP 地址和之外部看到该 Pod 的地址一致

CNI 对网络的实现做了详细的定义。CNI 的实现可以被分成三种:

  1. 3 层路由实现
  2. Overlay 实现
  3. 2 层交换实现

现在比较常用的 CNI 实现有:Flannel、Calico、Weave。 Flannel 通过 VXLan Overlay 来实现跨主机 Pod 网络, Calico 则完全通过 3 层路由来实现了跨主机的容器网络,Weave也是 Overlay 的实现。

什么是Network Policy

随着业务逻辑的复杂化,微服务的流行,越来越多的云服务平台需要大量模块之间的网络调用。

传统的单一外部防火墙,或依照应用分层的防火墙的做法渐渐无法满足需求。在一个大的集群里面,各模块,业务逻辑层,或者各个职能团队之间的网络策略的需求越来越强。

Kubernetes 在 1.3 引入了 Network Policy 这个功能来解决这个问题。这些 Policy 允许用户在同一个 Cluster 内实现网络的隔离。也就是在某些需要的 Pod 之间架起防火墙。可以简单的理解为各个微服务之间的动态防火墙。也有人把这叫做分布式防火墙。

并非所有的网络驱动都支持这个功能。比如大家比较熟悉的,比较流行的 Flannel 就还没有加入对 Network Policy 的支持。Calico 和 Weave 都各自实现了 NPC(network policy controller)。虽然 Flannel 不支持 Network Policy。但是,可以使用 Flannel 提供网络方案,同时使用 Calico 或者Weave 的 NPC 组件来共同完成。Canal 就提供了将 Flannel 和 Calico NPC 组合的方案。

DEMO

下面我们就以Calico为基础,给大家做一个demo。

这里我已经搭好了一个 Kubernetes 的简单的集群:只有一个 master 和两个 minion。我们先来部署 Calico。这里要注意的是,由于我们要 demo 的是最新的 Kubernetes API,我们必须使用 Kubernetes 1.7 和 Calico 2.3,并且,Calico只能配置成 Kubernetes Datastore 的模式。在这种模式下,Calico 对网络状态的控制是通过 Kubernetes API 来完成的。另外还有一种模式是通过 etcd 集群。那种模式暂时还不支持最新的API。Kubernetes Datastore 这种方式有时也叫做KDD — Kubernetes datastore driver。

在进行 KDD 模式的 Calico 安装时要注意以下这么几点:

  1. IPAM 要使用 host-local
  2. 通过 controller manager 来分配 CIDR

细节请点击:docs.projectcalico.org/v2.3/gettin…

配置好 Calico之后,我们来看一个简单的 demo,实际操作一下 Network Policy:

为了简单起见,我们会直接使用 default namespace。如果你在一个现有的环境里面, 可以将以下的命令在一个独立的 namespace 里面运行。

创建 namespace 使用这个命令:
kubectl create ns np-demo
接下来运行一个简单的 nginx deployment 并用80端口暴露服务:
kubectl run nginx --replicas=2 --image=nginx deployment "nginx" created kubectl expose deploy nginx --port=80 service "nginx" exposed
现在我们还没有做任何的限制,所以 Kubernetes 缺省情况是所有 Pod 都是开放的。

我们来用一个 BusyBox 的 Pod 验证一下:
kubectl run busy --rm -ti --image busybox /bin/sh If you don't see a command prompt, try pressing enter. / # wget -q nginx -O - | head -4
上面的 Wget 命令是在 BusyBox 这个 Pod 里面执行的。-q-O - 的组合会使这个命令在命令行输出 nginx 的缺省首页,这表明我们的验证是成功的。用 Ctl-D 退出容器。

接下来我们就要加入限制了。我们的做法是先限制对所有 Pod 的访问,然后建立白名单。 kubectl apply下面的 YAML 文件就可以限制所有访问:
kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: name: default-deny spec: podSelector:
注意我们提供了一个空的 podSelector。

我们再试着用之前的 BusyBox 的方式来访问一下:
kubectl run busy --rm -ti --image busybox /bin/sh / # wget -q --timeout=5 nginx -O -

这此我们设置了 5 秒的超时。因为访问被拒接,所以确实会超时:
wget: download timed out
好,我们的第一个 Network Policy 已经生效了。然而,限制对所有 Pod 的访问显然是没有意义的。接下来我们建立一个白名单 . apply 下面的 YAML 文件:
```kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: access-nginx
spec:
podSelector:
matchLabels:
run: nginx
ingress:

    - from:
      - podSelector:
          matchLabels:
            run: access```复制代码

这个 Network Policy 的意思是:标签 run:access 选中的 Pod 可以访问标签 run:nginx 的 Pod,也就是我们 demo 开始时创建的 Nginx 的 Pod。这些 label 都是 kubectl run 命令自动 添加的。

接下来我们试试看能否成功地访问了:
kubectl run access --rm -ti --image busybox /bin/sh wget -q nginx -O -
我们依然会看到熟悉的 Nginx 缺省首页。如果我们运行一个不符合上述 selector 的 Pod,就无法访问。这个留给有兴趣的同学自己回去验证。

如果你接触过 1.7 之前的 Network Policy 的话,你可能会发现这里的 API 有些不同。Kubernetes 1.7 已经将 Network Policy 正式提升到 GA。

正式的 API 和之前的 API 区别有:

  1. 不再使用 Annotation 来表达 default-deny 等这样的规则
  2. API version 从 extension/beta1 升级到了 networking.k8s.io/v1

实现

Calico 的实现是基于 iptables 的。在每个 chain 的顶端,Calico 都插入了一条定制的 chain,从而使得 packet 优先经过 Calico 定义的规则。我们在其中一个 minion 上面运行 iptables-save -c 就可以检查这些规则。可以看出 kube-proxy 和 Calico 都定义了大量的 iptable 规则。

这里细节很多,我们只需要关注这几点:

Calico 使用 conntrack 来优化。就是说,一旦一个连接已经建立,之后的packet都会直接被允许通过。比如:
-A cali-fw-cali7af3f94d3a1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A cali-fw-cali7af3f94d3a1 -m conntrack --ctstate INVALID -j DROP
名为 cali-pi-xxxx 的规则是负责 Network Policy Ingress 的。我们可以想见,如果我们定义了很多 Policy,一个一个单独定义的规则会导致性能下降。这里 Calico 利用了 iptables 的 ipset 特性。使得一个 rule 可以通过 hash 表来匹配多种地址。
`-A cali-pi-_G7e-YAvXRsfDoqGDf36 -m set --match-set cali4-s:2I5R46OBA_TBIUlpH0dCd_n src -j MARK --set-xmark 0x1000000/0x1000000 -A cali-pi-_G7e-YAvXRsfDoqGDf36 -m mark --mark 0x1000000/0x1000000 -j RETURN
Weave 的实现也类似。底层还是使用了 iptables 和 netfilter。Weave 也创建了自定义的 chain。但由于一个是 Overlay 一个是路由,规则还是有些不同的。

另外一个细微的不同是,Weave使用了 -m state 而不是 -m conntrack。conntrack 是比较新的语法,但实际使用中功能是一样的。下面是几个 Weave 安装的 iptables rules 的例子:
FORWARD chain: -o weave -j WEAVE-NPC -o weave -j DROP WEAVE_NPC chain: -m state --state RELATED,ESTABLISHED -j ACCEPT -m state --state NEW -j WEAVE-NPC-DEFAULT -m state --state NEW -j WEAVE-NPC-INGRESS -m set --match-set weave-v/q_G.;Q?uK]BuDs2 dst -j ACCEPT -m set --match-set weave-k?Z;25^M}|1s7P3|H dst -j ACCEPGo

Q&A

Q:Calico 和 Weave 从 Policy 处理性能来看,两者哪个更优?

A:两者在 iptables 层面上的实现原理是一样的。都用了-m
state 和 ipset 优化,性能差别不大。

Q:Calico 结合 Kubernetes 怎么实现多租户,比如网络隔离之类的?

A:可以考虑用 namespace 来隔离。没有 Network Policy 的情况下当然是互通的。但是 Kubernetes 的 Network Policy 支持 namespaceSelector,可以轻松搞定。

Q:Weave、Calico、Flannel 比较,适用场景和优缺点是什么,Flannel out了么?

A:各有各的市场 :-)。
Flannel 比较简单,资源消耗也会小些。Flannel 不能算 out 了。Cannel 的出现将 Flannel 和 Calico 整合了起来。

Q:NPC 必须用 iptables 实现吗?在某些情况下,Pod 出向流量并不会由主机协议栈,这样 iptables 就用不了,这种情况下 NPC 怎么实现呢 ?

A:Calico、Weave、Romana 的 NPC 都是通过 iptables 实现的。Pod
egress 不通过主机协议栈也会通过 netfilter。

原文链接

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值