最近学习k8s遇到很多问题,建了一个qq群:153144292,交流devops、k8s、docker等
配置网络策略
在Kubernetes系统中,报文的流入和流出的核心组件是Pod资源,它们也是网络策略功能的主要应用
对象。NetworkPolicy对象通过podSelector选择 一组Pod资源作为控制对象。NetworkPolicy是定义在一
组Pod资源之上用于管理入站流量,或出站流量的一组规则,有可以是出入站规则一起生效,规则的生效
模式通常由spec.policyTypes进行定义。
默认情况下,Pod对象的流量控制是为空的,报文可以自由出入。在附加网络策略之后,Pod对象会因
为NetworkPolicy而被隔离,一旦名称空间中有任何NetworkPolicy对象匹配了某特定的Pod对象,则该Pod
将拒绝NetworkPolicy规则中不允许的所有连接请求,但是那些未被匹配到的Pod对象依旧可以接受所有流
量。
就特定的Pod集合来说,入站和出站流量默认是放行状态,除非有规则可以进行匹配。还有一点需要注
意的是,在spec.policyTypes中指定了生效的规则类型,但是在networkpolicy.spec字段中嵌套定义了没有
任何规则的Ingress或Egress时,则表示拒绝入站或出站的一切流量。
定义网络策略的基本格式如下:
apiVersion: networking.k8s.io/v1 #定义API版本
kind: NetworkPolicy #定义资源类型
metadata:
name: allow-myapp-ingress #定义NetwokPolicy的名字
namespace: default
spec: #NetworkPolicy规则定义
podSelector: #匹配拥有标签app:myapp的Pod资源
matchLabels:
app: myapp
policyTypes ["Ingress"] #NetworkPolicy类型,可以是Ingress,Egress,或者两者共存
ingress: #定义入站规则
- from:
- ipBlock: #定义可以访问的网段
cidr: 10.244.0.0/16
except: #排除的网段
- 10.244.3.0/24
- podSelector: #选定当前default名称空间,标签为app:myapp可以入站
matchLabels:
app: myapp
ports: #开放的协议和端口定义
- protocol: TCP
port: 80
该网络策略就是将default名称空间中拥有标签"app=myapp"的Pod资源开放80/TCP端口给10.244.0.0/16网段,
并排除10.244.3.0/24网段的访问,并且也开放给标签为app=myapp的所有Pod资源进行访问。
[root@master network-policy-demo]# cat httpd.yaml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: httpd
spec:
replicas: 3
template:
metadata:
labels:
run: httpd
spec:
containers:
- name: httpd
image: httpd:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: httpd-svc
spec:
type: NodePort
selector:
run: httpd
ports:
- protocol: TCP
nodePort: 30000
port: 8080
targetPort: 80
[root@master network-policy-demo]# kubectl apply -f httpd.yaml
deployment.apps/httpd created
service/httpd-svc created
[root@master network-policy-demo]# kubectl get pods -o wide |grep httpd
httpd-5f955cf6d5-4htlh 1/1 Running 0 2m13s 10.244.2.3 node02 <none> <none>
httpd-5f955cf6d5-rcrjc 1/1 Running 0 2m13s 10.244.2.2 node02 <none> <none>
httpd-5f955cf6d5-xssvt 1/1 Running 0 2m13s 10.244.1.2 node01 <none> <none>
[root@master network-policy-demo]# kubectl get svc httpd-svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd-svc NodePort 10.107.167.46 <none> 8080:30000/TCP 2m35
当前没有定义任何Network Policy,验证应用的访问:
#启动一个busybox Pod,可以访问Service,也可以ping副本的Pod
[root@master network-policy-demo]# kubectl run busybox --rm -it --image=busybox /bin/sh
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
If you don't see a command prompt, try pressing enter
/ # wget httpd-svc:8080
Connecting to httpd-svc:8080 (10.107.167.46:8080)
index.html 100% |***********************************************************************************************************************************************| 45 0:00:00 ETA
/ # ping -c 2 10.244.2.3
PING 10.244.2.3 (10.244.2.3): 56 data bytes
64 bytes from 10.244.2.3: seq=0 ttl=63 time=0.203 ms
64 bytes from 10.244.2.3: seq=1 ttl=63 time=0.088 ms
--- 10.244.2.3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.088/0.145/0.203 ms
#集群节点也可以访问Sevice和ping通副本Pod
[root@node01 ~]# curl 10.107.167.46:8080
<html><body><h1>It works!</h1></body></html>
[root@node01 ~]# ping -c 2 10.244.2.3
PING 10.244.2.3 (10.244.2.3) 56(84) bytes of data.
64 bytes from 10.244.2.3: icmp_seq=1 ttl=63 time=0.389 ms
64 bytes from 10.244.2.3: icmp_seq=2 ttl=63 time=0.217 ms
#集群外部访问10.249.6.100:30000也是通的
[root@node01 ~]# curl 10.249.6.100:30000
<html><body><h1>It works!</h1></body></html>
那么下面再去设置不同的Network Policy来管控Pod的访问。
管控入站流量
NetworkPolicy资源属于名称空间级别,它的作用范围为其所属的名称空间。
1、设置默认的Ingress策略
用户可以创建一个NetworkPolicy来为名称空间设置一个默认的隔离策略,该策略选择所有的Pod对
象,然后允许或拒绝任何到达这些Pod的入站流量,如下:
[root@master network-policy-demo]# vim policy-demo.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
spec:
podSelector: {}
policyTypes: ["Ingress"]
#指明了Ingress生效规则,但不定义任何Ingress字段,因此不能匹配任何源端点,从而拒绝所有的入站流量
[root@master network-policy-demo]# kubectl apply -f policy-demo.yaml
networkpolicy.networking.k8s.io/deny-all-ingress created
[root@master network-policy-demo]# kubectl get networkpolicy
NAME POD-SELECTOR AGE
deny-all-ingress <none> 17s
#此时再去访问测试,是无法ping通,无法访问的
round-trip min/avg/max = 0.088/0.145/0.203 ms
/ # wget httpd-svc:8080
Connecting to httpd-svc:8080 (10.107.167.46:8080)
[root@node01 ~]# curl 10.249.6.101:30000
^C
[root@node01 ~]# curl 10.249.6.102:30000
^C
[root@node01 ~]# curl 10.249.6.100:30000
^C
如果要将默认策略设置为允许所有入站流量,只需要定义Ingress字段,并将这个字段设置为空,以匹配所有源
端点,但本身不设定网络策略,就已经是默认允许所有入站流量访问的,下面给出一个定义的格式:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
spec:
podSelector: {}
policyTypes: ["Ingress"]
ingress:
- {}
实践中,通常将默认的网络策略设置为拒绝所有入站流量,然后再放行允许的源端点的入站流量。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: access-httpd
spec:
podSelector:
matchLabels:
run: httpd
policyTypes: ["Ingress"]
ingress:
- from:
- ipBlock:
cidr: 10.244.0.0/16
except:
- 10.244.2.0/24
- 10.244.1.0/24
- podSelector:
matchLabels:
access: "true"
ports:
- protocol: TCP
port: 80
[root@master network-policy-demo]# kubectl delete networkpolicy deny-all-ingress
networkpolicy.extensions "deny-all-ingress" deleted
[root@master network-policy-demo]# kubectl apply -f policy-demo.yaml
networkpolicy.networking.k8s.io/access-httpd created
[root@master network-policy-demo]# kubectl get networkpolicy
NAME POD-SELECTOR AGE
access-httpd run=httpd 105s
验证NetworkPolicy的有效性(放行):
[root@master network-policy-demo]# kubectl run busybox --rm -it --labels="access=true" --image=busybox /bin/sh
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
If you don't see a command prompt, try pressing enter.
/ # wget httpd-svc:8080
Connecting to httpd-svc:8080 (10.107.167.46:8080)
index.html 100% |***********************************************************************************************************************************************| 45 0:00:00 ETA
/ #
[root@node01 ~]# curl 10.249.6.100:30000
<html><body><h1>It works!</h1></body></html>
[root@node01 ~]# curl 10.249.6.102:30000
^C
[root@node01 ~]# curl 10.249.6.101:30000
不知道是配置的问题还是什么问题,感觉网络策略不太好用,有点失灵
管控出站流量
通常,出站的流量默认策略应该是允许通过的,但是当有精细化需求,仅放行那些有对外请求需
要的Pod对象的出站流量,也可以先为名称空间设置“禁止所有”的默认策略,再细化制定准许的策略。
networkpolicy.spec中嵌套的Egress字段用来定义出站流量规则。
设定默认Egress策略
和Igress一样,只需要通过policyTypes字段指明生效的Egress类型规则,然后不去定义Egress字
段,就不会去匹配到任何目标端点,从而拒绝所有的出站流量。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-egress
spec:
podSelector: {}
policyTypes: ["Egress"]
实践中,需要进行严格隔离的环境通常将默认的策略设置为拒绝所有出站流量,再去细化配置允许到达的目标端点的出站流量。
放行特定的出站流量
下面举个例子定义一个Egress规则,对标签run=httpd的Pod对象,到达标签为access=true的Pod对象的80端口的流量进行放行。
[root@master network-policy-demo]# cat egress-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: httpd-egress
spec:
podSelector:
matchLabels:
run: httpd
policyTypes: ["Egress"]
egress:
- to:
- podSelector:
matchLabels:
access: "true"
ports:
- protocol: TCP
port: 80
[root@master network-policy-demo]# kubectl apply -f egress-policy.yaml
networkpolicy.networking.k8s.io/httpd-egress created
#NetworkPolicy检测,一个带有access=true标签,一个不带
[root@master network-policy-demo]# kubectl run busybox --rm -it --labels="access=true" --image=busybox /bin/sh
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
If you don't see a command prompt, try pressing enter.
/ # wget httpd-svc:8080
Connecting to httpd-svc:8080 (10.107.167.46:8080)
index.html 100% |***********************************************************************************************************************************************| 45 0:00:00 ETA
/ # wget httpd-svc:8080
Connecting to httpd-svc:8080 (10.107.167.46:8080)
wget: can't open 'index.html': File exists
/ # wget httpd-svc:8080
Connecting to httpd-svc:8080 (10.107.167.46:8080)
wget: can't open 'index.html': File exists
[root@master network-policy-demo]# kubectl run busybox2 --rm -it --image=busybox /bin/sh
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
If you don't see a command prompt, try pressing enter.
/ # wget httpd-svc:8080
Connecting to httpd-svc:8080 (10.107.167.46:8080)
^C
/ # wget httpd-svc:8080
Connecting to httpd-svc:8080 (10.107.167.46:8080)
从上面的检测结果可以看到,带有标签access=true的Pod才能访问到httpd-svc,说明上面配置的Network Policy已经生效
隔离名称空间
实践中,通常需要彼此隔离所有的名称空间,但是又需要允许它们可以和kube-system名称空间
中的Pod资源进行流量交换,以实现监控和名称解析等各种管理功能。下面的配置清单示例在default
名称空间定义相关规则,在出站和入站都默认均为拒绝的情况下,它用于放行名称空间内部的各Pod对
象之间的通信,以及和kube-system名称空间内各Pod间的通信。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: namespace-deny-all
namespace: default
spec:
policyTypes: ["Ingress","Egress"]
podSelector: {}
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: namespace-allow
namespace: default
spec:
policyTypes: ["Ingress","Egress"]
podSelector: {}
ingress:
- from:
- namespaceSelector:
matchExpressions:
- key: name
operator: In
values: ["default","kube-system"]
egress:
- to:
- namespaceSelector:
matchExpressions:
- key: name
operator: In
values: ["default","kube-system"]
需要注意的是,有一些额外的系统附件可能会单独部署到独有的名称空间中,比如将prometheus监控
系统部署到prom名称空间等,这类具有管理功能的附件所在的名称空间和每一个特定的名称空间的出
入流量也是需要被放行的。