如何暴露Pod中的服務(wù)到Kubernetes集群外?
使用Kubernetes集群運(yùn)行服務(wù),提供服務(wù)的應(yīng)用運(yùn)行在Pod中。為了在集群外訪問應(yīng)用,有兩類方式:一類是Pod自身實(shí)現(xiàn);其次是依賴其他組件。
- Pod自身暴露服務(wù)
1、hostNetwork:true
在Pod的yaml定義文件中配置該選項(xiàng)后,Pod就使用宿主機(jī)的網(wǎng)絡(luò)棧,這樣和直接訪問運(yùn)行在宿主機(jī)上的服務(wù)沒有什么區(qū)別,使用“宿主機(jī)IP+端口”的方式訪問運(yùn)行在Pod中的服務(wù),比如下面的Pod定義文件,
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
hostNetwork: true
containers:
- name: nginx
image: nginx:1.23.1
ports:
- containerPort: 80
執(zhí)行后,登錄容器運(yùn)行的宿主機(jī),可以看到有服務(wù)監(jiān)聽在80端口,
監(jiān)聽在宿主機(jī)的80端口
訪問也是沒有問題的(192.168.52.132是宿主機(jī)的IP)。
服務(wù)訪問
如果Pod重啟,可能會(huì)被調(diào)度到別的宿主機(jī),這樣的話,訪問IP也需跟著變動(dòng),還有要防止端口沖突,如果已經(jīng)有服務(wù)占用了宿主機(jī)的端口,新的Pod將不能啟動(dòng)。
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
相對(duì)于第一種,可以靈活地配置對(duì)外暴露的端口。有一點(diǎn)需要注意,因?yàn)椤癶ostPort”方式,服務(wù)監(jiān)聽在容器的網(wǎng)絡(luò)棧,宿主機(jī)在防火墻上做了轉(zhuǎn)發(fā),所以查詢宿主機(jī)8080端口,發(fā)現(xiàn)并沒有服務(wù)監(jiān)聽,
監(jiān)聽端口
查看防火墻,宿主機(jī)做了端口轉(zhuǎn)發(fā)。
Pod的IP
宿主機(jī)上執(zhí)行DNAT
這種方式和第一種方式有相同的缺點(diǎn),容器重啟可能會(huì)被調(diào)度到其他的主機(jī)上。不能在一臺(tái)宿主機(jī)上運(yùn)行同樣的Pod,除非人為調(diào)整Pod對(duì)外暴露的端口。
- 依賴組件暴露服務(wù)
上面兩種方法都是依賴Pod自身的資源定義暴露服務(wù)到集群外,下面兩種方法依賴其他Kubernetes資源實(shí)現(xiàn)服務(wù)的暴露。
3、NodePort
“NodePort”是Kubernetes中“Service”資源的一個(gè)屬性,默認(rèn)“Service”實(shí)現(xiàn)集群內(nèi)服務(wù)訪問,當(dāng)增加“NodePort”時(shí),服務(wù)便可以在集群外被訪問到,Kubernetes默認(rèn)會(huì)從宿主機(jī)的端口30000-32767之間選擇一個(gè)來(lái)提供訪問,可以人為指定。
一個(gè)示例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
應(yīng)用該yaml文件后,便可以在集群外通過“主機(jī)IP+30000”的方式訪問服務(wù)。
nodePort方式訪問服務(wù)
為了實(shí)現(xiàn)高可用,可以部署haproxy,后端為多個(gè)集群宿主機(jī)暴露的服務(wù),這樣可以提高可用性?!皀odePort”方式的Service工作原理是這樣:當(dāng)流量進(jìn)入宿主機(jī)暴露的30000端口后,會(huì)被轉(zhuǎn)發(fā)給“Service”的“Cluster IP+端口”,然后通過Iptables(也有可能是ipvs,具體看實(shí)現(xiàn))轉(zhuǎn)發(fā)到對(duì)應(yīng)的Pod。
4、Ingress
使用Ingress暴露服務(wù)的方式在生產(chǎn)環(huán)境中使用的比較多。Ingress API資源對(duì)象在kubernetes有內(nèi)置,但要使用這個(gè)對(duì)象,需要安裝“Controller”??蛇x的第三方“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
因?yàn)楣P者的測(cè)試環(huán)境Ingress Controller使用nodePort方式運(yùn)行,對(duì)外暴露的HTTP端口為31763。
ingress controller暴露的端口
使用Ingress資源定義中配置的域名訪問部署的服務(wù)。
訪問服務(wù)
生產(chǎn)環(huán)境可以修改Ingress controller網(wǎng)絡(luò)的工作方式,比如使用“hostPort”,讓其監(jiān)聽在80端口。
有一點(diǎn)需要注意,不同于“nodePort”引導(dǎo)流量到Service的Cluster IP,Ingress Controller會(huì)將集群外用戶的流量直接送到Pod監(jiān)聽的端口,這樣效率會(huì)高不少。
總結(jié)
除了以上介紹的四種暴露服務(wù)的方式,還可以采用“LoadBalancer”,它需要依賴云廠商,如果你的Kubernetes集群部署在公有云上,可以根據(jù)實(shí)際配置。