摘要:后端代理之前的文章部署最后的測試部分,創建了一組及服務來驗證業務,繼續以這個例子來說明集群中已經有如下一組都帶有標簽,對外暴露端口,訪問路徑會返回主機名。請求代理轉發是一個虛擬的地址,并不是某張網卡的真實地址。
為什么需要service
Kubernetes可以方便的為容器應用提供了一個持續運行且方便擴展的環境,但是,應用最終是要被用戶或其他應用訪問、調用的。要訪問應用pod,就會有以下兩個問題:
pod是有生命周期的。它會根據集群的期望狀態不斷的在創建、刪除、更新,所以pod的ip也在不斷變化,如何訪問到不斷變化的pod?
通常一個應用不會單只有一個pod,而是由多個相同功能的pod共同提供服務的。那么對這個應用的訪問,如何在多個pod中負載均衡?
service主要就是用來解決這兩個問題的。簡單來說,它是一個抽象的api對象,用來表示一組提供相同服務的pod及對這組pod的訪問方式。
service的實現service作為一個類似中介的角色,對內,它要能代理訪問到不斷變換的一組后端Pod;對外,它要能暴露自己給集群內部或外部的其他資源訪問。我們分別來看下具體是怎么實現的。
后端代理之前的文章kubeadm部署最后的測試部分,創建了一組pod及服務來驗證業務,繼續以這個例子來說明:
集群中已經有如下一組pod:
NAME READY STATUS IP NODE APP goweb-55c487ccd7-5t2l2 1/1 Running 10.244.1.15 node-1 goweb goweb-55c487ccd7-cp6l8 1/1 Running 10.244.3.9 node-2 goweb goweb-55c487ccd7-gcs5x 1/1 Running 10.244.1.17 node-1 goweb goweb-55c487ccd7-pp6t6 1/1 Running 10.244.3.10 node-2 goweb
pod都帶有app:goweb標簽,對外暴露8000端口,訪問/info路徑會返回主機名。
創建service創建一個servcie有兩種方式
命令式
$ kubectl expose deployment goweb --name=gowebsvc --port=80 --target-port=8000
聲明式
# 定義服務配置文件 # svc-goweb.yaml apiVersion: v1 kind: Service metadata: name: gowebsvc spec: selector: app: goweb ports: - name: default protocol: TCP port: 80 targetPort: 8000 type: ClusterIP # 創建服務 $ kubectl apply -f svc-goweb.yaml
我們來看下配置文件中幾個重點字段:
selector指定了app: goweb標簽。說明該svc代理所有包含有"app: goweb"的pod
port字段指定了該svc暴露80端口
targetPort指定改svc代理對應pod的8000端口
type定義了svc的類型為ClusterIP,這也是svc的默認類型
通過apply創建服務后,來查看一下服務狀態
$ kubectl get svc gowebsvc -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR gowebsvc ClusterIP 10.106.202.080/TCP 3d app=goweb
可以看到,Kubernetes自動為服務分配了一個CLUSTER-IP。通過這個訪問這個IP的80端口,就可以訪問到"app: goweb"這組pod的8000端口,并且可以在這組pod中負載均衡。
[root@master-1 ~]# curl http://10.106.202.0/info Hostname: goweb-55c487ccd7-gcs5x [root@master-1 ~]# curl http://10.106.202.0/info Hostname: goweb-55c487ccd7-cp6l8 [root@master-1 ~]# curl http://10.106.202.0/info Hostname: goweb-55c487ccd7-pp6t6請求代理轉發
cluster-ip是一個虛擬的ip地址,并不是某張網卡的真實地址。那具體的請求代理轉發過程是怎么實現的呢? 答案是iptables。我們來看下iptables中與cluster-ip相關的規則
[root@master-1 ~]# iptables-save | grep 10.106.202.0 -A KUBE-SERVICES ! -s 10.244.0.0/16 -d 10.106.202.0/32 -p tcp -m comment --comment "default/gowebsvc:default cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ -A KUBE-SERVICES -d 10.106.202.0/32 -p tcp -m comment --comment "default/gowebsvc:default cluster IP" -m tcp --dport 80 -j KUBE-SVC-SEG6BTF25PWEPDFT
可以看到,目的地址為CLUSTER-IP、目的端口為80的數據包,會被轉發到KUBE-MARK-MASQ與KUBE-SVC-SEG6BTF25PWEPDFT鏈上。其中,KUBE-MARK-MASQ鏈的作用是給數據包打上特定的標記(待驗證),重點來看下KUBE-SVC-SEG6BTF25PWEPDFT鏈:
-A KUBE-SVC-SEG6BTF25PWEPDFT -m statistic --mode random --probability 0.25000000000 -j KUBE-SEP-5ZXTVLEM4DKNW7T2 -A KUBE-SVC-SEG6BTF25PWEPDFT -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-EBFXI7VOCPDT2QU5 -A KUBE-SVC-SEG6BTF25PWEPDFT -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-C3PKSXKMO2M43SPF -A KUBE-SVC-SEG6BTF25PWEPDFT -j KUBE-SEP-2GQCCNJGO65Z5MFS
可以看到,KUBE-SVC-SEG6BTF25PWEPDFT鏈通過設置--probability,將請求等概率轉發到4條鏈上,查看其中一條轉發鏈:
[root@master-1 ~]# iptables-save | grep "A KUBE-SEP-5ZXTVLEM4DKNW7T2" -A KUBE-SEP-5ZXTVLEM4DKNW7T2 -s 10.244.1.15/32 -j KUBE-MARK-MASQ -A KUBE-SEP-5ZXTVLEM4DKNW7T2 -p tcp -m tcp -j DNAT --to-destination 10.244.1.15:8000
發現KUBE-SEP-5ZXTVLEM4DKNW7T2這條規則對請求的目的地址作了DNAT到10.244.1.15:8000,這正是goweb組中goweb-55c487ccd7-5t2l2這個pod的ip地址。這樣,對svc的CLUSTER-IP的請求,就會通過iptables規則轉發到相應的pod。
但是,還有個問題,svc是怎么跟蹤pod的ip變化的?
注意到前面的nat規則,第一次轉發的鏈名稱是KUBE-SVC-xxx,第二次轉發給具體pod的鏈名稱是KUBE-SEP-xxx,這里的SEP實際指的是kubernetes另一個對象endpoint,我們可以通過vkubectl get ep命令來查看:
[root@master-1 ~]# kubectl get ep gowebsvc NAME ENDPOINTS gowebsvc 10.244.1.15:8000,10.244.1.17:8000,10.244.3.10:8000 + 1 more... 35d
在svc創建的時候,kube-proxy組件會自動創建同名的endpoint對象,動態地跟蹤匹配selector的一組pod當前ip及端口,并生成相應的iptables KUBE-SVC-xxx規則。
請求代理的三種方式上面說的請求代理轉發的方式,是kubernetes目前版本的默認方式,實際上,service的代理方式一共有三種:
Userspace 模式在這種模式下,kube-proxy為每個服務都打開一個隨機的端口,所有訪問這個端口的請求都會被轉發到服務對應endpoints指定的后端。最后,kube-proxy還會生成一條iptables規則,把訪問cluster-ip的請求重定向到上面說的隨機端口,最終轉發到后端pod。整個過程如下圖所示:
Userspace模式的代理轉發主要依靠kube-proxy實現,工作在用戶態。所以,轉發效率不高。較為不推薦用該種模式。
iptables 模式iptables模式是目前版本的默認服務代理轉發模式,上兩小節做過詳細說明的就是這種模式,來看下請求轉發的示意圖:
與userspace模式最大的不同點在于,kube-proxy只動態地維護iptables,而轉發完全靠iptables實現。由于iptables工作在內核態,不用在用戶態與內核態切換,所以相比userspace模式更高效也更可靠。但是每個服務都會生成若干條iptables規則,大型集群iptables規則數會非常多,造成性能下降也不易排查問題。
ipvs 模式在v1.9版本以后,服務新增了ipvs轉發方式。kube-proxy同樣只動態跟蹤后端endpoints的情況,然后調用netlink接口來生成ipvs規則。通過ipvs來轉發請求:
ipvs同樣工作在內核態,而且底層轉發是依靠hash表實現,所以性能比iptables還要好的多,同步新規則也比iptables快。同時,負載均衡的方式除了簡單rr還有多種選擇,所以很適合在大型集群使用。而缺點就是帶來了額外的配置維護操作。
集群內部服務發現在集群內部對一個服務的訪問,主要有2種方式,環境變量與DNS。
環境變量方式當一個pod創建時,集群中屬于同個namespace下的所有service對象信息都會被作為環境變量添加到pod中。隨便找一個pod查看一下:
$ kubectl exec goweb-55c487ccd7-5t2l2 "env" | grep GOWEBSVC GOWEBSVC_PORT_80_TCP_ADDR=10.106.202.0 GOWEBSVC_SERVICE_PORT=80 GOWEBSVC_SERVICE_PORT_DEFAULT=80 GOWEBSVC_PORT_80_TCP=tcp://10.106.202.0:80 GOWEBSVC_PORT_80_TCP_PROTO=tcp GOWEBSVC_PORT_80_TCP_PORT=80 GOWEBSVC_PORT=tcp://10.106.202.0:80 GOWEBSVC_SERVICE_HOST=10.106.202.0
可以看到,pod通過{SVCNAME}_SERVICE_HOST/PORT就可以方便的訪問到某個服務。這種訪問方式簡單易用,可以用來快速測試服務。但最大的問題就是,服務必須先于pod創建,后創建的服務是不會添加到現有pod的環境變量中的。
DNS方式DNS組件是k8s集群的可選組件,它會不停監控k8s API,在有新服務創建時,自動創建相應的DNS記錄。。以gowebsvc為例,在服務創建時,會創建一條gowebsvc.default.svc.cluster.local的dns記錄指向服務。而且dns記錄作用域是整個集群,不局限在namespace。
雖然是可選組件,但DNS生產環境可以說是必備的組件了。這里先簡單說明,后面打算專門開篇文章來詳細介紹。
服務發現解決了集群內部訪問pod問題,但很多時候,pod提供的服務也是要對集群外部來暴露訪問的,最典型的就是web服務。k8s中的service有多種對外暴露的方式,可以在部署Service時通過ServiceType字段來指定。默認情況下,ServiceType配置是只能內部訪問的ClusterIP方式,前面的例子都是這種模式,除此之外,還可以配置成下面三種方式:
NodePort方式:該方式把服務暴露在每個Node主機IP的特定端口上,同一個服務在所有Node上端口是相同的,并自動生成相應的路由轉發到ClusterIP。這樣,集群外部通過
## 創建svc,通過Nodeport方式暴露服務 $ kubectl expose deployment goweb --name=gowebsvc-nodeport --port=80 --target-port=8000 --type=NodePort ## 查看svc,可以看到NodePort隨機分配的端口為32538 $ kubectl get svc gowebsvc-nodeport NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE gowebsvc-nodeport NodePort 10.101.166.252LoadBalance:80:32538/TCP 86s ## 隨便訪問一個nodeip的32538端口,都可以訪問到gowebsvc-nodeport服務對應的pod $ curl 172.16.201.108:32538/info Hostname: goweb-55c487ccd7-pp6t6 $ curl 172.16.201.109:32538/info Hostname: goweb-55c487ccd7-5t2l2
LoadBalance方式主要是給公有云服務使用的,通過配置LoadBalance,可以觸發公有云創建負載均衡器,并把node節點作為負載的后端節點。每個公有云的配置方式不同,具體可以參考各公有云的相關文檔。
ExternalName:當ServiceType被配置為這種方式時,該服務的目的就不是為了外部訪問了,而是為了方便集群內部訪問外部資源。舉個例子,假如目前集群的pod要訪問一組DB資源,而DB是部署在集群外部的物理機,還沒有容器化,可以配置這么一個服務:
apiVersion: v1 kind: Service metadata: name: dbserver namespace: default spec: type: ExternalName externalName: database.abc.com
這樣,集群內部的pod通過dbserver.default.svc.cluster.local這個域名訪問這個服務時,請求會被cname到database.abc.com來。過后,假如db容器化了,不需要修改業務代碼,直接修改service,加上相應selector就可以了。
幾種特殊的service除了上面這些通常的service配置,還有幾種特殊情況:
Multi-Port Servicesservice可以配置不止一個端口,比如官方文檔的例子:
apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: MyApp ports: - name: http protocol: TCP port: 80 targetPort: 9376 - name: https protocol: TCP port: 443 targetPort: 9377
這個service保留了80與443端口,分別對應pod的9376與9377端口。這里需要注意的是,pod的每個端口一定指定name字段(默認是default)。
Headless servicesHeadless services是指一個服務沒有配置了clusterIP=None的服務。這種情況下,kube-proxy不會為這個服務做負載均衡的工作,而是交予DNS完成。具體又分為2種情況:
有配置selector: 這時候,endpoint控制器會為服務生成對應pod的endpoint對象。service對應的DNS返回的是endpoint對應后端的集合。
沒有配置selector:這時候,endpoint控制器不會自動為服務生成對應pod的endpoint對象。若服務有配置了externalname,則生成一套cnmae記錄,指向externalname。如果沒有配置,就需要手動創建一個同名的endpoint對象。dns服務會創建一條A記錄指向endpoint對應后端。
External IPs如果有個非node本地的IP地址,可以通過比如外部負載均衡的vip等方式被路由到任意一臺node節點,那就可以通過配置service的externalIPs字段,通過這個IP地址訪問到服務。集群以這個IP為目的IP的請求時,會把請求轉發到對應服務。參考官方文檔的例子:
apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: MyApp ports: - name: http protocol: TCP port: 80 targetPort: 9376 externalIPs: - 80.11.12.10
這里的80.11.12.10就是一個不由kubernetes維護的公網IP地址,通過80.11.12.10:80就可以訪問到服務對應的pod。
簡單總結下,service對象實際上解決的就是一個分布式系統的服務發現問題,把相同功能的pod做成一個服務集也能很好的對應微服務的架構。在目前的kubernetes版本中,service還只能實現4層的代理轉發,并且要搭配好DNS服務才能真正滿足生產環境的需求。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/32978.html
摘要:參數說明本文主要描述用于創建類型的時,與相關的說明。為時表示連接保持的時間,單位為秒,取值范圍,,表示禁用連接保持,默認為。會話保持方式枚舉值為關閉,自動生成,用戶自定義,默認為。健康檢查方式為時有效,指檢查路徑。ULB 參數說明本文主要描述用于創建LoadBalancer 類型的Service時,與ULB相關的Annotations說明。備注:目前除了外網 ULB 綁定的 EIP 的帶寬值...
摘要:儀表板是一個附加組件,它能提供集群上運行的資源的概述信息。可以很容易地創建圖形,并且把它們合并稱儀表板,而這些儀表板由一個強大的身份驗證和授權層保護,它們還可以和其他儀表板進行共享而不需要訪問服務器本身。 介 紹 Kubernetes在Github上擁有超過4萬顆星,7萬以上的commits,以及像Google這樣的主要貢獻者。Kubernetes可以說已經快速地接管了容器生態系統,成...
摘要:下載在這里下載修改替換鏡像修改添加,同時把由改為。因為的跟中的的沖突了。修改新增的暴露出來,同時添加創建配置修改下數據源的查看數據總結部署詳解監控 下載yaml 在這里下載deploy/kube-config/influxdb 修改yaml 替換鏡像 gcr.io/google_containers/heapster-grafana:v4.0.2 registry.cn-hangzho...
摘要:下面通過該文章來簡述的基礎信息并詳述的生命周期。聲明周期鉤子函數為容器提供了兩種生命周期鉤子于容器創建完成之后立即運行的鉤子程序。向容器指定發起請求,響應碼為或者是為成功,否則失敗。 簡述 Kubernetes 是一種用于在一組主機上運行和協同容器化應用程序的系統,提供應用部署、規劃、更新維護的機制。應用運行在 kubernetes 集群之上,實現服務的擴容、縮容,執行滾動更新以及在不...
閱讀 3384·2023-04-26 01:46
閱讀 2906·2023-04-25 20:55
閱讀 5471·2021-09-22 14:57
閱讀 2974·2021-08-27 16:23
閱讀 1712·2019-08-30 14:02
閱讀 2063·2019-08-26 13:44
閱讀 644·2019-08-26 12:08
閱讀 2951·2019-08-26 11:47