概述
在实际生产环境中,有些容器内应用(比如编码器)需要用到物理层面的网络资源(比如组播流)。这就要求Kubernetes中的该Pod以HOST模式来启动。以下实验了Kubernetes-HOST网络模式,并给出了一些运维建议。
一、Pod的网络
每个Pod都会默认启动一个pod-infrastructure(或pause)的容器,作为共享网络的基准容器。其他业务容器在启动之后,会将自己的网络模式指定为“"NetworkMode": "container:pause_containerID”。这样就能做到Pod中的所有容器网络都是共享的,一个Pod中的所有容器中的网络是一致的,它们能够通过本地地址(localhost)访问其他用户容器的端口。在Kubernetes的网络模型中,每一个Pod都拥有一个扁平化共享网络命名空间的IP,称为PodIP。通过PodIP,Pod就能够跨网络与其他物理机和容器进行通信。
也可以设置Pod为Host网络模式,即直接使用宿主机的网络,不进行网络虚拟化隔离。这样一来,Pod中的所有容器就直接暴露在宿主机的网络环境中,这时候,Pod的PodIP就是其所在Node的IP。从原理上来说,当设定Pod的网络为Host时,是设定了Pod中pod-infrastructure(或pause)容器的网络为Host,Pod内部其他容器的网络指向该容器。如下所示(65070affecfc61为业务容器,f60a2ee415e3为pod-infrastructure容器):
[root@k8s-node-3 ~]# docker inspect 65070affecfc6131b2385e5c40d4f21f73c343cc15e7983cdce8594e38ed020f | grep NetworkMode
"NetworkMode": "container:f60a2ee415e301491f30ffc12855880273da6eded2526a5319eed72a92caef7f",
[root@k8s-node-3 ~]# docker inspect f60a2ee415e301491f30ffc12855880273da6eded2526a5319eed72a92caef7f | grep NetworkMode
"NetworkMode": "host",
[root@k8s-node-3 ~]#
这里要区分一下 hostPort: 8081 和 hostNetwork: true 区别,这两者其实作用差不多,都属于 Host 模式,两者都可以获得到真实IP,不过后者可以通过容器间服务发现的方式进行通信,所以我一般会选择后者。
如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。
二、启动示例
[root@k8s-master yaml]# cat test-host.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: test-host
spec:
replicas: 4
template:
metadata:
labels:
name: test-host
spec:
containers:
- name: test-host
image: registry:5000/back_demon:1.0
command:
- /jboss/jboss-eap-6.1/bin/standalone.sh
ports:
- containerPort: 8080
hostNetwork: true
三、运维经验
3.1、副本数量
对于同Deployment下的Host模式启动的Pod,每个node上只能启动一个。也就是说,Host模式的Pod启动副本数不可以多于“目标node”的数量,“目标node”指的是在启动Pod时选定的node,若未选定(没有指定nodeSelector),“目标node”的数量就是集群中全部的可用的node的数量。当副本数大于“目标node”的数量时,多出来的Pod会一直处于Pending状态,因为schedule已经找不到可以调度的node了。
以下示例中,集群只有4个node,当设置副本数量为5时,最后一个Pod状态会一直处于Pending状态。
[root@k8s-master yaml]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
test-host-1108333573-11wbl 1/1 Running 0 17s 10.0.251.153 k8s-node-1
test-host-1108333573-2k35s 1/1 Running 0 17s 10.0.251.146 k8s-node-3
test-host-1108333573-lnlpy 1/1 Running 0 17s 10.0.251.222 k8s-node-4
test-host-1108333573-t6izr 1/1 Running 0 17s 10.0.251.155 k8s-node-2
test-host-1108333573-tf4mc 0/1 Pending 0 17s <none>
3.2、PodIP
Pod的PodIP就是其所在Node的IP,具体如下:
[root@k8s-master yaml]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
test-host-1108333573-11wbl 1/1 Running 0 2h 10.0.251.153 k8s-node-1
test-host-1108333573-2k35s 1/1 Running 0 2h 10.0.251.146 k8s-node-3
test-host-1108333573-lnlpy 1/1 Running 0 2h 10.0.251.222 k8s-node-4
test-host-1108333573-t6izr 1/1 Running 0 2h 10.0.251.155 k8s-node-2
虽然PodIP是NodeIP,但也可以通过service的方式加到Kubernetes的虚拟化网络中被使用。具体如下:
[root@k8s-master yaml]# cat demon1/frontend-service.yaml
apiVersion: v1
kind: Service
metadata:
name: frontend-service
labels:
name: frontend-service
spec:
type: NodePort
ports:
- port: 8080
nodePort: 30002
selector:
name: frontend-service
[root@k8s-master yaml]# kubectl create -f test-host-svc.yaml
service "test-host" created
[root@k8s-master yaml]# kubectl describe svc test-host
Name: test-host
Namespace: default
Labels: name=test-host
Selector: name=test-host
Type: NodePort
IP: 10.254.127.198
Port: <unset> 8080/TCP
NodePort: <unset> 30003/TCP
Endpoints: 10.0.251.146:8080,10.0.251.153:8080,10.0.251.155:8080 + 1 more...
Session Affinity: None
No events.
创建成功之后,集群内部的应用可通过虚拟网络中的clusterIP:10.254.127.198:8080来访问后端服务,集群外部的应用(如浏览器)可以通过nodeIP+NodePort来访问后端服务。
3.3、Pod端口占用
若同集群中,用host模式启动的deployment(或RC)有多个,若这些 deployment中定义的containerPort有相同的值,那么,Kubernetes会校验出端口资源的冲突。示例如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: openailab-application-gateway
namespace: oas-dev
labels:
name: openailab-application-gateway
spec:
replicas: 2
selector:
matchLabels:
name: openailab-application-gateway
template:
metadata:
labels:
name: openailab-application-gateway
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: env
operator: In
values:
- dev
containers:
- name: openailab-application-gateway
image: 192.168.3.202:8088/oascloud/openailab-application-gateway:latest
env:
- name: APOLLO_APP_ID
value: 'openailab-application-gateway'
- name: APOLLO_EUREKA_URI
value: 'http://192.168.3.206:30030/'
- name: APOLLO_NAMESPACE
value: 'application'
- name: SPRING_EUREKA_URI
value: 'http://192.168.3.206:30001/eureka/'
volumeMounts:
- name: openailab-application-gateway
mountPath: /usr/local/logs
command: ["sh","-c","java -server -Xms512m -Xmx1024m -Djava.io.tmpdir=/var/tmp -Duser.timezone=Asia/Shanghai -jar openailab-application-gateway-*.jar
--server.port=30003 --spring.profiles.active=remote"]
ports:
- containerPort: 30003
resources:
requests:
memory: 512Mi
cpu: 250m
limits:
memory: 1024Mi
cpu: 500m
volumes:
- name: openailab-application-gateway
hostPath:
path: /usr/local/logs
hostNetwork: true
如果该Deployment使用Host网络模式进行部署,和宿主机同网段,此时启动2个副本,会报端口占用,如图所示:
所以如果决定Deployment采用Host网络模式部署,则必须单副本部署,多副本会报端口占用。
3.4、宿主机端口占用
当Host模式的Deployment(或RC)声明一个端口时,比如8080,若宿主机上有非Kubernetes控制的程序占用了8080这个端口,这时Kubernetes是无法校验到的。也就是说,schedule仅仅会记录Kubernetes集群中的端口占用信息,并在调度时做相关的校验工作。但schedule不会校验宿主机上真正的端口占用信息。这其实是非常合理的,集群中的node通常成千上万,被当做一台台单纯的提供计算能力的资源,计算什么由中心节点来决定。没有必要,也没有场景需要在node上额外的跑其他程序。
在使用Host模式网络时,需注意的是,每个应用(部署成一个deployment)都要有自己固定的、和其他应用不同的端口,比如编码器永远固定成9525、源服务器永远固定成9537等。且宿主机在做了Kubernetes集群中的node之后,尽量不对非本集群应用提供服务。
3.5、镜像制作要求
必须用Host模式启动的Pod,在镜像制作时要求端口唯一、且副本单一。
一般Pod中只会存在一个业务主镜像,该业务镜像在制作时,应该只放一种应用,这个应用只对外开放一个接口。例如,编码器主控节点这个应用,主要有两方面的功能:1)接收组播流,并控制处理节点,占用端口9525;2)可视化操控界面,占用端口8080。其中接收组播流这块,需要使用Host模式的网络。拆分建议为两个业务镜像,部署时部署两个deployment。即接收组播流拆成一个镜像,固定端口9525,使用Host模式启动;可视化界面拆成一个镜像,用Kubernetes默认网络模式启动。
最后
以上就是爱笑猫咪为你收集整理的Kubernetes Host网络模式应用(可获取真实IP)的全部内容,希望文章能够帮你解决Kubernetes Host网络模式应用(可获取真实IP)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复