系列目錄html
經過ReplicaSet來建立一組Pod來提供具備高可用性的服務。雖然每一個Pod都會分配一個單獨的Pod IP,然而卻存在以下兩問題:node
Pod IP僅僅是集羣內可見的虛擬IP,外部沒法訪問。nginx
Pod IP會隨着Pod的銷燬而消失,當ReplicaSet對Pod進行動態伸縮時,Pod IP可能隨時隨地都會變化,這樣對於咱們訪問這個服務帶來了難度。算法
所以,Kubernetes中的Service對象就是解決以上問題的核心關鍵。數據庫
Service能夠看做是一組提供相同服務的Pod對外的訪問接口
。藉助Service,應用能夠方便地實現服務發現和負載均衡
。json
Service同其餘Kubernetes對象同樣,也是經過yaml或json文件進行定義。此外,它和其餘Controller對象同樣,經過Label Selector來肯定一個Service將要使用哪些Pod。一個簡單的Service定義以下:後端
apiVersion: v1 kind: Service metadata: labels: run: nginx name: nginx-service spec: ports: - port: 80 protocol: TCP targetPort: 81 selector: app: nginx type: ClusterIP
下面簡單分析一下上面的Service描述文件:api
經過spec.selector字段肯定這個Service將要使用哪些Label。在本例中,這個名爲nginx的Service,將會管理全部具備app: nginxLabel的Pod。服務器
spec.ports.port: 80代表此Service將會監聽80端口,並將全部監聽到的請求轉發給其管理的Pod。spec.ports.targetPort: 81代表此Service監聽到的80端口的請求都會被轉發給其管理的Pod的81端口,此字段能夠省略,省略後其值會被設置爲spec.ports.port的值。session
type: ClusterIP表面此Service的type,會在下文中講到。
在Serive定義時,咱們須要指定spec.type字段,這個字段擁有四個選項:
ClusterIP。默認值。給這個Service分配一個Cluster IP,它是Kubernetes系統自動分配的虛擬IP,所以只能在集羣內部訪問。
NodePort。將Service經過指定的Node上的端口暴露給外部
。經過此方法,訪問任意一個NodeIP:nodePort
都將路由到ClusterIP,從而成功得到該服務。
LoadBalancer。在 NodePort 的基礎上,藉助 cloud provider 建立一個外部的負載均衡器,並將請求轉發到
ExternalName。將服務經過 DNS CNAME 記錄方式轉發到指定的域名(經過 spec.externlName 設定)。須要 kube-dns 版本在 1.7 以上。
注:kubernetes 1.13之後默認集羣coreDns,再也不使用默認kube-dns,對
ExternalName
支持狀況須要進一步確認
在定義Service時指定spec.type=NodePort,並指定spec.ports.nodePort
的值,Kubernetes就會在集羣中的每個Node上打開你定義的這個端口
,這樣,就可以從外部經過任意一個NodeIP:nodePort訪問到這個Service
了。
下面是一個簡單的例子:
apiVersion: v1 kind: Service metadata: name: nginx-service labels: run: nginx spec: selector: app: nginx ports: - port: 80 nodePort: 30001 type: NodePort
假若有3個app: nginx Pod運行在3個不一樣的Node中,那麼此時客戶端訪問任意一個Node的30001端口都能訪問到這個nginx服務。
若是雲服務商支持外接負載均衡器,則能夠經過spec.type=LoadBalancer
來定義Service,一個簡單的例子以下:
kind: Service apiVersion: v1 metadata: name: my-service spec: selector: app: MyApp ports: - protocol: TCP port: 80 targetPort: 9376 clusterIP: 10.0.171.239 loadBalancerIP: 78.11.24.19 type: LoadBalancer status: loadBalancer: ingress: - ip: 146.148.47.155
Service能夠抽象訪問Pod集羣,同時 Service也能夠抽象其餘後端
在生產環境中使用外部數據庫,在測試環境中使用本身的數據庫
將本身的Service指向其餘集羣或者其餘命名空間的Service
遷移應用到k8s,可是仍是有些應用運行在k8s之
經過定義不包含selector的Service實現
kind: service apiVersion: v1 metadata: name: my-service spec: ports: - protocol: TCP port: 80 targetPort: 9376
Service 沒有Selector,K8s不會建立Endpoints,你能夠經過手動建立Endpoint指向本身的endpoint
kind: Endpoints apiVersion: v1 metadata: name: my-service subsets: - addresses: ip: 1.2.3.4 - ports: port: 9376
Endpoint的IP不能是loopback(127.0.0.1/8),link-local(169.254.0.0/16), link-local
multicast (224.0.0.0/24).
訪問不含有selector的Service和訪問含有Selector的Service 方式同樣,都會講流向重定向的endpoint
其餘命名空間的服務是一個特例,他不會定義ports和endpoint,他只是返回一個訪問外部服務的別名
其餘命名空間的服務是一個特例,他不會定義ports和endpoint,他只是返回一個訪問外部服務的別名
kind: kind apiVersion: v1 metadata: name: my-service namespace: prod spec: type: ExternalName externalName: my.database.example.com
當你訪問服務my-service.prod.svc.CLUSTER時,cluster的dns服務會返回記錄my.database.example.com 的CNAME,這個重定向是發生在dns解析階段。
K8s集羣內每一個節點都會運行kube-proxy,負責實現服務的虛擬機IP(不是externalName)。1.0版本的代理模式在是userspace,1.1增長了iptables proxy,從1.2開始 iptables 代理是默認的模式
K8s 1.0的service是三層(TCP/UDP),從k8s1.1開始,增長了Ingress,實現七層(HTTP)服務
Kube-proxy監控k8s master節點來發現Service、Endpointd的增長和刪除,對於Service,在本地打開一個隨機端口做爲代理端口,任何訪問改代理端口的鏈接都會被指向Service對象的Pod集合,最終指向哪一個Pod取決於Service的SessionAffinity,最後,他會配置iptables,捕獲流向Service 的Cluster IP 和Port的鏈接,並重定向到這個代理端口。
最終結果,任何到Service Cluster Ip 和port的流量都會指向合適的Pod
默認狀況下,都是輪訓算法選擇後端,也能夠經過設置service.spec.sessionAffinity 爲ClientIP,將選擇算法改成Client-IP based session affinity
該模式與userspace模式相似,只是沒有這個代理端口
比userspace方式更快更可靠,而後與userspace方式不一樣,當選擇的pod異常時,該方式沒法自動嘗試選擇其餘Pod。
userspace模式只不適合大規模集羣使用(數千個服務)
userspace模式隱藏了訪問服務的源IP,iptables模式雖然沒有隱藏源IP,可是也是經過負載均衡或者nodeport 影響了客戶端輸入