當新手剛學習k8s時候,會被各類的IP 和port 搞暈,其實它們都與k8s service的訪問有密切關係,梳理它們之間的差別能夠更好了解k8s的服務訪問機制。node
Pod IP 地址是實際存在於某個網卡(能夠是虛擬設備)上的,但Service Cluster IP就不同了,沒有網絡設備爲這個地址負責。它是由kube-proxy使用Iptables規則從新定向到其本地端口,再均衡到後端Pod的。mysql
例如,當Service被建立時,Kubernetes給它分配一個地址10.0.0.1。這個地址從咱們啓動API的service-cluster-ip-range參數(舊版本爲portal_net參數)指定的地址池中分配,好比--service-cluster-ip-range=10.0.0.0/16。假設這個Service的端口是1234。集羣內的全部kube-proxy都會注意到這個Service。當proxy發現一個新的service後,它會在本地節點打開一個任意端口,建相應的iptables規則,重定向服務的IP和port到這個新建的端口,開始接受到達這個服務的鏈接。nginx
當一個客戶端訪問這個service時,這些iptable規則就開始起做用,客戶端的流量被重定向到kube-proxy爲這個service打開的端口上,kube-proxy隨機選擇一個後端pod來服務客戶。web
Service的IP地址,此爲虛擬IP地址。外部網絡沒法ping通,只有kubernetes集羣內部訪問使用。經過命令 kubectl -n 命名空間 get Service
便可查詢ClusterIPsql
Cluster IP是一個虛擬的IP,但更像是一個僞造的IP網絡,緣由有如下幾點mongodb
Cluster IP僅僅做用於Kubernetes Service這個對象,並由Kubernetes管理和分配P地址docker
Cluster IP沒法被ping,他沒有一個「實體網絡對象」來響應數據庫
Cluster IP只能結合Service Port組成一個具體的通訊端口Endpoint
,單獨的Cluster IP不具有通訊的基礎,而且他們屬於Kubernetes集羣這樣一個封閉的空間。後端
在不一樣Service下的pod節點在集羣間相互訪問能夠經過Cluster IPapi
爲了實現圖上的功能主要須要如下幾個組件的協同工做:
根據是否生成ClusterIP又可分爲普通Service和Headless Service兩類:
普通Service:經過爲Kubernetes的Service分配一個集羣內部可訪問的固定虛擬IP(Cluster IP),實現集羣內的訪問。爲最多見的方式。
Headless Service:該服務不會分配Cluster IP,也不經過kube-proxy作反向代理和負載均衡。而是經過DNS提供穩定的網絡ID來訪問,DNS會將headless service的後端直接解析爲Pod IP列表。主要供StatefulSet使用
。
apiVersion: v1 kind: Service metadata: name: nginx-service spec: type: NodePort // 有配置NodePort,外部流量可訪問k8s中的服務 ports: - port: 30080 // 服務訪問端口,集羣內部訪問的端口 targetPort: 80 // pod控制器中定義的端口(應用訪問的端口) nodePort: 30001 // NodePort,外部客戶端訪問的端口 selector: name: nginx-pod
內部訪問
service的端口(service暴露在Cluster IP上的端口),即經過clusterIP: port
能夠訪問到某個service外部訪問
k8s集羣中service的端口,經過nodeIP: nodePort
能夠從外部訪問到某個service。該端口號的範圍是 kube-apiserver 的啓動參數 –service-node-port-range指定的,在當前測試環境中其值是 30000-50000。表示只容許分配30000-50000之間的端口。
好比外部用戶要訪問k8s集羣中的一個Web應用,那麼咱們能夠配置對應service的type=NodePort,nodePort=30001。其餘用戶就能夠經過瀏覽器http://node:30001訪問到該web服務。而數據庫等服務可能不須要被外界訪問,只需被內部服務訪問便可,那麼咱們就沒必要設置service的NodePort
這是一種直接定義Pod網絡的方式。hostPort是直接將容器的端口與所調度的節點上的端口路由,這樣用戶就能夠經過宿主機的IP加上來訪問Pod了,如
apiVersion: v1 kind: Pod metadata: name: influxdb spec: containers: - name: influxdb image: influxdb ports: - containerPort: 8086 # 此處定義暴露的端口 hostPort: 8086
這樣作有個缺點,由於Pod從新調度的時候該Pod被調度到的宿主機可能會變更,這樣就變化了,用戶必須本身維護一個Pod與所在宿主機的對應關係。
使用了 hostPort 的容器只能調度到端口不衝突的 Node 上,除非有必要(好比運行一些系統級的 daemon 服務),不建議使用端口映射功能。若是須要對外暴露服務,建議使用 NodePort Service。
總的來講,port和nodePort都是service的端口,前者暴露給集羣內客戶訪問服務,後者暴露給集羣外客戶訪問服務。從這兩個端口到來的數據都須要通過反向代理kube-proxy流入後端 pod的targetPod,從而到達pod上的容器內。
建立Service的同時,會自動建立跟Service同名的Endpoints。
Endpoint 是k8s集羣中一個資源對象,存儲在etcd裏面,用來記錄一個service對應的全部pod的訪問地址。service經過selector和pod創建關聯。
Endpoint = Pod IP + Container Port
service配置selector endpoint controller 纔會自動建立對應的endpoint 對象,不然是不會生產endpoint 對象
一個service由一組後端的pod組成,這些後端的pod經過service endpoint暴露出來,若是有一個新的pod建立建立出來,且pod的標籤名稱(label:pod)跟service裏面的標籤(label selector 的label)一致會自動加入到service的endpoints 裏面,若是pod對象終止後,pod 會自動從edponts 中移除。在集羣中任意節點 可使用curl請求service <CLUSTER-IP>:<PORT>
Endpoint Controller是k8s集羣控制器的其中一個組件,其功能以下:
對於Service,咱們還能夠定義Endpoint,Endpoint 把Service和Pod動態地鏈接起來,Endpoint 的名稱必須和服務的名稱相匹配。
建立mysql-service.yaml
apiVersion: v1 kind: Service metadata: name: mysql-production spec: ports: - port: 3306
建立mysql-endpoints.yaml
kind: Endpoints apiVersion: v1 metadata: name: mysql-production namespace: default subsets: - addresses: - ip: 192.168.1.25 ports: - port: 3306
[root@k8s-master endpoint]# kubectl describe svc mysql-production Name: mysql-production Namespace: default Labels: <none> Annotations: <none> Selector: <none> Type: ClusterIP IP: 10.254.218.165 Port: <unset> 3306/TCP Endpoints: 192.168.1.25:3306 Session Affinity: None Events: <none>
service 不只能夠代理pod, 還能夠代理任意其它的後端(運行在k8s集羣外部的服務,好比mysql mongodb)。若是須要從k8s裏面連接外部服務(mysql),可定義同名的service和endpoint
在實際生成環境中,像mysql mongodb這種IO密集行應用,性能問題會顯得很是突出,因此在實際應用中,通常不會把這種有狀態的應用(mysql 等)放入k8s裏面,而是使用單獨的服務來部署,而像web這種無狀態的應用更適合放在k8s裏面 裏面k8s的自動伸縮,和負載均衡,故障自動恢復 等強大功能
建立service (mongodb-service-exten)
kind: Service apiVersion: v1 metadata: name: mongodb namespace: name spec: ports: - port: 30017 name: mongodb targetPort: 30017
建立 endpoint(mongodb-endpoint)
kind: Endpoints apiVersion: v1 metadata: name: mongodb namespace: tms-test subsets: - addresses: - ip: xxx.xxx.xx.xxx ports: - port: 30017 name: mongod
能夠看到service跟endpoint成功掛載一塊兒了,表面外面服務成功掛載到k8s裏面了,在應用中配置連接的地方使用mongodb://mongodb:30017
連接數據
除了手動配置服務的endpoint來代替公開外部服務方法,還能夠經過徹底限定域名(FQDN)
訪問外部服務——建立ExternalName類型的服務。
ExternalName類型的服務建立後,pod能夠經過external-service.default.svc.cluster.local
域名鏈接到外部服務,或者經過externale-service
。當須要指向其餘外部服務時,只須要修改spec.externalName的值便可。