K8s Service(3)

Service

概念介紹

雖然每個Pod都會被分配一個單獨的IP地址,但這個IP地址會隨著Pod的銷毀而消失悲关。引出的一個問題是:如果有一組Pod組成一個應(yīng)用集群來提供服務(wù),那么該如何訪問它們呢娄柳?

Service就是用來解決這個問題的,一個Service可以看作一組提供相同服務(wù)的Pod的對外接口艘绍,Service是通過LabelSelector選擇一組Pod作為后端服務(wù)提供者赤拒。

定義

一個 Service 在 Kubernetes 中是一個 REST 對象,和 Pod 類似。
例如挎挖,假定有一組 Pod这敬,它們對外暴露了 3000 端口,同時還被打上 app=jaymz 標(biāo)簽蕉朵。

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: jaymz
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000

上述配置創(chuàng)建一個名稱為 “my-service” 的 Service 對象崔涂,它會將請求代理到使用 TCP 端口 3000,并且具有標(biāo)簽 "app=jaymz"Pod 上始衅。 Kubernetes 為該服務(wù)分配一個 IP 地址(有時稱為 “集群IP” )冷蚂。

多端口 Service

對于某些服務(wù),需要公開多個端口汛闸。 Kubernetes允許在Service對象上配置多個端口定義蝙茶。 當(dāng)使用多個端口時,必須提供所有端口名稱诸老,以使它們無歧義隆夯。 例如:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 3000
    - name: https
      protocol: TCP
      port: 443
      targetPort: 9000

服務(wù)代理

在 Kubernetes 集群中,每個 Node 運行一個 kube-proxy 進(jìn)程。kube-proxy 負(fù)責(zé)為 Service 實現(xiàn)了一種 VIP(虛擬 IP)的形式睬关,而不是 ExternalName 的形式赠尾。

為什么不使用 DNS 輪詢?

時不時會有人問道宦芦,就是為什么 Kubernetes 依賴代理將入站流量轉(zhuǎn)發(fā)到后端。 那其他方法呢轴脐? 例如调卑,是否可以配置具有多個A值(或IPv6為AAAA)的DNS記錄,并依靠輪詢名稱解析大咱?

使用服務(wù)代理有以下幾個原因:

  • DNS 實現(xiàn)的歷史由來已久恬涧,它不遵守記錄 TTL,并且在名稱查找結(jié)果到期后對其進(jìn)行緩存碴巾。
  • 有些應(yīng)用程序僅執(zhí)行一次 DNS 查找溯捆,并無限期地緩存結(jié)果。
  • 即使應(yīng)用和庫進(jìn)行了適當(dāng)?shù)闹匦陆馕鱿闷埃珼NS 記錄上的 TTL 值低或為零也可能會給 DNS 帶來高負(fù)載提揍,從而使管理變得困難。

版本兼容性

從Kubernetes v1.0開始煮仇,您已經(jīng)可以使用 用戶空間代理模式劳跃。 Kubernetes v1.1添加了 iptables 模式代理,在 Kubernetes v1.2 中浙垫,kube-proxy 的 iptables 模式成為默認(rèn)設(shè)置刨仑。 Kubernetes v1.8添加了 ipvs 代理模式郑诺。

虛擬IP

Service一般會提供一個虛擬IP(Virtual IP),它在Service創(chuàng)建之后就保持不變杉武,并且能夠被同一集群中的Pod資源所訪問辙诞。Service端口用于接收客戶端請求并將其轉(zhuǎn)發(fā)給后端的Pod應(yīng)用程序,這種代理機(jī)制稱為“端口代理”或四層代理轻抱,工作于TCP/IP協(xié)議棧的傳輸層飞涂。

API Server會持續(xù)監(jiān)聽(watch)Pod的變化(增加、刪除)祈搜,并實時更新Endpoint较店,Endpoint是一個由Pod的IP地址和端口組成的列表,Service會從Endpoint列表中選擇一條記錄進(jìn)行流量調(diào)度夭问。

服務(wù)代理 - userspace(用戶空間)泽西、iptables、ipvs

在眾多的Pod對象中缰趋,Service資源是如何選擇正確的Pod進(jìn)行流量調(diào)度的呢捧杉?

這就是我們要具體介紹的,Kubernetes提供的“端口代理”的幾種實現(xiàn)方式秘血。

簡單來說味抖,一個Service對象就是Node上的一些iptables或ipvs規(guī)則,用于將到達(dá)Service對象的流量調(diào)度到相應(yīng)的Pod上灰粮。Kubernetes集群中的每個Node上都會有產(chǎn)生一個Kube-proxy程序仔涩,它通過API-Server持續(xù)監(jiān)控各Service及其關(guān)聯(lián)的Pod對象,并將其變化實時反映至當(dāng)前節(jié)點的iptables或ipvs規(guī)則上粘舟。

kube-Proxy將請求代理至相應(yīng)端點的方式有三種:userspace(用戶空間)熔脂、iptables、ipvs
userspace代理模型

這里的userspace是指Linux操作系統(tǒng)的用戶空間柑肴。對于每個Service對象它會打開一個本地端口(運行于用戶空間的kube-proxy進(jìn)程負(fù)責(zé)監(jiān)聽此端口)霞揉,任何到達(dá)此代理端口的連接請求都會被代理至當(dāng)前Service資源后端的各Pod對象上,至于會挑選哪個Pod取決于Service資源的調(diào)度方式晰骑,默認(rèn)為輪詢(roundrobin)

這種代理模式請求流量到達(dá)內(nèi)核空間后經(jīng)由套接字送往用戶空間的kube-proxy适秩,而后由它送回內(nèi)核空間,并調(diào)度至后端pod硕舆。這種方式請求會在內(nèi)核和用戶空間之間來回轉(zhuǎn)發(fā)導(dǎo)致效率不高秽荞。

iptables代理模型

iptables代理模式和前一種代理模式是類似的,都是由kube-proxy來跟蹤監(jiān)聽API-server上的service和Endpoints的變更抚官。但是有一點不同的是iptables規(guī)則直接捕獲到達(dá)cluster IP和port的流量扬跋,并將其重定向至當(dāng)前Service的后端,對于每個Endpoints對象耗式,Service資源會為其創(chuàng)建iptables規(guī)則并關(guān)聯(lián)至挑選的后端pod資源胁住,默認(rèn)算法是隨機(jī)調(diào)度(random)趁猴。iptables代理模式在Kubernetes1.1版本引入刊咳,并在1.2版開始成為默認(rèn)類型彪见。

在創(chuàng)建service資源時,集群中每個節(jié)點上的kube-proxy都會接受到通知并將其定義為當(dāng)前節(jié)點上的iptables規(guī)則娱挨,用于轉(zhuǎn)發(fā)接收到的iptables余指,進(jìn)行調(diào)度和目標(biāo)地址轉(zhuǎn)換(DNAT)后再轉(zhuǎn)發(fā)至集群內(nèi)部的pod對象上。

默認(rèn)的策略是跷坝,kube-proxy 在 iptables 模式下隨機(jī)選擇一個 backend酵镜。

相對于用戶空間來講,iptables模型無須將流量在用戶空間和內(nèi)核空間來回切換柴钻,因更加高效和可靠淮韭。

ipvs代理模型

Kubernetes從1.9版本引入ipvs代理模型,且從1.11版本起成為默認(rèn)設(shè)置贴届。它和iptables模型很類似靠粪,唯一一點不同的是在其請求流量的調(diào)度功能由ipvs實現(xiàn),余下的功能仍由iptables完成毫蚓。

ipvs是建立在netfilter的鉤子函數(shù)上占键,但它使用hash表作為底層數(shù)據(jù)結(jié)構(gòu)并工作于內(nèi)核空間,因此流量轉(zhuǎn)發(fā)速度特別快元潘、規(guī)則同步性很好畔乙,而且它支持眾多調(diào)度算法,rr(輪詢)翩概、lc(最小連接數(shù))牲距、dh(目標(biāo)哈希)、sh(源哈希)钥庇、sed(最短期望延遲)牍鞠、nq(不排隊調(diào)度)。

服務(wù)發(fā)現(xiàn)

Kubernetes 支持2種基本的服務(wù)發(fā)現(xiàn)模式 —— 環(huán)境變量和 DNS上沐。

環(huán)境變量

當(dāng) Pod 運行在 Node 上皮服,kubelet 會為每個活躍的 Service 添加一組環(huán)境變量, {SVCNAME}_SERVICE_HOST{SVCNAME}_SERVICE_PORT 變量参咙,這里 Service 的名稱需大寫龄广,橫線被轉(zhuǎn)換成下劃線。

舉例蕴侧,一個名稱為 "redis-master" 的 Service 暴露了 TCP 端口 6379择同,同時給它分配了 Cluster IP 地址 10.0.0.11,這個 Service 生成了如下環(huán)境變量:

REDIS_MASTER_SERVICE_HOST=10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
REDIS_MASTER_PORT_6379_TCP_PORT=6379
REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11

注意: 必須在Pod出現(xiàn) 之前 創(chuàng)建Service净宵, 否則敲才,這些Pod將不會設(shè)定其環(huán)境變量裹纳。 如果僅使用DNS查找Service的群集IP,則無需擔(dān)心環(huán)境變量問題紧武。

DNS

您可以使用附加組件為Kubernetes集群設(shè)置DNS服務(wù)剃氧。

支持群集的DNS服務(wù)器(例如CoreDNS)監(jiān)視 Kubernetes API 中的新Service,并為每個Service創(chuàng)建一組 DNS 記錄阻星。 如果在整個集群中都啟用了 DNS朋鞍,則所有 Pod 都應(yīng)該能夠通過其 DNS 名稱自動解析出Service對應(yīng)的IP地址。

Headless Services

有時不需要或不想要負(fù)載均衡妥箕,以及單獨的 Service IP滥酥。 遇到這種情況,可以通過指定 Cluster IP(spec.clusterIP)的值為 "None" 來創(chuàng)建 Headless Service畦幢。

您可以使用 headless Service 與其他服務(wù)發(fā)現(xiàn)機(jī)制進(jìn)行接口坎吻,而不必與 Kubernetes 的實現(xiàn)捆綁在一起。

對這 headless Service 并不會分配 Cluster IP宇葱,kube-proxy 不會處理它們瘦真,而且平臺也不會為它們進(jìn)行負(fù)載均衡和路由。 DNS 如何實現(xiàn)自動配置贝搁,依賴于 Service 是否定義了 selector吗氏。

配置 Selector

對定義了 selector 的 Headless Service,Endpoint 控制器在 會創(chuàng)建 Endpoints 記錄雷逆,并且修改 DNS 配置返回 A 記錄(地址)弦讽,通過這個地址直接到達(dá) Service 的后端 Pod 上。

配置 Selector的Headless Services應(yīng)用場景
  1. 自主選擇權(quán)膀哲,有時候client想自己來決定使用哪個Endpoints記錄往产,可以通過查詢DNS來獲取Endpoints的信息。

  2. Headless Services還有一個用處(PS:也就是我們需要的那個特性)某宪。Headless Service的對應(yīng)的每一個Endpoints仿村,即每一個Pod,都會有對應(yīng)的DNS域名兴喂;這樣Pod之間就可以互相訪問蔼囊。

不配置 Selector

對沒有定義 selector 的 Headless Service,Endpoint 控制器不會創(chuàng)建 Endpoints 記錄衣迷。 然而 DNS 系統(tǒng)會查找和配置畏鼓,無論是:

  • ExternalName 類型 Service 的 CNAME 記錄
  • 記錄:與 Service 共享一個名稱的任何 Endpoints,以及所有其它類型
不配置 Selector的Headless Services應(yīng)用場景

Service最常見的應(yīng)用是作為Pod的負(fù)載均衡器(反向代理)使用壶谒,抽象化對 Kubernetes Pod 的訪問云矫,但是Service也可以作為其他應(yīng)用程序的反向代理來使用。 實例:

  • 希望在生產(chǎn)環(huán)境中使用外部的數(shù)據(jù)庫集群汗菜,但測試環(huán)境使用自己的數(shù)據(jù)庫让禀。
  • 希望Service指向另一個Namespace中或其它集群中的服務(wù)挑社。
  • 您正在將工作負(fù)載遷移到 Kubernetes。 在評估該方法時巡揍,您僅在 Kubernetes 中運行一部分后端痛阻。
    服務(wù)沒有選擇器,因此不會自動創(chuàng)建相應(yīng)的 Endpoint 對象吼肥。 您可以通過手動添加 Endpoint 對象录平,將服務(wù)手動映射到運行該服務(wù)的網(wǎng)絡(luò)地址和端口:
apiVersion: v1
kind: Endpoints
metadata:
  name: my-service
subsets:
  - addresses:
      - ip: 192.0.2.42
    ports:
      - port: 9376

注意: 端點 IPs 必須不可以 : 環(huán)回( IPv4 的 127.0.0.0/8 , IPv6 的 ::1/128 )或本地鏈接(IPv4 的 169.254.0.0/16 和 224.0.0.0/24麻车,IPv6 的 fe80::/64)缀皱。 端點 IP 地址不能是其他 Kubernetes Services 的群集 IP,因為 kube-proxy 不支持將虛擬 IP 作為目標(biāo)动猬。

訪問沒有 selector 的 Service啤斗,與有 selector 的 Service 的原理相同。 請求將被路由到用戶定義的 Endpoint赁咙, YAML中為: 192.0.2.42:9376 (TCP)钮莲。

ExternalName ServiceService 的特例,它沒有 selector彼水,也沒有使用 DNS 名稱代替崔拥。

類型ExternalName

類型為 ExternalName 的服務(wù)將Service 映射到 DNS 名稱,而不是典型的選擇器凤覆,例如 my-service 链瓦, 您可以使用 spec.externalName 參數(shù)指定這些服務(wù)。

例如盯桦,以下 Service 定義將 prod 名稱空間中的 my-service 服務(wù)映射到 my.database.example.com

apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: my.database.example.com

注意: ExternalName 接受 IPv4 地址字符串慈俯,但作為包含數(shù)字的 DNS 名稱,而不是 IP 地址拥峦。 類似于 IPv4 地址的外部名稱不能由 CoreDNS 或 ingress-nginx 解析贴膘,因為外部名稱旨在指定規(guī)范的 DNS 名稱。 要對 IP 地址進(jìn)行硬編碼略号,請考慮使用 headless Services刑峡。

當(dāng)查找主機(jī) my-service.prod.svc.cluster.local 時,群集DNS服務(wù)返回 CNAME 記錄玄柠,其值為 my.database.example.com突梦。 訪問 my-service 的方式與其他服務(wù)的方式相同,但主要區(qū)別在于重定向發(fā)生在 DNS 級別随闪,而不是通過代理或轉(zhuǎn)發(fā)阳似。 如果以后您決定將數(shù)據(jù)庫移到群集中,則可以啟動其 Pod铐伴,添加適當(dāng)?shù)倪x擇器或端點以及更改Service的類型撮奏。

外部 IP

如果外部的 IP 路由到集群中一個或多個 Node 上俏讹,Kubernetes Service 會被暴露給這些 externalIPs。 通過外部 IP(作為目的 IP 地址)進(jìn)入到集群畜吊,打到 Service 的端口上的流量泽疆,將會被路由到 Service 的 Endpoint 上。 externalIPs 不會被 Kubernetes 管理玲献,它屬于集群管理員的職責(zé)范疇殉疼。

發(fā)布服務(wù) —— 服務(wù)類型

有一些Pod可能希望將服務(wù)暴露給外部應(yīng)用調(diào)用,可以通過Service捌年,選擇合適的類型來實現(xiàn)瓢娜。

Service的默認(rèn)值是 ClusterIP 類型。

Type 的可選值以及行為如下:

  • ClusterIP:通過集群的內(nèi)部 IP 暴露服務(wù)礼预,選擇該值眠砾,服務(wù)只能夠在集群內(nèi)部可以訪問,這也是默認(rèn)的 ServiceType托酸。
  • NodePort:通過每個 Node 上的 IP 和靜態(tài)端口(NodePort)暴露服務(wù)褒颈。NodePort 服務(wù)會路由到 ClusterIP 服務(wù),這個 ClusterIP 服務(wù)會自動創(chuàng)建励堡。通過請求 <NodeIP>:<NodePort>谷丸,可以從集群的外部訪問一個 NodePort 服務(wù)。
  • LoadBalancer:使用云提供商的負(fù)載局衡器应结,可以向外部暴露服務(wù)刨疼。外部的負(fù)載均衡器可以路由到 NodePort 服務(wù)和 ClusterIP 服務(wù)。
  • ExternalName:通過返回 CNAME 和它的值摊趾,可以將服務(wù)映射到 externalName 字段的內(nèi)容(例如币狠, foo.bar.example.com)。 沒有任何類型代理被創(chuàng)建砾层。

注意: 您需要 CoreDNS 1.7 或更高版本才能使用 ExternalName 類型漩绵。

您也可以使用 Ingress 來暴露自己的服務(wù)。 Ingress 不是服務(wù)類型肛炮,但它充當(dāng)集群的入口點止吐。 它可以將路由規(guī)則整合到一個資源中,因為它可以在同一IP地址下公開多個服務(wù)侨糟。

保留源 IP

各種類型的 Service 對源 IP 的處理方法不同:

  • 使用 userspace 代理碍扔,隱藏了訪問 Service 的數(shù)據(jù)包的源 IP 地址。 這使得一些類型的防火墻無法起作用秕重。

  • ClusterIP Service:使用 iptables 模式不同,集群內(nèi)部的源 IP 會保留(不做 SNAT)。如果 client 和 server pod 在同一個 Node 上,那源 IP 就是 client pod 的 IP 地址二拐;如果在不同的 Node 上服鹅,源 IP 則取決于網(wǎng)絡(luò)插件是如何處理的,比如使用 flannel 時百新,源 IP 是 node flannel IP 地址企软。

  • NodePort Service:默認(rèn)情況下,源 IP 會做 SNAT饭望,server pod 看到的源 IP 是 Node IP仗哨。為了避免這種情況,可以給 service 設(shè)置 spec.ExternalTrafficPolicy=Local (1.6-1.7 版本設(shè)置 Annotation service.beta.kubernetes.io/external-traffic=OnlyLocal)铅辞,讓 service 只代理本地 endpoint 的請求(如果沒有本地 endpoint 則直接丟包)厌漂,從而保留源 IP。

  • LoadBalancer Service:默認(rèn)情況下巷挥,源 IP 會做 SNAT桩卵,server pod 看到的源 IP 是 Node IP。設(shè)置 service.spec.ExternalTrafficPolicy=Local 后可以自動從云平臺負(fù)載均衡器中刪除沒有本地 endpoint 的 Node倍宾,從而保留源 IP。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末胜嗓,一起剝皮案震驚了整個濱河市高职,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌辞州,老刑警劉巖怔锌,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異变过,居然都是意外死亡埃元,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門媚狰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來岛杀,“玉大人,你說我怎么就攤上這事崭孤±噜停” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵辨宠,是天一觀的道長遗锣。 經(jīng)常有香客問我,道長嗤形,這世上最難降的妖魔是什么精偿? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上笔咽,老公的妹妹穿的比我還像新娘墓阀。我一直安慰自己,他們只是感情好拓轻,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布斯撮。 她就那樣靜靜地躺著,像睡著了一般扶叉。 火紅的嫁衣襯著肌膚如雪勿锅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天枣氧,我揣著相機(jī)與錄音溢十,去河邊找鬼。 笑死达吞,一個胖子當(dāng)著我的面吹牛张弛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播酪劫,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼吞鸭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了覆糟?” 一聲冷哼從身側(cè)響起刻剥,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎滩字,沒想到半個月后造虏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡麦箍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年漓藕,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挟裂。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡享钞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出话瞧,到底是詐尸還是另有隱情嫩与,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布交排,位于F島的核電站划滋,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏埃篓。R本人自食惡果不足惜处坪,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧同窘,春花似錦玄帕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至丧没,卻和暖如春鹰椒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背呕童。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工漆际, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人夺饲。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓奸汇,卻偏偏與公主長得像,于是被迫代替她去往敵國和親往声。 傳聞我的和親對象是個殘疾皇子擂找,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354