應用在k8s上執行的幾種網路模式
應用部署在k8s上,首先想到的是應用k8s的預設service模式配置。
應用通過service向叢集內部(ClusterIP)和叢集外部(NodePort)暴露服務。k8s中的其他應用通過kube-dns提供的dns解析功能,訪問servicename:port即可訪問service後面的pod的服務。這需要兩個應用服務之間的互動不需要記錄對方的hostname或者IP,例如,假如應用服務通過socket連線到另一個應用服務,並通過記錄他的IP或者Hostname,以便下次連線時作為驗證對方。這樣的話會出現servicename:port與podname:port或者podIP:port不符。
k8s hostnetwork配置
解決servicename:port與podname:port或者podIP:port不符的問題,可以把被驗證的應用使用hostnetwork。
應用與宿主機共享網路空間,也就是k8s節點的IP,端口占用與宿主機一樣。這樣應用的IP就是宿主機的IP,與另一個應用的連線也不經過service IP這一層。另一個應用仍然採用kubernetes的pod網路模型,為使使用hostnetwork的應用能對其他應用的service name進行DNS解析,需要設定引數hostNetwork: true和dnsPolicy: ClusterFirstWithHostNet。
該配置的缺點:應用的網路與宿主機一樣,需保證應用需要監聽的網路埠在宿主機上沒有被佔用。並且無法使用容器漂移,動態伸縮特性。
k8s headless service配置
解決servicename:port與podname:port或者podIP:port不符的問題,還有一種方法,就是把被驗證的應用配置使用headless service。headless service即是把service type為ClusterIP的service配置spec.clusterIP為None,這樣的話就不會為其分配serviceIP,kube-dns解析servicename:port就會變成podIP:port。在把servicename配置和pod的hostname一樣,這樣的kube-dns解析servicename:port就與podhostname:port一樣。達到了獲得實際podIP的目的。相比hostnetwork配置,這個配置沒有它所具有的缺點。
k8s statefulset headless service配置
上面提到headless service可以解決servicename:port與podname:port或者podIP:port不符的問題。這是針對一個應用pod在service後面,另一個應用pod在service的前面。現在假設同一個service後面的pod之間需要獲悉對方的hostname或者podIP進行通訊,怎麼辦?例如,storm的worker元件之間需要通過hostname通訊,我們想要能快速伸縮worker元件,因此把所有的worker放到同一個service後面。
一種解決辦法就是使用statefulset加headless service配置,這種配置kube-dns可以解析
podname.servicename.namespacename.svc.cluster.local對應到podIP。在同一個statefulset的pod的podname都是podname-0,podname-1,podname-2等數字遞增的命名。對於podname-0可以解析
podname-1.servicename.namespacename.svc.cluster.local到podname-1的podIP。
在podname-0中使用命令
nslookup podname-1
會解析podname-1.namespacename.svc.cluster.local。因此需要我們修改/etc/resolv.conf
檔案
在search 後面加上 servicename.namespacename.svc.cluster.local,這樣就達到了解析到
podname-1.servicename.namespacename.svc.cluster.local的目的。
具體做法就是在statefulset的pod配置中加入lifecycle的postStart配置
lifecycle:
postStart:
exec:
command:
- /bin/sh
- -c
- >
if [ -z "$(grep servicename /etc/resolv.conf)" ]; then
sed "s/^search \([^ ]\+\)/search servicename.\1 \1/" /etc/resolv.conf > /etc/resolv.conf.new;
cat /etc/resolv.conf.new > /etc/resolv.conf;
rm /etc/resolv.conf.new;
fi;
至此,headless service後面的statefulset的pod之間可以相互通訊了。