NodePort
NodePort
在 Kubernetes
里是一个广泛应用的服务暴露方式。 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 中同时配置了 hostPort
和 hostNetwork
,那么 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 的异同
相同点:
- hostPort 与 hostNetwork 本质上都是终端用户能访问到 pod 中的业务
- 访问的时候,只能用 pod 所在宿主机 IP + 容器端口或 hostport 端口 进行访问
不同点:
- 网络地址空间不同。hostport 使用 CNI 分配的地址,hostNetwork 使用宿主机网络地址空间
- hostport 宿主机不生成端口,hostNetwork 宿主机生成端口
- hostport 通过 iptable 防火墙的 nat 表进行转发,hostNetwork 直接通过主机端口到容器中
- 定义的路径不同。
deploy.spec.template.spec.containers.ports.hostPort
与 deploy.spec.template.spec.hostNetwork
- 优先级不同,hostNetwork 高于 hostPort