<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # Service Kubernetes [`Pod`](https://kubernetes.io/docs/user-guide/pods) 是有生命周期的,它們可以被創建,也可以被銷毀,然而一旦被銷毀生命就永遠結束。 通過 [`ReplicationController`](https://kubernetes.io/docs/user-guide/replication-controller) 能夠動態地創建和銷毀 `Pod`。 每個 `Pod` 都會獲取它自己的 IP 地址,即使這些 IP 地址不總是穩定可依賴的。 這會導致一個問題:在 Kubernetes 集群中,如果一組 `Pod`(稱為 backend)為其它 `Pod` (稱為 frontend)提供服務,那么那些 frontend 該如何發現,并連接到這組 `Pod` 中的哪些 backend 呢? 關于 `Service` Kubernetes `Service` 定義了這樣一種抽象:一個 `Pod` 的邏輯分組,一種可以訪問它們的策略 —— 通常稱為微服務。 這一組 `Pod` 能夠被 `Service` 訪問到,通常是通過 [`Label Selector`](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors)(查看下面了解,為什么可能需要沒有 selector 的 `Service`)實現的。 舉個例子,考慮一個圖片處理 backend,它運行了3個副本。這些副本是可互換的 —— frontend 不需要關心它們調用了哪個 backend 副本。 然而組成這一組 backend 程序的 `Pod` 實際上可能會發生變化,frontend 客戶端不應該也沒必要知道,而且也不需要跟蹤這一組 backend 的狀態。 `Service` 定義的抽象能夠解耦這種關聯。 對 Kubernetes 集群中的應用,Kubernetes 提供了簡單的 `Endpoints` API,只要 `Service` 中的一組 `Pod` 發生變更,應用程序就會被更新。 對非 Kubernetes 集群中的應用,Kubernetes 提供了基于 VIP 的網橋的方式訪問 `Service`,再由 `Service` 重定向到 backend `Pod`。 ## 定義 Service 一個 `Service` 在 Kubernetes 中是一個 REST 對象,和 `Pod` 類似。 像所有的 REST 對象一樣, `Service` 定義可以基于 POST 方式,請求 apiserver 創建新的實例。 例如,假定有一組 `Pod`,它們對外暴露了 9376 端口,同時還被打上 `"app=MyApp"` 標簽。 ```yaml kind: Service apiVersion: v1 metadata: name: my-service spec: selector: app: MyApp ports: - protocol: TCP port: 80 targetPort: 9376 ``` 上述配置將創建一個名稱為 “my-service” 的 `Service` 對象,它會將請求代理到使用 TCP 端口 9376,并且具有標簽 `"app=MyApp"` 的 `Pod` 上。 這個 `Service` 將被指派一個 IP 地址(通常稱為 “Cluster IP”),它會被服務的代理使用(見下面)。 該 `Service` 的 selector 將會持續評估,處理結果將被 POST 到一個名稱為 “my-service” 的 `Endpoints` 對象上。 需要注意的是, `Service` 能夠將一個接收端口映射到任意的 `targetPort`。 默認情況下,`targetPort` 將被設置為與 `port` 字段相同的值。 可能更有趣的是,`targetPort` 可以是一個字符串,引用了 backend `Pod` 的一個端口的名稱。 但是,實際指派給該端口名稱的端口號,在每個 backend `Pod` 中可能并不相同。 對于部署和設計 `Service` ,這種方式會提供更大的靈活性。 例如,可以在 backend 軟件下一個版本中,修改 Pod 暴露的端口,并不會中斷客戶端的調用。 Kubernetes `Service` 能夠支持 `TCP` 和 `UDP` 協議,默認 `TCP` 協議。 ### 沒有 selector 的 Service Service 抽象了該如何訪問 Kubernetes `Pod`,但也能夠抽象其它類型的 backend,例如: * 希望在生產環境中使用外部的數據庫集群,但測試環境使用自己的數據庫。 * 希望服務指向另一個 [`Namespace`](https://kubernetes.io/docs/user-guide/namespaces) 中或其它集群中的服務。 * 正在將工作負載轉移到 Kubernetes 集群,和運行在 Kubernetes 集群之外的 backend。 在任何這些場景中,都能夠定義沒有 selector 的 `Service` : ```yaml kind: Service apiVersion: v1 metadata: name: my-service spec: ports: - protocol: TCP port: 80 targetPort: 9376 ``` 由于這個 `Service` 沒有 selector,就不會創建相關的 `Endpoints` 對象。可以手動將 `Service` 映射到指定的 `Endpoints`: ```yaml kind: Endpoints apiVersion: v1 metadata: name: my-service subsets: - addresses: - ip: 1.2.3.4 ports: - port: 9376 ``` 注意:Endpoint IP 地址不能是 loopback(127.0.0.0/8)、 link-local(169.254.0.0/16)、或者 link-local 多播(224.0.0.0/24)。 訪問沒有 selector 的 `Service`,與有 selector 的 `Service` 的原理相同。請求將被路由到用戶定義的 Endpoint(該示例中為 `1.2.3.4:9376`)。 ExternalName `Service` 是 `Service` 的特例,它沒有 selector,也沒有定義任何的端口和 Endpoint。 相反地,對于運行在集群外部的服務,它通過返回該外部服務的別名這種方式來提供服務。 ```yaml kind: Service apiVersion: v1 metadata: name: my-service namespace: prod spec: type: ExternalName externalName: my.database.example.com ``` 當查詢主機 `my-service.prod.svc.CLUSTER`時,集群的 DNS 服務將返回一個值為 `my.database.example.com` 的 `CNAME` 記錄。 訪問這個服務的工作方式與其它的相同,唯一不同的是重定向發生在 DNS 層,而且不會進行代理或轉發。 如果后續決定要將數據庫遷移到 Kubernetes 集群中,可以啟動對應的 Pod,增加合適的 Selector 或 Endpoint,修改 `Service` 的 `type`。 ## VIP 和 Service 代理 在 Kubernetes 集群中,每個 Node 運行一個 `kube-proxy` 進程。`kube-proxy` 負責為 `Service` 實現了一種 VIP(虛擬 IP)的形式,而不是 `ExternalName` 的形式。 在 Kubernetes v1.0 版本,代理完全在 userspace。在 Kubernetes v1.1 版本,新增了 iptables 代理,但并不是默認的運行模式。 從 Kubernetes v1.2 起,默認就是 iptables 代理。 在Kubernetes v1.8.0-beta.0中,添加了ipvs代理。 在 Kubernetes v1.0 版本,`Service` 是 “4層”(TCP/UDP over IP)概念。 在 Kubernetes v1.1 版本,新增了 `Ingress` API(beta 版),用來表示 “7層”(HTTP)服務。 ### userspace 代理模式 這種模式,kube-proxy 會監視 Kubernetes master 對 `Service` 對象和 `Endpoints` 對象的添加和移除。 對每個 `Service`,它會在本地 Node 上打開一個端口(隨機選擇)。 任何連接到“代理端口”的請求,都會被代理到 `Service` 的backend `Pods` 中的某個上面(如 `Endpoints` 所報告的一樣)。 使用哪個 backend `Pod`,是基于 `Service` 的 `SessionAffinity` 來確定的。 最后,它安裝 iptables 規則,捕獲到達該 `Service` 的 `clusterIP`(是虛擬 IP)和 `Port` 的請求,并重定向到代理端口,代理端口再代理請求到 backend `Pod`。 網絡返回的結果是,任何到達 `Service` 的 IP:Port 的請求,都會被代理到一個合適的 backend,不需要客戶端知道關于 Kubernetes、`Service`、或 `Pod` 的任何信息。 默認的策略是,通過 round-robin 算法來選擇 backend `Pod`。 實現基于客戶端 IP 的會話親和性,可以通過設置 `service.spec.sessionAffinity` 的值為 `"ClientIP"` (默認值為 `"None"`)。 ![userspace代理模式下Service概覽圖](https://box.kancloud.cn/d78e52853d7688a6f83976e52bb16692_600x400.jpg) ### iptables 代理模式 這種模式,kube-proxy 會監視 Kubernetes master 對 `Service` 對象和 `Endpoints` 對象的添加和移除。 對每個 `Service`,它會安裝 iptables 規則,從而捕獲到達該 `Service` 的 `clusterIP`(虛擬 IP)和端口的請求,進而將請求重定向到 `Service` 的一組 backend 中的某個上面。 對于每個 `Endpoints` 對象,它也會安裝 iptables 規則,這個規則會選擇一個 backend `Pod`。 默認的策略是,隨機選擇一個 backend。 實現基于客戶端 IP 的會話親和性,可以將 `service.spec.sessionAffinity` 的值設置為 `"ClientIP"` (默認值為 `"None"`)。 和 userspace 代理類似,網絡返回的結果是,任何到達 `Service` 的 IP:Port 的請求,都會被代理到一個合適的 backend,不需要客戶端知道關于 Kubernetes、`Service`、或 `Pod` 的任何信息。 這應該比 userspace 代理更快、更可靠。然而,不像 userspace 代理,如果初始選擇的 `Pod` 沒有響應,iptables 代理不能自動地重試另一個 `Pod`,所以它需要依賴 [readiness probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#defining-readiness-probes)。 ![iptables代理模式下Service概覽圖](https://box.kancloud.cn/419caf278fcb874828cb9349a38d6ca0_600x400.jpg) ### ipvs 代理模式 這種模式,kube-proxy會監視Kubernetes `Service`對象和`Endpoints`,調用`netlink`接口以相應地創建ipvs規則并定期與Kubernetes `Service`對象和`Endpoints`對象同步ipvs規則,以確保ipvs狀態與期望一致。訪問服務時,流量將被重定向到其中一個后端Pod。 與iptables類似,ipvs基于netfilter 的 hook 功能,但使用哈希表作為底層數據結構并在內核空間中工作。這意味著ipvs可以更快地重定向流量,并且在同步代理規則時具有更好的性能。此外,ipvs為負載均衡算法提供了更多選項,例如: - `rr`:輪詢調度 - `lc`:最小連接數 - `dh`:目標哈希 - `sh`:源哈希 - `sed`:最短期望延遲 - `nq`:?不排隊調度 **注意:** ipvs模式假定在運行kube-proxy之前在節點上都已經安裝了IPVS內核模塊。當kube-proxy以ipvs代理模式啟動時,kube-proxy將驗證節點上是否安裝了IPVS模塊,如果未安裝,則kube-proxy將回退到iptables代理模式。 ![ipvs代理模式下Service概覽圖](https://box.kancloud.cn/2a25e7292211c94bda067b0d09ccc54b_2508x1630.png) ## 多端口 Service 很多 `Service` 需要暴露多個端口。對于這種情況,Kubernetes 支持在 `Service` 對象中定義多個端口。 當使用多個端口時,必須給出所有的端口的名稱,這樣 Endpoint 就不會產生歧義,例如: ```yaml kind: Service apiVersion: v1 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 ``` ## 選擇自己的 IP 地址 在 `Service` 創建的請求中,可以通過設置 `spec.clusterIP` 字段來指定自己的集群 IP 地址。 比如,希望替換一個已經存在的 DNS 條目,或者遺留系統已經配置了一個固定的 IP 且很難重新配置。 用戶選擇的 IP 地址必須合法,并且這個 IP 地址在 `service-cluster-ip-range` CIDR 范圍內,這對 API Server 來說是通過一個標識來指定的。 如果 IP 地址不合法,API Server 會返回 HTTP 狀態碼 422,表示值不合法。 ### 為何不使用 round-robin DNS? 一個不時出現的問題是,為什么我們都使用 VIP 的方式,而不使用標準的 round-robin DNS,有如下幾個原因: * 長久以來,DNS 庫都沒能認真對待 DNS TTL、緩存域名查詢結果 * 很多應用只查詢一次 DNS 并緩存了結果 * 就算應用和庫能夠正確查詢解析,每個客戶端反復重解析造成的負載也是非常難以管理的 我們盡力阻止用戶做那些對他們沒有好處的事情,如果很多人都來問這個問題,我們可能會選擇實現它。 ## 服務發現 Kubernetes 支持2種基本的服務發現模式 —— 環境變量和 DNS。 ### 環境變量 當 `Pod` 運行在 `Node` 上,kubelet 會為每個活躍的 `Service` 添加一組環境變量。 它同時支持 [Docker links 兼容](https://docs.docker.com/userguide/dockerlinks/) 變量(查看 makeLinkVariables)、簡單的 `{SVCNAME}_SERVICE_HOST` 和 `{SVCNAME}_SERVICE_PORT` 變量,這里 `Service` 的名稱需大寫,橫線被轉換成下劃線。 舉個例子,一個名稱為 `"redis-master"` 的 Service 暴露了 TCP 端口 6379,同時給它分配了 Cluster IP 地址 10.0.0.11,這個 Service 生成了如下環境變量: ```bash 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` 想要訪問的任何 `Service` 必須在 `Pod` 自己之前被創建,否則這些環境變量就不會被賦值。DNS 并沒有這個限制。 ### DNS 一個可選(盡管強烈推薦)[集群插件](http://releases.k8s.io/master/cluster/addons/README.md) 是 DNS 服務器。 DNS 服務器監視著創建新 `Service` 的 Kubernetes API,從而為每一個 `Service` 創建一組 DNS 記錄。 如果整個集群的 DNS 一直被啟用,那么所有的 `Pod` 應該能夠自動對 `Service` 進行名稱解析。 例如,有一個名稱為 `"my-service"` 的 `Service`,它在 Kubernetes 集群中名為 `"my-ns"` 的 `Namespace` 中,為 `"my-service.my-ns"` 創建了一條 DNS 記錄。 在名稱為 `"my-ns"` 的 `Namespace` 中的 `Pod` 應該能夠簡單地通過名稱查詢找到 `"my-service"`。 在另一個 `Namespace` 中的 `Pod` 必須限定名稱為 `"my-service.my-ns"`。 這些名稱查詢的結果是 Cluster IP。 Kubernetes 也支持對端口名稱的 DNS SRV(Service)記錄。 如果名稱為 `"my-service.my-ns"` 的 `Service` 有一個名為 `"http"` 的 `TCP` 端口,可以對 `"_http._tcp.my-service.my-ns"` 執行 DNS SRV 查詢,得到 `"http"` 的端口號。 Kubernetes DNS 服務器是唯一的一種能夠訪問 `ExternalName` 類型的 Service 的方式。 更多信息可以查看 [DNS Pod 和 Service](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/)。 ## Headless Service 有時不需要或不想要負載均衡,以及單獨的 Service IP。 遇到這種情況,可以通過指定 Cluster IP(`spec.clusterIP`)的值為 `"None"` 來創建 `Headless` Service。 這個選項允許開發人員自由尋找他們自己的方式,從而降低與 Kubernetes 系統的耦合性。 應用仍然可以使用一種自注冊的模式和適配器,對其它需要發現機制的系統能夠很容易地基于這個 API 來構建。 對這類 `Service` 并不會分配 Cluster IP,kube-proxy 不會處理它們,而且平臺也不會為它們進行負載均衡和路由。 DNS 如何實現自動配置,依賴于 `Service` 是否定義了 selector。 ### 配置 Selector 對定義了 selector 的 Headless Service,Endpoint 控制器在 API 中創建了 `Endpoints` 記錄,并且修改 DNS 配置返回 A 記錄(地址),通過這個地址直接到達 `Service` 的后端 `Pod` 上。 ### 不配置 Selector 對沒有定義 selector 的 Headless Service,Endpoint 控制器不會創建 `Endpoints` 記錄。 然而 DNS 系統會查找和配置,無論是: * `ExternalName` 類型 Service 的 CNAME 記錄 * 記錄:與 Service 共享一個名稱的任何 `Endpoints`,以及所有其它類型 ## 發布服務 —— 服務類型 對一些應用(如 Frontend)的某些部分,可能希望通過外部(Kubernetes 集群外部)IP 地址暴露 Service。 Kubernetes `ServiceTypes` 允許指定一個需要的類型的 Service,默認是 `ClusterIP` 類型。 `Type` 的取值以及行為如下: * `ClusterIP`:通過集群的內部 IP 暴露服務,選擇該值,服務只能夠在集群內部可以訪問,這也是默認的 `ServiceType`。 * `NodePort`:通過每個 Node 上的 IP 和靜態端口(`NodePort`)暴露服務。`NodePort` 服務會路由到 `ClusterIP` 服務,這個 `ClusterIP` 服務會自動創建。通過請求 `<NodeIP>:<NodePort>`,可以從集群的外部訪問一個 `NodePort` 服務。 * `LoadBalancer`:使用云提供商的負載均衡器,可以向外部暴露服務。外部的負載均衡器可以路由到 `NodePort` 服務和 `ClusterIP` 服務。 * `ExternalName`:通過返回 `CNAME` 和它的值,可以將服務映射到 `externalName` 字段的內容(例如, `foo.bar.example.com`)。 沒有任何類型代理被創建,這只有 Kubernetes 1.7 或更高版本的 `kube-dns` 才支持。 ### NodePort 類型 如果設置 `type` 的值為 `"NodePort"`,Kubernetes master 將從給定的配置范圍內(默認:30000-32767)分配端口,每個 Node 將從該端口(每個 Node 上的同一端口)代理到 `Service`。該端口將通過 `Service` 的 `spec.ports[*].nodePort` 字段被指定。 如果需要指定的端口號,可以配置 `nodePort` 的值,系統將分配這個端口,否則調用 API 將會失敗(比如,需要關心端口沖突的可能性)。 這可以讓開發人員自由地安裝他們自己的負載均衡器,并配置 Kubernetes 不能完全支持的環境參數,或者直接暴露一個或多個 Node 的 IP 地址。 需要注意的是,Service 將能夠通過 `<NodeIP>:spec.ports[*].nodePort` 和 `spec.clusterIp:spec.ports[*].port` 而對外可見。 ### LoadBalancer 類型 使用支持外部負載均衡器的云提供商的服務,設置 `type` 的值為 `"LoadBalancer"`,將為 `Service` 提供負載均衡器。 負載均衡器是異步創建的,關于被提供的負載均衡器的信息將會通過 `Service` 的 `status.loadBalancer` 字段被發布出去。 ```yaml kind: Service apiVersion: v1 metadata: name: my-service spec: selector: app: MyApp ports: - protocol: TCP port: 80 targetPort: 9376 nodePort: 30061 clusterIP: 10.0.171.239 loadBalancerIP: 78.11.24.19 type: LoadBalancer status: loadBalancer: ingress: - ip: 146.148.47.155 ``` 來自外部負載均衡器的流量將直接打到 backend `Pod` 上,不過實際它們是如何工作的,這要依賴于云提供商。 在這些情況下,將根據用戶設置的 `loadBalancerIP` 來創建負載均衡器。 某些云提供商允許設置 `loadBalancerIP`。如果沒有設置 `loadBalancerIP`,將會給負載均衡器指派一個臨時 IP。 如果設置了 `loadBalancerIP`,但云提供商并不支持這種特性,那么設置的 `loadBalancerIP` 值將會被忽略掉。 ### AWS 內部負載均衡器 在混合云環境中,有時從虛擬私有云(VPC)環境中的服務路由流量是非常有必要的。 可以通過在 `Service` 中增加 `annotation` 來實現,如下所示: ```yaml [...] metadata: name: my-service annotations: service.beta.kubernetes.io/aws-load-balancer-internal: 0.0.0.0/0 [...] ``` 在水平分割的 DNS 環境中,需要兩個 `Service` 來將外部和內部的流量路由到 Endpoint 上。 ### AWS SSL 支持 對運行在 AWS 上部分支持 SSL 的集群,從 1.3 版本開始,可以為 `LoadBalancer` 類型的 `Service` 增加兩個 annotation: ``` metadata: name: my-service annotations: service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012 ``` 第一個 annotation 指定了使用的證書。它可以是第三方發行商發行的證書,這個證書或者被上傳到 IAM,或者由 AWS 的證書管理器創建。 ```yaml metadata: name: my-service annotations: service.beta.kubernetes.io/aws-load-balancer-backend-protocol: (https|http|ssl|tcp) ``` 第二個 annotation 指定了 `Pod` 使用的協議。 對于 HTTPS 和 SSL,ELB 將期望該 `Pod` 基于加密的連接來認證自身。 HTTP 和 HTTPS 將選擇7層代理:ELB 將中斷與用戶的連接,當轉發請求時,會解析 Header 信息并添加上用戶的 IP 地址(`Pod` 將只能在連接的另一端看到該 IP 地址)。 TCP 和 SSL 將選擇4層代理:ELB 將轉發流量,并不修改 Header 信息。 ### 外部 IP 如果外部的 IP 路由到集群中一個或多個 Node 上,Kubernetes `Service` 會被暴露給這些 `externalIPs`。 通過外部 IP(作為目的 IP 地址)進入到集群,打到 `Service` 的端口上的流量,將會被路由到 `Service` 的 Endpoint 上。 `externalIPs` 不會被 Kubernetes 管理,它屬于集群管理員的職責范疇。 根據 `Service` 的規定,`externalIPs` 可以同任意的 `ServiceType` 來一起指定。 在下面的例子中,`my-service` 可以在 80.11.12.10:80(外部 IP:端口)上被客戶端訪問。 ```yaml kind: Service apiVersion: v1 metadata: name: my-service spec: selector: app: MyApp ports: - name: http protocol: TCP port: 80 targetPort: 9376 externalIPs: - 80.11.12.10 ``` ## 不足之處 為 VIP 使用 userspace 代理,將只適合小型到中型規模的集群,不能夠擴展到上千 `Service` 的大型集群。 查看 [最初設計方案](http://issue.k8s.io/1107) 獲取更多細節。 使用 userspace 代理,隱藏了訪問 `Service` 的數據包的源 IP 地址。 這使得一些類型的防火墻無法起作用。 iptables 代理不會隱藏 Kubernetes 集群內部的 IP 地址,但卻要求客戶端請求必須通過一個負載均衡器或 Node 端口。 `Type` 字段支持嵌套功能 —— 每一層需要添加到上一層里面。 不會嚴格要求所有云提供商(例如,GCE 就沒必要為了使一個 `LoadBalancer` 能工作而分配一個 `NodePort`,但是 AWS 需要 ),但當前 API 是強制要求的。 ## 未來工作 未來我們能預見到,代理策略可能會變得比簡單的 round-robin 均衡策略有更多細微的差別,比如 master 選舉或分片。 我們也能想到,某些 `Service` 將具有 “真正” 的負載均衡器,這種情況下 VIP 將簡化數據包的傳輸。 我們打算為 L7(HTTP)`Service` 改進我們對它的支持。 我們打算為 `Service` 實現更加靈活的請求進入模式,這些 `Service` 包含當前 `ClusterIP`、`NodePort` 和 `LoadBalancer` 模式,或者更多。 ## VIP 的那些駭人聽聞的細節 對很多想使用 `Service` 的人來說,前面的信息應該足夠了。 然而,有很多內部原理性的內容,還是值去理解的。 ### 避免沖突 Kubernetes 最主要的哲學之一,是用戶不應該暴露那些能夠導致他們操作失敗、但又不是他們的過錯的場景。 這種場景下,讓我們來看一下網絡端口 —— 用戶不應該必須選擇一個端口號,而且該端口還有可能與其他用戶的沖突。 這就是說,在彼此隔離狀態下仍然會出現失敗。 為了使用戶能夠為他們的 `Service` 選擇一個端口號,我們必須確保不能有2個 `Service` 發生沖突。 我們可以通過為每個 `Service` 分配它們自己的 IP 地址來實現。 為了保證每個 `Service` 被分配到一個唯一的 IP,需要一個內部的分配器能夠原子地更新 etcd 中的一個全局分配映射表,這個更新操作要先于創建每一個 `Service`。 為了使 `Service` 能夠獲取到 IP,這個映射表對象必須在注冊中心存在,否則創建 `Service` 將會失敗,指示一個 IP 不能被分配。 一個后臺 Controller 的職責是創建映射表(從 Kubernetes 的舊版本遷移過來,舊版本中是通過在內存中加鎖的方式實現),并檢查由于管理員干預和清除任意 IP 造成的不合理分配,這些 IP 被分配了但當前沒有 `Service` 使用它們。 ### IP 和 VIP 不像 `Pod` 的 IP 地址,它實際路由到一個固定的目的地,`Service` 的 IP 實際上不能通過單個主機來進行應答。 相反,我們使用 `iptables`(Linux 中的數據包處理邏輯)來定義一個虛擬IP地址(VIP),它可以根據需要透明地進行重定向。 當客戶端連接到 VIP 時,它們的流量會自動地傳輸到一個合適的 Endpoint。 環境變量和 DNS,實際上會根據 `Service` 的 VIP 和端口來進行填充。 #### Userspace 作為一個例子,考慮前面提到的圖片處理應用程序。 當創建 backend `Service` 時,Kubernetes master 會給它指派一個虛擬 IP 地址,比如 10.0.0.1。 假設 `Service` 的端口是 1234,該 `Service` 會被集群中所有的 `kube-proxy` 實例觀察到。 當代理看到一個新的 `Service`, 它會打開一個新的端口,建立一個從該 VIP 重定向到新端口的 iptables,并開始接收請求連接。 當一個客戶端連接到一個 VIP,iptables 規則開始起作用,它會重定向該數據包到 `Service代理` 的端口。 `Service代理` 選擇一個 backend,并將客戶端的流量代理到 backend 上。 這意味著 `Service` 的所有者能夠選擇任何他們想使用的端口,而不存在沖突的風險。 客戶端可以簡單地連接到一個 IP 和端口,而不需要知道實際訪問了哪些 `Pod`。 #### Iptables 再次考慮前面提到的圖片處理應用程序。 當創建 backend `Service` 時,Kubernetes master 會給它指派一個虛擬 IP 地址,比如 10.0.0.1。 假設 `Service` 的端口是 1234,該 `Service` 會被集群中所有的 `kube-proxy` 實例觀察到。 當代理看到一個新的 `Service`, 它會安裝一系列的 iptables 規則,從 VIP 重定向到 per-`Service` 規則。 該 per-`Service` 規則連接到 per-`Endpoint` 規則,該 per-`Endpoint` 規則會重定向(目標 NAT)到 backend。 當一個客戶端連接到一個 VIP,iptables 規則開始起作用。一個 backend 會被選擇(或者根據會話親和性,或者隨機),數據包被重定向到這個 backend。 不像 userspace 代理,數據包從來不拷貝到用戶空間,kube-proxy 不是必須為該 VIP 工作而運行,并且客戶端 IP 是不可更改的。 當流量打到 Node 的端口上,或通過負載均衡器,會執行相同的基本流程,但是在那些案例中客戶端 IP 是可以更改的。 ## API 對象 在 Kubernetes REST API 中,Service 是 top-level 資源。 ## 更多信息 - [使用 Service 連接 Frontend 到 Backend](https://kubernetes.io/docs/tutorials/connecting-apps/connecting-frontend-backend/)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看