可以使用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。

广告
将在 10 秒后关闭
bannerAds