在Kubernetes中,网络隔离功能是通过叫NetworkPolicy的API对象来描述的。
    如下一个完整的NetworkPolicy定义:

    1. apiVersion: networking.k8s.io/v1
    2. kind: NetworkPolicy
    3. metadata:
    4. name: test-network-policy
    5. namespace: default
    6. spec:
    7. podSelector:
    8. matchLabels:
    9. role: db
    10. policyTypes:
    11. - Ingress
    12. - Egress
    13. ingress:
    14. - from:
    15. - ipBlock:
    16. cidr: 172.17.0.0/16
    17. except:
    18. - 172.17.1.0/24
    19. - namespaceSelector:
    20. matchLabels:
    21. project: myproject
    22. - podSelector:
    23. matchLabels:
    24. role: frontend
    25. ports:
    26. - protocol: TCP
    27. port: 6379
    28. egress:
    29. - to:
    30. - ipBlock:
    31. cidr: 10.0.0.0/24
    32. ports:
    33. - protocol: TCP
    34. port: 5978

    解释:

    • podSelector:定义这个NetworkPolicy的限制范围,上面就是定义namespace中标签为role: db的Pod,如果为空,则标识这个namespace下的所有Pod,如果一旦被podSelector选中,则这个Pod就会进入拒绝所有的状态,即这个Pod既不允许被外界访问,也不能对外界发起访问。
    • policyTypes:定义NetworkPolicy的类型,ingress表示流入请求,egress表示流出请求。
    • ingress:定义流入的规则
    • egress:定义流出的规则

    其中ingress字段中的from和ports,定义允许流入的白名单和端口,这里面的白名单有三种限制方式:

    • ipBlock:限制IP,上面定义的即为允许172.17.0.0/16但不是172.17.1.0/24的网段请求;
    • namespaceSelector:限制namespace,上面定义即为允许default namespace下标签为project: myproject的的Pod请求;
    • podSelector:限制Pod,上面定义即为允许标签为role: frontend的Pod请求;

    而egress字段中的to和ports,则指定允许流出的白名单和端口,这里的限制方式和ingress类似。

    注意:下面这两种白名单的定义方式是不一样的。
    (1)、第一种

    1. ...
    2. ingress:
    3. - from:
    4. - namespaceSelector:
    5. matchLabels:
    6. user: alice
    7. - podSelector:
    8. matchLabels:
    9. role: client
    10. ...

    (2)、第二种

    1. ...
    2. ingress:
    3. - from:
    4. - namespaceSelector:
    5. matchLabels:
    6. user: alice
    7. podSelector:
    8. matchLabels:
    9. role: client
    10. ...

    这两种看起来类似,但是其表示的意义是不一样的,对于第一种表示的是一种OR(或)的关系,对于这种情况只要其中一种规则满足要求都可以通过,而对于第二种则表示AND(与)的关系,必须两种同时满足才会通过。

    Kubernetes对Pod的网络隔离其实是靠宿主机上生成NetworkPolicy对应的iptables规则来实现的。
    比如定义好了上面的NetworkPolicy,那么就会生成类似下面的iptables规则:

    1. iptables -A KUBE-NWPLCY-CHAIN -s $srcIP -d $dstIP -p $protocol -m $protocol --dport $port -j ACCEPT

    其中:

    • srcIP:原IP
    • dstIP:目的IP
    • protocol:协议
    • port:端口

    这些参数都是从我们定义的NetworkPolicy中取出来,然后还将对所有对被隔离Pod的访问请求都转发到KUBE-NWPLCY-CHAIN上去匹配,如果匹配不通过则拒绝。
    第一组KUBE-NWPLCY-CHAIN规则如下:

    1. iptables -A FORWARD -d $podIP -m physdev --physdev-is-bridged -j KUBE-POD-SPECIFIC-FW-CHAIN
    2. iptables -A FORWARD -d $podIP -j KUBE-POD-SPECIFIC-FW-CHAIN

    其中:

    • 第一条FORWARD链的作用是通过本机网桥设备发往podIP的IP包;
    • 第二条就是拦截跨主机通信,定义规则都到KUBE-POD-SPECIFIC-FW-CHAIN规则上

    第二组KUBE-POD-SPECIFIC-FW-CHAIN规则如下:

    1. iptables -A KUBE-POD-SPECIFIC-FW-CHAIN -j KUBE-NWPLCY-CHAIN
    2. iptables -A KUBE-POD-SPECIFIC-FW-CHAIN -j REJECT --reject-with icmp-port-unreachable

    其中:

    • 第一条是把数据包发到KUBE-NWPLCY-CHAIN去匹配;
    • 第二条就是把不满足NetworkPolicy中定义的请求都拒绝掉,从而实现对容器的隔离;

    默认的Policies:
    (1)、默认拒绝所有Ingress:

    1. apiVersion: networking.k8s.io/v1
    2. kind: NetworkPolicy
    3. metadata:
    4. name: default-deny
    5. spec:
    6. podSelector: {}
    7. policyTypes:
    8. - Ingress

    (2)、默认允许所有ingress:

    1. apiVersion: networking.k8s.io/v1
    2. kind: NetworkPolicy
    3. metadata:
    4. name: allow-all
    5. spec:
    6. podSelector: {}
    7. ingress:
    8. - {}
    9. policyTypes:
    10. - Ingress

    (3)、默认拒绝所有Egress:

    1. apiVersion: networking.k8s.io/v1
    2. kind: NetworkPolicy
    3. metadata:
    4. name: default-deny
    5. spec:
    6. podSelector: {}
    7. policyTypes:
    8. - Egress

    (4)、默认允许所有Egress:

    1. apiVersion: networking.k8s.io/v1
    2. kind: NetworkPolicy
    3. metadata:
    4. name: allow-all
    5. spec:
    6. podSelector: {}
    7. egress:
    8. - {}
    9. policyTypes:
    10. - Egress

    (5)、拒绝所有Ingress和Egress:

    1. apiVersion: networking.k8s.io/v1
    2. kind: NetworkPolicy
    3. metadata:
    4. name: default-deny
    5. spec:
    6. podSelector: {}
    7. policyTypes:
    8. - Ingress
    9. - Egress

    例子:
    1、创建两个namespace

    1. # kubectl create ns dev
    2. # kubectl create ns sit

    2、给dev下的所有pod配置Ingress权限,不允许所有人访问

    1. apiVersion: networking.k8s.io/v1
    2. kind: NetworkPolicy
    3. metadata:
    4. name: networkpolicy-ingress-demo
    5. spec:
    6. podSelector: {}
    7. policyTypes:
    8. - Ingress

    然后使其作用于dev

    1. # kubectl apply -f ingress-demo.yaml -n dev

    我们在dev里创建一个Pod,在外部访问查看情况

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: myapp
    5. spec:
    6. containers:
    7. - name: myapp
    8. image: nginx:1.7.9
    9. imagePullPolicy: IfNotPresent
    10. command:
    11. - "/bin/sh"
    12. - "-c"
    13. args:
    14. - "nginx && sleep 3600"

    启动Pod

    1. # kubectl apply -f pod-demo.yaml -n dev