使用Kubernetes集群运行服务,提供服务的应用运行在Pod中。为了在集群外访问应用,有两类方式:一类是Pod自身实现;其次是依赖其他组件。
- Pod自身暴露服务
1、hostNetwork:true
在Pod的yaml定义文件中配置该选项后,Pod就使用宿主机的网络栈,这样和直接访问运行在宿主机上的服务没有什么区别,使用“宿主机IP+端口”的方式访问运行在Pod中的服务,比如下面的Pod定义文件,
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
hostNetwork: true
containers:
- name: nginx
image: nginx:1.23.1
ports:
- containerPort: 80
执行后,登录容器运行的宿主机,可以看到有服务监听在80端口,
监听在宿主机的80端口
访问也是没有问题的(192.168.52.132是宿主机的IP)。
服务访问
如果Pod重启,可能会被调度到别的宿主机,这样的话,访问IP也需跟着变动,还有要防止端口冲突,如果已经有服务占用了宿主机的端口,新的Pod将不能启动。
2、hostPort
将上面Pod的yaml文件稍作修改,增加最后一行,去掉“hostNetwork: true”。
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.23.1
ports:
- containerPort: 80
hostPort: 8080
相对于第一种,可以灵活地配置对外暴露的端口。有一点需要注意,因为“hostPort”方式,服务监听在容器的网络栈,宿主机在防火墙上做了转发,所以查询宿主机8080端口,发现并没有服务监听,
监听端口
查看防火墙,宿主机做了端口转发。
Pod的IP
宿主机上执行DNAT
这种方式和第一种方式有相同的缺点,容器重启可能会被调度到其他的主机上。不能在一台宿主机上运行同样的Pod,除非人为调整Pod对外暴露的端口。
- 依赖组件暴露服务
上面两种方法都是依赖Pod自身的资源定义暴露服务到集群外,下面两种方法依赖其他Kubernetes资源实现服务的暴露。
3、NodePort
“NodePort”是Kubernetes中“Service”资源的一个属性,默认“Service”实现集群内服务访问,当增加“NodePort”时,服务便可以在集群外被访问到,Kubernetes默认会从宿主机的端口30000-32767之间选择一个来提供访问,可以人为指定。
一个示例yaml文件。
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.23.1
ports:
- containerPort: 80
---
kind: Service
apiVersion: v1
metadata:
name: nginx
spec:
type: NodePort
ports:
- port: 8080
nodePort: 30000
targetPort: 80
selector:
name: nginx
应用该yaml文件后,便可以在集群外通过“主机IP+30000”的方式访问服务。
nodePort方式访问服务
为了实现高可用,可以部署haproxy,后端为多个集群宿主机暴露的服务,这样可以提高可用性。“nodePort”方式的Service工作原理是这样:当流量进入宿主机暴露的30000端口后,会被转发给“Service”的“Cluster IP+端口”,然后通过Iptables(也有可能是ipvs,具体看实现)转发到对应的Pod。
4、Ingress
使用Ingress暴露服务的方式在生产环境中使用的比较多。Ingress API资源对象在kubernetes有内置,但要使用这个对象,需要安装“Controller”。可选的第三方“Controller”有很多,这里选择“Nginx Ingress controller”。(安装过程不涉及)。
示例yaml:
apiVersion: v1
kind: Pod
metadata:
namespace: test
name: nginx
labels:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.23.1
ports:
- containerPort: 80
---
kind: Service
apiVersion: v1
metadata:
namespace: test
name: nginx
spec:
ports:
- port: 8080
targetPort: 80
selector:
name: nginx
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: test
name: nginx
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: nginx.example.cc
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: nginx
port:
number: 8080
因为笔者的测试环境Ingress Controller使用nodePort方式运行,对外暴露的HTTP端口为31763。
ingress controller暴露的端口
使用Ingress资源定义中配置的域名访问部署的服务。
访问服务
生产环境可以修改Ingress controller网络的工作方式,比如使用“hostPort”,让其监听在80端口。
有一点需要注意,不同于“nodePort”引导流量到Service的Cluster IP,Ingress Controller会将集群外用户的流量直接送到Pod监听的端口,这样效率会高不少。
总结
除了以上介绍的四种暴露服务的方式,还可以采用“LoadBalancer”,它需要依赖云厂商,如果你的Kubernetes集群部署在公有云上,可以根据实际配置。