Featured image of post NodePort和HostPort与HostNetwork之间的区别

NodePort和HostPort与HostNetwork之间的区别

Kubernetes 集群外部访问的几种访问方式之间的区别

NodePort

NodePortKubernetes 里是一个广泛应用的服务暴露方式。 Kubernetes 中的 service 默认情况下都是使用的 ClusterIP 这种类型,这样的 service 会产生一个 ClusterIP ,这个 IP 只能在集群内部访问,要想让外部能够直接访问 service ,需要将 service type 修改为 nodePort

如下就是一个 NodePort 的示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      nodeSelector:
        nginx: ok
      containers:
        - name: nginx
          image: nginx:stable
          command: ["nginx", "-g", "daemon off;"]
---
kind: Service
apiVersion: v1
metadata:
  name: nginx-svc
spec:
  type: NodePort
  ports:
    - port: 80
      nodePort: 30001
  selector:
    name: nginx
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$ kube get svc -o wide
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE    SELECTOR
kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP        176d   <none>
nginx-svc    NodePort    10.110.21.50   <none>        80:30001/TCP   26s    app=nginx

$ kube get pod -o wide
NAME                                    READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
clubproxy-deployment-55c958bf67-cg424   1/1     Running   0          11h   10.244.0.56   k8s-master01   <none>           <none>
nginx-deployment-c9fd6b54f-bdr8l        1/1     Running   0          18s   10.244.0.58   k8s-master01   <none>           <none>

$ sudo netstat -lpn | grep 30001
tcp        0      0 0.0.0.0:30001           0.0.0.0:*               LISTEN      15954/kube-proxy

如上配置,可以通过 {pod_ip}/index.html{cluster_ip}/index.html{node_ip}:30001/index.html 访问 nginx。node 节点上可以看到 kube-proxy 进程在监听 30001 端口,用于接收从主机网络进入的外部流量。最后,通过 iptables 规则将 {node_ip}:30001 映射到 {pod_ip}:容器端口

HostPort

hostPort 是将容器端口与宿主节点上的端口建立映射关系,这样用户就可以通过宿主机的 IP 加上来访问 Pod 了。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:stable
          command: ["nginx", "-g", "daemon off;"]
          ports:
            - containerPort: 80
              hostPort: 81
1
2
3
4
5
$ kube get pod -o wide|grep nginx
nginx-deployment-ff549cb9d-5t4bp        1/1     Running   0          5m8s    10.244.0.40   k8s-master01   <none>           <none>

$ sudo iptables -L -nv -t nat| grep "10.244.0.40:80"
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:81 to:10.244.0.40:80

如上配置,既可以通过 curl 10.244.0.40/index.html 访问 nginx ,也可以通过 curl {node_ip}:81/index.html访问nginx。可以看到 iptables 会添加一条 DNAT 规则,将宿主机的 81 端口映射到 Pod 的 80 端口。

HostNetwork

这种网络模式 ,相当于 docker run --net=host,采用宿主机的网络命名空间。此时,Pod 的 ip 为 node 节点的 ip,Pod 的端口需要保持不与宿主机上的 port 端口发生冲突。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      hostNetwork: true
      containers:
        - name: nginx
          image: nginx:stable
          command: ["nginx", "-g", "daemon off;"]
1
2
3
4
5
6
7
8
9
$ sudo ps aux| grep nginx
root     20126  0.0  0.0  10640  3512 ?        Ss   10:17   0:00 nginx: master process nginx -g daemon off;
101      20138  0.0  0.0  11044  1524 ?        S    10:17   0:00 nginx: worker process
101      20139  0.0  0.0  11044  1524 ?        S    10:17   0:00 nginx: worker process
101      20140  0.0  0.0  11044  1524 ?        S    10:17   0:00 nginx: worker process
101      20141  0.0  0.0  11044  1524 ?        S    10:17   0:00 nginx: worker process

$ sudo netstat -lpn| grep ":80 "
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      20126/nginx: master

如上配置,可以直接通过 curl {node_ip}/index.html 访问 nginx ,并且由于 Pod 采用的是宿主机的网络命名空间,因此宿主机可以直接看到 nginx master 进程正在监听 80 端口。

同时使用 HostPort 和 HostNetwork

如果在 deployment 中同时配置了 hostPorthostNetwork ,那么 hostPort 会失效,只生效hostNetwork

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
apiVersion: apps/v1
kind: Deployment
metadata:
  name: server-deployment
  labels:
    app: server
spec:
  replicas: 3
  selector:
    matchLabels:
      app: server
  template:
    metadata:
      labels:
        app: server
    spec:
      hostNetwork: true
      containers:
        - name: server
          image: techoc/server:alpine
          ports:
            - containerPort: 9697
              hostPort: 9697
          env:
            - name: PORT
              value: "9697"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ k get po -owide
NAME                                 READY   STATUS    RESTARTS   AGE   IP                NODE          NOMINATED NODE   READINESS GATES
server-deployment-648dc69468-srwzh   1/1     Running   0          48s   192.168.157.129   k8s-master    <none>           <none>
server-deployment-648dc69468-bxtjz   1/1     Running   0          48s   192.168.157.133   k8s-worker2   <none>           <none>
server-deployment-648dc69468-p6bm2   1/1     Running   0          48s   192.168.157.132   k8s-worker1   <none>           <none>

$ sudo netstat -lpn| grep ":9697"
tcp6       0      0 :::9697                 :::*                    LISTEN      17101/./server

$ sudo iptables -L -nv -t nat| grep ":9697"

可以看到,yaml中填写了hostPort,和hostNetwork 。但是查看端口,发现端口被占用,并且端口被占用的进程是./server,查看 iptables 则并没有添加任何规则,

HostPort 和 HostNetwork 的异同

相同点:

  1. hostPort 与 hostNetwork 本质上都是终端用户能访问到 pod 中的业务
  2. 访问的时候,只能用 pod 所在宿主机 IP + 容器端口或 hostport 端口 进行访问

不同点:

  1. 网络地址空间不同。hostport 使用 CNI 分配的地址,hostNetwork 使用宿主机网络地址空间
  2. hostport 宿主机不生成端口,hostNetwork 宿主机生成端口
  3. hostport 通过 iptable 防火墙的 nat 表进行转发,hostNetwork 直接通过主机端口到容器中
  4. 定义的路径不同。deploy.spec.template.spec.containers.ports.hostPortdeploy.spec.template.spec.hostNetwork
  5. 优先级不同,hostNetwork 高于 hostPort
使用 Hugo 构建
主题 StackJimmy 设计