⒈介紹
kubernetes 通過標簽選擇的方式來匹配一組pod,然后提供對外訪問的一種機制
一組pod可以對應到多個svc的
每一個service(svc)都可以理解為一個微服務
Service有且只有一個算法 RB 輪詢,
Service能夠提供負載均衡的能力,但是在使用上有以下限制:
·只提供4層負載均衡能力【只能基於ip地址和端口進行轉發】,而沒有7層功能【不能通過主機名及域名的方案去進行負載均衡】,但有時我們可能需要更多的匹配規則來轉發請求,這點上4層負載均衡是不支持的

⒉Service的類型
Service在K8s中有以下四種類型
·Clusterlp:默認類型,自動分配一個僅Cluster內部可以訪問的虛擬IP【service創建一個僅集群內部可訪問的ip,集群內部其他的pod可以通過該服務訪問到其監控下的pod】
·NodePort:在ClusterlP基礎上為Service在每台機器上綁定一個端口,這樣就可以通過:NodePort來訪問該服務【在service及各個node節點上開啟端口,外部的應用程序或客戶端訪問node的端口將會轉發到service的端口,而service將會依據負載均衡隨機將請求轉發到某一個pod的端口上。一般暴露服務常用的類型】
·LoadBalancer:在NodePort的基礎上,借助 cloud provider 創建一個外部負載均衡器,並將請求轉發到:NodePort【在NodePort基礎之上,即各個節點前加入了負載均衡器實現了真正的高可用,一般雲供應商提供的k8s集群就是這種】
·ExternalName:把集群外部的服務引入到集群內部來,在集群內部直接使用。沒有任何類型代理被創建,這只有kubernetes 1.7或更高版本的kube-dns 才支持【當我們的集群服務需要訪問k8s之外的集群時,可以選擇這種類型,然后把外部服務的IP及端口寫入到k8s服務中來,k8s的代理將會幫助我們訪問到外部的集群服務】
1.ClusterIP
clusterIP主要在每個node節點使用iptables【新版本模式是ipvs代理模式因此此處為ipvs,代理模式不同所使用的底層方案也是不一致的】,將發向clusterlP對應端口的數據,轉發到kube-proxy中。然后kube-proxy自己內部實現有負載均衡的方法,並可以查詢到這個service下對應pod的地址和端口,進而把數據轉發給對應的pod的地址和端口

為了實現圖上的功能,主要需要以下幾個組件的協同工作:
·apiserver 用戶通過kubectl命令向apiserver發送創建service的命令,apiserver接收到請求后將數據存儲到etcd中
·kube-proxy kubernetes的每個節點中都有一個叫做kube-porxy的進程,這個進程負責感知service,pod的變化,並將變化的信息寫入本地的iptables規則中
·iptables 使用NAT等技術將virtuallP的流量轉至endpoint中
資源清單示例:
㈠創建一個Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: myapp
release: stabel
template:
metadata:
1abels:
app: myapp
release: stabel
env: test
spec:
containers:
- name: myapp
image: fanqisoft/myapp:v2
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: default
spec:
type: ClusterIP
selector:
app: myapp
release: stabel
ports:
- name: http
port: 80
targetPort: 80
Headless Service【無頭服務,無頭服務也是一種Cluster IP,只不過是一種特殊的Cluster IP】
有時不需要或不想要負載均衡,以及單獨的Service IP。遇到這種情況,可以通過指定 ClusterIP(spec.clusterIP)的值為“None”來創建 Headless Service。這類Service 並不會分配 Cluster IP,kube-proxy 不會處理它們,而且平台也不會為它們進行負載均衡和路由
主要的特點是通過無頭服務的方式去解決hostname和portname的變化問題,也就是通過它去進行綁定
apiVersion: v1
kind: Service
metadata:
name: myapp-headless
namespace: default
spec:
selector:
app: myapp
clusterIP: "None"
ports:
- port: 80
targetPort: 80
對於svc,一旦創建成功以后,它會寫入到coreDNS中去,我們的svc的創建會有一個主機名會被寫入到coreDNS,寫入的格式體就是 svc的名稱+命名空間的名稱+當前集群的域名
yum -y install bind-utils
dig -t A myapp-headless.default.svc.cluster.local. @10.96.0.10
意味着在無頭服務中,雖然它沒有ip了,但可以通過訪問域名的方案依然可以訪問服務下的pod
2.NodePort
nodePort的原理在於在node上開了一個端口,將向該端口的流量導入到kube-proxy,然后由 kube-proxy進一步到給對應的pod
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: default
spec:
type: NodePort
selector:
app: myapp
release: stabel
ports:
- name: http
port: 80
targetPort: 80
#查詢流程 iptables -t nat -nvL KUBE-NODEPORTS
3.LoadBalancer
loadBalancer和nodePort 其實是同一種方式。區別在於 loadBalancer 比nodePort多了一步,就是可以調用cloud provider【雲供應商】 去創建LB【負載均衡】來向節點導流
4.ExternalName
這種類型的 Service 通過返回 CNAME和它的值,可以將服務映射到externalName字段的內容(例如:hub.coreqi.cn)。ExternalName Service 是Service的特例,它沒有 selector,也沒有定義任何的端口和Endpoint。相反的,對於運行在集群外部的服務,它通過返回該外部服務的別名這種方式來提供服務
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: default
spec:
type: ExternalName
externalName: hub.coreqi.cn
當查詢主機 my-service.defalut.svc.cluster.local(SVC_NAME.NAMESPACE.svc.cluster.local)時,集群的DNS 服務將返回一個值my.database.example.com的CNAME記錄。訪問這個服務的工作方式和其他的相同,唯一不同的是重定向發生在DNS層,而且不會進行代理或轉發。
⒊實現原理

apiServer: 監聽服務和端點通過kube-proxy去監控
kube-proxy:通過選擇標簽去監控對應的pod並寫入到iptable規則里面去
客戶端訪問服務時通過iptables中的規則被定向到pod的地址信息
客戶端訪問pod是通過iptables去實現的v
iptables規則是通過kube-proxy去寫入的
apiserver通過監控kube-proxy去實現服務端點信息的發現
⒌k8s代理模式的分類
在Kubernetes集群中,每個Node 運行一個kube-proxy 進程。kube-proxy負責為service 實現了一種VIP(虛擬IP)的形式【可以在集群內部直接訪問】,而不是ExternalName【返回集群外部的地址信息】 的形式。在Kubernetes v1.0版本,代理完全由userspace實現。在Kubernetesv1.1版本,新增了iptables代理,但並不是默認的運行模式。從Kubernetesv1.2起,默認就是iptables 代理。在Kubernetes v1.8.0-beta.0中,添加了ipvs代理
在Kubernetes 1.14版本開始默認使用ipvs代理
在Kubernetes v1.0版本,service是“4層”(TCP/UDP over IP)概念。在Kubernetes v1.1版本,新增了IngressAPI(beta版),用來表示“7層”(HTTP)服務!可以進行7層的負載均衡。正是因為有了Ingress的API接口,我們才有了7層調度的功能。
為何不使用 round-robin DNS?
k8s不管是歷史還是現在都沒有使用過DNS,不采用DNS負載均衡集群,最大最有意義的一點就是DNS會在很多的客戶端里進行緩存,很對服務訪問DNS進行域名解析的時候解析完成以后得到地址以后很多的服務都不會對DNS的緩存進行清除,也就意味着只要緩存存在服務在下次訪問的時候還是這個地址信息,因此也就達不到我們負載均衡的要求了,因此DNS一般僅僅作為負載均衡的一種輔助手段
1.userspace代理模式
客戶端首先訪問iptables通過iptables訪問到kube-proxy然后訪問到具體的pod上
也就是說每次訪問的時候都需要Kube-proxy進行一次代理
也就是說kube-proxy壓力是非常大的
同時kube-apiserver也會監控kube-proxy服務更新及端點的維護

2.iptables代理模式
舍棄掉了kube-proxy,所有訪問直接通過iptables而不需要kube-proxy去調度
這樣的話訪問速度就會大大增加以及kube-proxy穩定性會提高壓力將會減少很多
當然使用iptables(防火牆)性能並不會怎么高,但除此之外幾乎沒有什么缺點。
kube-apiserver依然通過監控kube-proxy去實現iptables的端口的更新維護

3.ipvs代理模式
將iptables代理模式中iptables變更為ipvs,原來是把所有的調度規則通過iptables
進行所謂的服務轉發定向的變成了通過ipvs模塊去實現負載均衡以及流量導向,並且和
iptables代理模式相同,所有的訪問也是不經過kube-proxy的
如果沒有提前安裝ipvs模塊以及一些基本需求沒有完成,那些k8s將會使用iptables的代理模式

ipvs這種模式,kube-proxy會監視Kubernetes service 對象和Endpoints,調用netlink 接口以相應地創建ipvs 規則並定期與Kubernetes service對象和Endpoints 對象同步ipvs規則,以確保ipvs狀態與期望一致。訪問服務時,流量將被重定向到其中一個后端 Pod
與iptables類似,ipvs於netfilter的hook功能,但使用哈希表作為底層數據結構並在內核空間中工作。這意味着ipvs可以更快地重定向流量,並且在同步代理規則時具有更好的性能。此外,ipvs為負載均衡算法提供了更多選項,例如:
·rr:輪詢調度
·1c:最小連接數
·dh:目標哈希
·sh:源哈希
·sed:最短期望延遲
·nq:不排隊調度
注意: ipvs模式假定在運行kube-proxy之前在節點上都已經安裝了IPVS內核模塊。當kube-proxy以ipvs代理模式啟動時,kube-proxy將驗證節點上是否安裝了IPVS模塊,如果未安裝,則kube-proxy將回退到iptables代理模式
#查看ipvs代理規則
ipvsadm -Ln