可以使用Kubernetes的NodePort和NetworkPolicy来实现
如果在Kubernetes上运行Web服务,通常会通过Ingress控制器进行访问配置,我认为不需要使用NodePort,但是我有一个机会来研究使用NodePort公开服务,并且使用NetworkPolicy进行通信限制是否可行?以下是我的验证记录。
从结论来看,可以通过NetworkPolicy对NodePort公开服务进行通信限制。然而,与普通的NodePort不同,它可以通过Kubernetes集群上的任何节点访问,而通过Pod所运行的节点的NodePort只能实质上进行通信限制。
环境 –
之前创建的Kubernetes v1.27集群。CNI是Calico。
链接:https://qiita.com/rk05231977/items/032feaed7b46fc2bbabd
使用一台CP节点和一台Worker节点。IP地址为c1:192.168.0.204,w1:192.168.0.205。
在此基础上,部署一个名为Pod1的nginx容器,部署一个名为Pod2的httpd容器,并且都通过NodePort方式进行服务公开。Pod1的公开端口号是30080,Pod2的公开端口号是30081。
准备两台设备来访问Pod,各自的IP地址为p1: 192.168.0.202、p2: 192.168.0.100。
Pod的部署
在测试用的命名空间中部署两个用于访问的Pod,并使用NodePort方式进行公开。然后,使用root以ssh连接到c1节点,并执行以下操作。
# kubectl create ns test
# cat << EOF > pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod1
namespace: test
labels:
app: pod1
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
EOF
# kubectl create -f pod1.yaml
# cat << EOF > svc1.yaml
apiVersion: v1
kind: Service
metadata:
name: svc1
namespace: test
spec:
type: NodePort
selector:
app: pod1
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
EOF
# kubectl create -f svc1.yaml
# cat << EOF > pod2.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod2
namespace: test
labels:
app: pod2
spec:
containers:
- name: httpd
image: httpd:latest
ports:
- containerPort: 80
EOF
# kubectl create -f pod2.yaml
# cat << EOF > svc2.yaml
apiVersion: v1
kind: Service
metadata:
name: svc2
namespace: test
spec:
type: NodePort
selector:
app: pod2
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
nodePort: 30081
EOF
# kubectl create -f svc2.yaml
检查Pod后,发现两个都在w1节点上运行。
[root@c1 ~]# kubectl get pod -n test -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod1 1/1 Running 0 3m19s 172.16.190.67 w1 <none> <none>
pod2 1/1 Running 0 2m16s 172.16.190.68 w1 <none> <none>
由于没有特别的通信限制,因此可以通过节点端口(NodePort)访问任何一个Pod。
(p1からアクセス)
# curl http://192.168.0.205:30080
...
<title>Welcome to nginx!</title>
...
# curl http://192.168.0.205:30081
<html><body><h1>It works!</h1></body></html>
(p2からアクセス)
# curl http://192.168.0.205:30080
...
<title>Welcome to nginx!</title>
...
# curl http://192.168.0.205:30081
<html><body><h1>It works!</h1></body></html>
可以通过Worker节点(192.168.0.205)访问上述内容,同时也可通过CP节点(192.168.0.204)访问。
(p1からのアクセス)
# curl http://192.168.0.204:30080
...
<title>Welcome to nginx!</title>
...
# curl http://192.168.0.204:30081
<html><body><h1>It works!</h1></body></html>
(p2からのアクセス)
# curl http://192.168.0.204:30080
...
<title>Welcome to nginx!</title>
...
# curl http://192.168.0.204:30081
<html><body><h1>It works!</h1></body></html>
设置NetworkPolicy
我們可以嘗試設定NetworkPolicy,以允許僅從客戶端p1(192.168.0.202)訪問pod1,從上述狀態開始。
Kubernetes的Network Policy說明如下:
https://kubernetes.io/docs/concepts/services-networking/network-policies/
首先在测试命名空间中设置deny all策略。
在c1节点上执行以下命令。
# cat << EOF > np1.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: test
spec:
podSelector: {}
policyTypes:
- Ingress
EOF
# kubectl create -f np1.yaml
在这种情况下,p1和p2的客户端都无法连接到任何Pod。
接下来,通过NetworkPolicy使用ipBlock指定p1的IP地址,以便可以访问pod1。
# cat << EOF > np2.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-pod1
namespace: test
spec:
podSelector:
matchLabels:
app: pod1
policyTypes:
- Ingress
ingress:
- from:
- ipBlock:
cidr: 192.168.0.202/32
EOF
# kubectl create -f np2.yaml
尝试连接后,可以预期地看到访问受限的情况。
(p1からのアクセス)
# curl http://192.168.0.205:30080
...
<title>Welcome to nginx!</title>
...
# curl http://192.168.0.205:30081
curl: (28) Failed to connect to 192.168.0.205 port 30081 after 21032 ms: Couldn't connect to server
(p2からのアクセス)
# curl http://192.168.0.205:30080
curl: (28) Failed to connect to 192.168.0.205 port 30080 after 21002 ms: Timed out
# curl http://192.168.0.205:30081
curl: (28) Failed to connect to 192.168.0.205 port 30081 after 21000 ms: Timed out
由于是NodePort,希望也能从c1节点访问。
正如前面所提到的,尽管此时可以通过w1节点(192.168.0.205)进行访问,但无法通过c1节点(192.168.0.204)从客户端p1进行访问。
(p1からのアクセス)
# curl http://192.168.0.204:30080
curl: (28) Failed to connect to 192.168.0.204 port 30080 after 21049 ms: Couldn't connect to server
我认为这是因为在通过c1的NodePort时,p1的IP地址经过了NAT地址转换。例如,如果将c1节点的IP地址添加到NetworkPolicy中,就可以通过c1节点进行访问。
# cat << EOF > np2.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-pod1
namespace: test
spec:
podSelector:
matchLabels:
app: pod1
policyTypes:
- Ingress
ingress:
- from:
- ipBlock:
cidr: 192.168.0.202/32
- ipBlock:
cidr: 192.168.0.204/32
EOF
# kubectl apply -f np2.yaml
(p1からのアクセス)
# curl http://192.168.0.204:30080
...
<title>Welcome to nginx!</title>
...
但是,在这种情况下,客户端 p2 也可以通过 c1 节点的 NodePort 访问到 pod1,这将使最初的目标只允许 p1 访问 pod1 的要求无法满足。
(p2からのアクセス)
# curl http://192.168.0.204:30080
...
<title>Welcome to nginx!</title>
...
所以,提供像Ingress控制器配置节点一样集中外部访问的节点,并使用NetworkPolicy限制通过NodePort公开的服务的配置,并不奏效,客户端需要直接访问Pod运行的Worker节点的NodePort。