一、概述
k8s暴露服務的方式有很多使用ingress、nodeport等,這類比較適用於無狀態的服務,對於statefulset部署的有狀態的服務,(關於statefulset的介紹參考kubernetes的官網或參考我的https://www.cnblogs.com/cuishuai/p/10243291.html),由於statefulset使用的是headless service。是固定網絡標示的,也就是服務的完整域名是不會改變的。但是有兩個問題:
1、物理機在k8s集群的外面沒辦法解析k8s集群內部的域名
2、解析域名后網絡不能通信
二、物理網絡與k8s集群打通
有了上面提出的兩個問題,我們先來簡單分析一下k8s的網絡,我們使用的是calico-bgp+ipvs,所以這里就以calico為例,calico為k8s提供了一個網絡空間,提供的地址池和k8s初始化時指定的pod-cidr是相同的。部署服務的時候會在地址池里面為pod分配地址,比如設置的是192.168.0.0/16,首先是分配node節點,一般情況下calico會先給node節點隨機分配一個網段,例如有個節點是node1 ,calico會分配一個192.168.19.0網段,具體的子網掩碼(netmask)要看路由表在任意節點上執行(route -n)查看。
查看具體的分配,部署calico的時候選擇的是將數據存儲到etcd集群,所以也可以去etcd里面產看:
# etcdctl get --prefix "/calico" --keys-only | grep "ipam/v2/host"
/calico/ipam/v2/host/ku13-1/ipv4/block/192.244.190.128-26
/calico/ipam/v2/host/ku13-1/ipv4/block/192.244.190.192-26
/calico/ipam/v2/host/ku13-2/ipv4/block/192.244.32.0-26
/calico/ipam/v2/host/ku13-2/ipv4/block/192.244.32.64-26
/calico/ipam/v2/host/ku13-3/ipv4/block/192.244.6.192-26
/calico/ipam/v2/host/ku13-3/ipv4/block/192.244.7.0-26
/calico/ipam/v2/host/ku13-3/ipv4/block/192.244.7.64-26
/calico/ipam/v2/host/ku13-4/ipv4/block/192.244.70.0-26
還有一個服務kube-proxy,這個服務負責node之間的網絡通信,刷新ipvs列表。具體的calico和kube-proxy工作詳情這里不做詳解。
我們了解到要想解決我們上面提出的兩個問題,我們需要將kubernets里面的coredns服務拿出來,為物理機提供dns解析、然后需要將物理機與k8s集群網絡打通。接下來我們解決這兩個問題:
解決第一個問題也需要以第二個問題為前提,所以我們只需要解決了第二個問題,第一個問題只需要在物理機上面的/etc/resolv.conf添加一條nameserver記錄。
解決第二個問題:網絡打通
打通網絡我們需要兩個工具:calico、kube-proxy
我們之前的集群都是使用kubeadm部署的,所以我們可以很簡單實現這兩個服務的部署,如果不是使用kubeadm部署的集群可以參考網上這個服務的部署,本文不做介紹。主要介紹kubeadm部署的實現。
我們准備一個服務器,上面需要部署kubeadm、docker具體的准備參考之前的集群初始化,我們將新服務器以node節點的形式加入到集群里面,使用kubeadm join很方便的將服務器加入到現有的k8s集群里面,這個服務器只需要分配很小的資源,因為這個上面不會部署任何服務,只有kubeadm join時部署的calico-node、kube-proxy。
添加節點參考:https://www.cnblogs.com/cuishuai/p/9897006.html
節點成功加入集群后還要執行一個操作,就是設置節點不能被調度:
kubctl drain [node-name] --ignore-daemonsets
這樣我們新加入的這個節點上面只部署了calico-node、kube-proxy,並且該服務器節點是能和k8s集群通信的,我們把該節點作為k8s網絡與物理網絡的gateway,所有物理服務器進入k8s集群網絡的路由都經過這個gateway。這樣就實現了通訊。
2、生成路由規則
在上面新部署的服務器上面有到k8s集群的所有路由,我們將這些路由進行提取生成一個路由表給物理機使用,將所有路由設置成默認路由,都經過上面新加服務器的ip。
為了方便使用我寫了一個生成腳本,此腳本在gateway節點即上面新加的節點上面執行:
#cat generate-rule
#!/bin/bash route -n | grep UG | grep -v ^0 | awk '{print $1,$3}' >a.txt ip=`ip a | grep eth0 | grep inet |awk -F '/' '{print $1}'|awk '{print $2}'`
service_net="192.96.0.0"
service_mask="255.255.0.0" #判斷route.rule文件是否存在 if [ -f route.rule ];then
>route.rule fi
#生成route.rule文件
#添加coredns的路由
echo "route add -net $service_net netmask $service_mask gw $ip" >route.rule
while read NT MK do
echo "route add -net $NT netmask $MK gw $ip " >>route.rule done < a.txt #刪除臨時文件 rm -rf a.txt
service_net是k8s service的網段,即coredns的service ip所在的網段,service_mask是k8s service的子網掩碼,這個在使用kubeadm初始化的時候就指定了,我們使用的是:
https://www.cnblogs.com/cuishuai/p/9897006.html
podSubnet: 192.244.0.0/16 serviceSubnet: 192.96.0.0/16
將service_net、service_mask換成自己的。
然后將生成的文件copy到物理機上,然后執行:
sh route.rule
在物理機上面在/etc/resolv.conf里面添加coredns的service的ip,service名稱是kube-dns,在任意master節點上查看:
kubectl get svc -n kube-system | grep kube-dns
kube-dns ClusterIP 192.96.0.10 <none> 53/UDP,53/TCP 7d8h
將找到的ip地址添加到/etc/resolv.conf:
nameserver 192.96.0.10
在物理機上面測試連通性: