Kubernetes 网络策略
2020-04-15 by dongnan
开始之前
在前面的三篇文章中,至此我们已经准备好了K8S集群环境。
接下来我们将以在K8S集群运行一个真实的项目为目标,依次介绍项目所使用的K8S资源对象。
这个项目是一个典型的Web系统,使用 Java Spring Boot框架开发,需要使用 MySql、Redis数据库、NFS共享存储(多个Pod容器间共享文件)。
由于K8S环境部署在阿里云上,所以这里使用了阿里云提供的 RDS-Mysql 、RDS-Redis 数据库服务、NAS(NFS)
网络附加存储等中间件产品,对于K8S集群来说,我们需要将这些服务映射为K8S的资源对象。
项目使用的K8S的资源对象包括:
- PV&PVC,用于Pod数据卷(NFS)。
- Pod (volumeMounts、readinessProbe),挂载数据卷、健康检查。
- Secret,存储机密数据。
- Service,服务-外部域名(ExternalName)。
- NetworkPolicy,网络策略。
- LimitRange,限制资源。
- Ingress
环境
测试的k8s集群由一个Master管理节点、两个Worker计算节点组成,详细请参考这里。
目标
- 使用 NetworkPolicy隔离命名空间,例如隔离生产环境、测试环境的网络。
- 使用 NetworkPolicy网络策略保护Pod的网络服务 (白名单)。
举个栗子
Yaml文档
定义名称为 yyi-server-np 的网络策略:
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  namespace: yyi-prod
  name: yyi-server-np
spec:
  podSelector:
    matchLabels:
      app: yyi-server
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          app.kubernetes.io/name: ingress-nginx
    ports:
    - protocol: TCP
      port: 8080
这个NetworkPolicy对象的作用如下:
- 使用这个 NetworkPolicy对象,需要在yyi-prod命名空间中,并且必须带有app: yyi-server标签的Pod容器组。
- 进入方向,允许来自 ingress-nginx命名空间的Pod(Ingress控制器),访问yyi-server(Pod)容器的TCP协议8080端口。
- 进入方向,拒绝其它不符合规则的请求。
- 出方向,没有规则限制。
创建网络策略
kubectl apply -f yii-np.yaml
验证网络策略
查看 NetworkPolicy详细信息:
kubectl -n yyi-prod describe networkpolicies yyi-server-np 
Name:         yyi-server-np
Namespace:    yyi-prod
Labels:       <none>
              #...省略
Spec:
  PodSelector:     app=yyi-server
  Allowing ingress traffic:
    To Port: 8080/TCP
    From:
      NamespaceSelector: app.kubernetes.io/name=ingress-nginx
  Not affecting egress traffic
  Policy Types: Ingress
尝试使用 default 命名空间中的Pod 访问 yyi-server 容器的 8080 端口:
# 获得 Pod IP 地址
kubectl -n yyi-prod get pod -o wide
NAME                            READY   STATUS    RESTARTS   AGE    IP              NODE   #...省略  
yyi-server-78df87c94d-gxt6r     1/1     Running   0          164d   172.18.xx.120   host2
# 登录 Pod 控制台
kubectl exec -ti demo-secret-cf58d4f99-8n6wj /bin/bash
# 尝试访问 yyi-server 的端口
root@demo-secret-cf58d4f99-8n6wj:/var/www/html# telnet 172.18.xx.120 8080
Trying 172.18.xx.120...
telnet: Unable to connect to remote host: Connection timed out
由于 yyi-server-np 网络策略的规则,拒绝了访问请求。
NetworkPolicy
NetworkPolicy 定义了一组Pod是否允许相互通信,或者Pod与网络中的其它端点通信的规则。
NetworkPolicy 对象使用标签选择Pod,并规定选中的Pod可以执行什么样的网络通信。
NetworkPolicy 由网络插件实现,因此使用的网络插件必须能够支持 NetworkPolicy 才可以使用此特性。
参数含义
重点看下spec段包,含了定义网络策略的主要信息:
podSelector:
- 同名称空间中,符合此标签选择器.spec.podSelectorr的Pod都将应用这个NetworkPolicy。
- 如果该字段为空,则将对名称空间中所有的Pod应用这个NetworkPolicy。
policyTypes:
- 是一个数组类型的字段,该数组中可以包含 Ingress、Egress中的一个,也可能两个都包含。
- 该字段默认将始终包含 Ingress,当NetworkPolicy中包含出方向的规则时,Egress也将被添加到默认值。
ingress:
- ingress,代表入方向的白名单规则,每一条规则都将允许与- from和- ports匹配的入方向的网络流量发生关联。
egress:
- egress,代表出方向的白名单规则,每一条规则都将允许与- to和- ports匹配的出方向的网络流量发生。
.spec.ingress.from 和 .spec.egress.to 字段可以指定4种类型的标签选择器:
- podSelector: 选择与 NetworkPolicy相同名称空间中的 Pod 作为入方向访问控制规则的源或者出方向访问控制规则的目标。
- namespaceSelector: 选择某个名称空间所有的Pod 作为入方向访问控制规则的源或者出方向访问控制规则的目标。
- namespaceSelector && podSelector: 在一个 to/from条目中同时包含这两个选择器,将选中指定名称空间中的指定 Pod。
- ipBlock 可选择IP地址CIDR范围作为入方向访问控制规则的源或者出方向访问控制规则的目标。这里应该指定的是集群外部的IP,因为集群内部 Pod 的 IP 地址是临时分配的,且不可预测。
小结
- NetworkPolicy由网络插件实现,因此使用的网络插件必须能够支持- NetworkPolicy才可以使用。
- 默认情况下 Pod都是非隔离的,可以接受来自任何请求方的网络请求。
- 如果一个 NetworkPolicy的标签选择器选中了某个Pod,则该Pod将变成隔离的,并将拒绝任何不被NetworkPolicy许可的网络连接。
- NetworkPolicy不会相互冲突,而是相互叠加的。
- 如果多个 NetworkPolicy选中了同一个Pod,则该Pod可以接受这些NetworkPolicy当中任何一个NetworkPolicy定义的规则。
- 因此,NetworkPolicy的顺序并不重要,因为不会影响到最终的结果。