官方地址:
https://kubernetes.io/zh/docs/concepts/services-networking/service/
服務
將運行在一組 Pods 上的應用程序公開為網絡服務的抽象方法。
使用 Kubernetes,你無需修改應用程序即可使用不熟悉的服務發現機制。 Kubernetes 為 Pods 提供自己的 IP 地址,並為一組 Pod 提供相同的 DNS 名, 並且可以在它們之間進行負載均衡。
動機
創建和銷毀 Kubernetes Pod 以匹配集群狀態。 Pod 是非永久性資源。 如果你使用 Deployment 來運行你的應用程序,則它可以動態創建和銷毀 Pod。
每個 Pod 都有自己的 IP 地址,但是在 Deployment 中,在同一時刻運行的 Pod 集合可能與稍后運行該應用程序的 Pod 集合不同。
這導致了一個問題: 如果一組 Pod(稱為“后端”)為集群內的其他 Pod(稱為“前端”)提供功能, 那么前端如何找出並跟蹤要連接的 IP 地址,以便前端可以使用提供工作負載的后端部分?
進入 Services。
Service 資源
Kubernetes Service 定義了這樣一種抽象:邏輯上的一組 Pod,一種可以訪問它們的策略 —— 通常稱為微服務。 Service 所針對的 Pods 集合通常是通過選擇算符來確定的。 要了解定義服務端點的其他方法,請參閱不帶選擇算符的服務。
舉個例子,考慮一個圖片處理后端,它運行了 3 個副本。這些副本是可互換的 —— 前端不需要關心它們調用了哪個后端副本。 然而組成這一組后端程序的 Pod 實際上可能會發生變化, 前端客戶端不應該也沒必要知道,而且也不需要跟蹤這一組后端的狀態。
Service 定義的抽象能夠解耦這種關聯。
雲原生服務發現
如果你想要在應用程序中使用 Kubernetes API 進行服務發現,則可以查詢 API 服務器 的 Endpoints 資源,只要服務中的 Pod 集合發生更改,Endpoints 就會被更新。
對於非本機應用程序,Kubernetes 提供了在應用程序和后端 Pod 之間放置網絡端口或負載均衡器的方法。
定義 Service
Service 在 Kubernetes 中是一個 REST 對象,和 Pod 類似。 像所有的 REST 對象一樣,Service 定義可以基於 POST
方式,請求 API server 創建新的實例。 Service 對象的名稱必須是合法的 RFC 1035 標簽名稱.。
例如,假定有一組 Pod,它們對外暴露了 9376 端口,同時還被打上 app=MyApp
標簽:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
上述配置創建一個名稱為 "my-service" 的 Service 對象,它會將請求代理到使用 TCP 端口 9376,並且具有標簽 "app=MyApp"
的 Pod 上。
Kubernetes 為該服務分配一個 IP 地址(有時稱為 "集群IP"),該 IP 地址由服務代理使用。 (請參見下面的 VIP 和 Service 代理).
服務選擇算符的控制器不斷掃描與其選擇器匹配的 Pod,然后將所有更新發布到也稱為 “my-service” 的 Endpoint 對象。
說明: 需要注意的是,Service 能夠將一個接收 port
映射到任意的 targetPort
。 默認情況下,targetPort
將被設置為與 port
字段相同的值。
Pod 中的端口定義是有名字的,你可以在服務的 targetPort
屬性中引用這些名稱。 即使服務中使用單個配置的名稱混合使用 Pod,並且通過不同的端口號提供相同的網絡協議,此功能也可以使用。 這為部署和發展服務提供了很大的靈活性。 例如,你可以更改 Pods 在新版本的后端軟件中公開的端口號,而不會破壞客戶端。
服務的默認協議是 TCP;你還可以使用任何其他受支持的協議。
由於許多服務需要公開多個端口,因此 Kubernetes 在服務對象上支持多個端口定義。 每個端口定義可以具有相同的 protocol
,也可以具有不同的協議。
沒有選擇算符的 Service
服務最常見的是抽象化對 Kubernetes Pod 的訪問,但是它們也可以抽象化其他種類的后端。 實例:
- 希望在生產環境中使用外部的數據庫集群,但測試環境使用自己的數據庫。
- 希望服務指向另一個 名字空間(Namespace) 中或其它集群中的服務。
- 你正在將工作負載遷移到 Kubernetes。 在評估該方法時,你僅在 Kubernetes 中運行一部分后端。
在任何這些場景中,都能夠定義沒有選擇算符的 Service。 實例:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
由於此服務沒有選擇算符,因此不會自動創建相應的 Endpoint 對象。 你可以通過手動添加 Endpoint 對象,將服務手動映射到運行該服務的網絡地址和端口:
apiVersion: v1
kind: Endpoints
metadata:
name: my-service
subsets:
- addresses:
- ip: 192.0.2.42
ports:
- port: 9376
Endpoints 對象的名稱必須是合法的 DNS 子域名。
說明:
端點 IPs 必須不可以 是:本地回路(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 服務的集群 IP,因為 kube-proxy 不支持將虛擬 IP 作為目標。
訪問沒有選擇算符的 Service,與有選擇算符的 Service 的原理相同。 請求將被路由到用戶定義的 Endpoint,YAML 中為:192.0.2.42:9376
(TCP)。
ExternalName Service 是 Service 的特例,它沒有選擇算符,但是使用 DNS 名稱。 有關更多信息,請參閱本文檔后面的ExternalName。
超出容量的 Endpoints
如果某個 Endpoints 資源中包含的端點個數超過 1000,則 Kubernetes v1.22 版本 (及更新版本)的集群會將為該 Endpoints 添加注解 endpoints.kubernetes.io/over-capacity: truncated
。 這一注解表明所影響到的 Endpoints 對象已經超出容量,此外 Endpoints 控制器還會將 Endpoints 對象數量截斷到 1000。
EndpointSlice
FEATURE STATE: Kubernetes v1.21 [stable]
Endpoint 切片是一種 API 資源,可以為 Endpoint 提供更可擴展的替代方案。 盡管從概念上講與 Endpoint 非常相似,但 Endpoint 切片允許跨多個資源分布網絡端點。 默認情況下,一旦到達100個 Endpoint,該 Endpoint 切片將被視為“已滿”, 屆時將創建其他 Endpoint 切片來存儲任何其他 Endpoint。
Endpoint 切片提供了附加的屬性和功能,這些屬性和功能在 EndpointSlices 中有詳細描述。
應用協議
FEATURE STATE: Kubernetes v1.20 [stable]
appProtocol
字段提供了一種為每個 Service 端口指定應用協議的方式。 此字段的取值會被映射到對應的 Endpoints 和 EndpointSlices 對象。
該字段遵循標准的 Kubernetes 標簽語法。 其值可以是 IANA 標准服務名稱 或以域名為前綴的名稱,如 mycompany.com/my-custom-protocol
。
虛擬 IP 和 Service 代理
在 Kubernetes 集群中,每個 Node 運行一個 kube-proxy
進程。 kube-proxy
負責為 Service 實現了一種 VIP(虛擬 IP)的形式,而不是 ExternalName
的形式。
為什么不使用 DNS 輪詢?
時不時會有人問到為什么 Kubernetes 依賴代理將入站流量轉發到后端。那其他方法呢? 例如,是否可以配置具有多個 A 值(或 IPv6 為 AAAA)的 DNS 記錄,並依靠輪詢名稱解析?
使用服務代理有以下幾個原因:
- DNS 實現的歷史由來已久,它不遵守記錄 TTL,並且在名稱查找結果到期后對其進行緩存。
- 有些應用程序僅執行一次 DNS 查找,並無限期地緩存結果。
- 即使應用和庫進行了適當的重新解析,DNS 記錄上的 TTL 值低或為零也可能會給 DNS 帶來高負載,從而使管理變得困難。
userspace 代理模式
這種模式,kube-proxy 會監視 Kubernetes 控制平面對 Service 對象和 Endpoints 對象的添加和移除操作。 對每個 Service,它會在本地 Node 上打開一個端口(隨機選擇)。 任何連接到“代理端口”的請求,都會被代理到 Service 的后端 Pods
中的某個上面(如 Endpoints
所報告的一樣)。 使用哪個后端 Pod,是 kube-proxy 基於 SessionAffinity
來確定的。
最后,它配置 iptables 規則,捕獲到達該 Service 的 clusterIP
(是虛擬 IP) 和 Port
的請求,並重定向到代理端口,代理端口再代理請求到后端Pod。
默認情況下,用戶空間模式下的 kube-proxy 通過輪轉算法選擇后端。
iptables 代理模式
這種模式,kube-proxy
會監視 Kubernetes 控制節點對 Service 對象和 Endpoints 對象的添加和移除。 對每個 Service,它會配置 iptables 規則,從而捕獲到達該 Service 的 clusterIP
和端口的請求,進而將請求重定向到 Service 的一組后端中的某個 Pod 上面。 對於每個 Endpoints 對象,它也會配置 iptables 規則,這個規則會選擇一個后端組合。
默認的策略是,kube-proxy 在 iptables 模式下隨機選擇一個后端。
使用 iptables 處理流量具有較低的系統開銷,因為流量由 Linux netfilter 處理, 而無需在用戶空間和內核空間之間切換。 這種方法也可能更可靠。
如果 kube-proxy 在 iptables 模式下運行,並且所選的第一個 Pod 沒有響應, 則連接失敗。 這與用戶空間模式不同:在這種情況下,kube-proxy 將檢測到與第一個 Pod 的連接已失敗, 並會自動使用其他后端 Pod 重試。
你可以使用 Pod 就緒探測器 驗證后端 Pod 可以正常工作,以便 iptables 模式下的 kube-proxy 僅看到測試正常的后端。 這樣做意味着你避免將流量通過 kube-proxy 發送到已知已失敗的 Pod。
IPVS 代理模式
FEATURE STATE: Kubernetes v1.11 [stable]
在 ipvs
模式下,kube-proxy 監視 Kubernetes 服務和端點,調用 netlink
接口相應地創建 IPVS 規則, 並定期將 IPVS 規則與 Kubernetes 服務和端點同步。 該控制循環可確保IPVS 狀態與所需狀態匹配。訪問服務時,IPVS 將流量定向到后端Pod之一。
IPVS代理模式基於類似於 iptables 模式的 netfilter 掛鈎函數, 但是使用哈希表作為基礎數據結構,並且在內核空間中工作。 這意味着,與 iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通信的延遲要短,並且在同步代理規則時具有更好的性能。 與其他代理模式相比,IPVS 模式還支持更高的網絡流量吞吐量。
IPVS 提供了更多選項來平衡后端 Pod 的流量。 這些是:
rr
:輪替(Round-Robin)lc
:最少鏈接(Least Connection),即打開鏈接數量最少者優先dh
:目標地址哈希(Destination Hashing)sh
:源地址哈希(Source Hashing)sed
:最短預期延遲(Shortest Expected Delay)nq
:從不排隊(Never Queue)
說明:
要在 IPVS 模式下運行 kube-proxy,必須在啟動 kube-proxy 之前使 IPVS 在節點上可用。
當 kube-proxy 以 IPVS 代理模式啟動時,它將驗證 IPVS 內核模塊是否可用。 如果未檢測到 IPVS 內核模塊,則 kube-proxy 將退回到以 iptables 代理模式運行。
在這些代理模型中,綁定到服務 IP 的流量: 在客戶端不了解 Kubernetes 或服務或 Pod 的任何信息的情況下,將 Port 代理到適當的后端。
如果要確保每次都將來自特定客戶端的連接傳遞到同一 Pod, 則可以通過將 service.spec.sessionAffinity
設置為 "ClientIP" (默認值是 "None"),來基於客戶端的 IP 地址選擇會話關聯。 你還可以通過適當設置 service.spec.sessionAffinityConfig.clientIP.timeoutSeconds
來設置最大會話停留時間。 (默認值為 10800 秒,即 3 小時)。
多端口 Service
對於某些服務,你需要公開多個端口。 Kubernetes 允許你在 Service 對象上配置多個端口定義。 為服務使用多個端口時,必須提供所有端口名稱,以使它們無歧義。 例如:
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
說明:
與一般的Kubernetes名稱一樣,端口名稱只能包含小寫字母數字字符 和 -
。 端口名稱還必須以字母數字字符開頭和結尾。
例如,名稱 123-abc
和 web
有效,但是 123_abc
和 -web
無效。
選擇自己的 IP 地址
在 Service
創建的請求中,可以通過設置 spec.clusterIP
字段來指定自己的集群 IP 地址。 比如,希望替換一個已經已存在的 DNS 條目,或者遺留系統已經配置了一個固定的 IP 且很難重新配置。
用戶選擇的 IP 地址必須合法,並且這個 IP 地址在 service-cluster-ip-range
CIDR 范圍內, 這對 API 服務器來說是通過一個標識來指定的。 如果 IP 地址不合法,API 服務器會返回 HTTP 狀態碼 422,表示值不合法。
流量策略
外部流量策略
你可以通過設置 spec.externalTrafficPolicy
字段來控制來自於外部的流量是如何路由的。 可選值有 Cluster
和 Local
。字段設為 Cluster
會將外部流量路由到所有就緒的端點, 設為 Local
會只路由到當前節點上就緒的端點。 如果流量策略設置為 Local
,而且當前節點上沒有就緒的端點,kube-proxy 不會轉發請求相關服務的任何流量。
說明:
FEATURE STATE: Kubernetes v1.22 [alpha]
如果你啟用了 kube-proxy 的 ProxyTerminatingEndpoints
特性門控, kube-proxy 會檢查節點是否有本地的端點,以及是否所有的本地端點都被標記為終止中。
如果本地有端點,而且所有端點處於終止中的狀態,那么 kube-proxy 會忽略任何設為 Local
的外部流量策略。 在所有本地端點處於終止中的狀態的同時,kube-proxy 將請求指定服務的流量轉發到位於其它節點的 狀態健康的端點,如同外部流量策略設為 Cluster
。
針對處於正被終止狀態的端點這一轉發行為使得外部負載均衡器可以優雅地排出由 NodePort
服務支持的連接,就算是健康檢查節點端口開始失敗也是如此。 否則,當節點還在負載均衡器的節點池內,在 Pod 終止過程中的流量會被丟掉,這些流量可能會丟失。
內部流量策略
FEATURE STATE: Kubernetes v1.22 [beta]
你可以設置 spec.internalTrafficPolicy
字段來控制內部來源的流量是如何轉發的。可設置的值有 Cluster
和 Local
。 將字段設置為 Cluster
會將內部流量路由到所有就緒端點,設置為 Local
只會路由到當前節點上就緒的端點。 如果流量策略是 Local
,而且當前節點上沒有就緒的端點,那么 kube-proxy 會丟棄流量。
服務發現
Kubernetes 支持兩種基本的服務發現模式 —— 環境變量和 DNS。
環境變量
當 Pod 運行在 Node
上,kubelet 會為每個活躍的 Service 添加一組環境變量。 它同時支持 Docker links兼容 變量 (查看 makeLinkVariables)、 簡單的 {SVCNAME}_SERVICE_HOST
和 {SVCNAME}_SERVICE_PORT
變量。 這里 Service 的名稱需大寫,橫線被轉換成下划線。
舉個例子,一個名稱為 redis-master
的 Service 暴露了 TCP 端口 6379, 同時給它分配了 Cluster IP 地址 10.0.0.11,這個 Service 生成了如下環境變量:
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 時,並且你正在使用環境變量方法將端口和集群 IP 發布到客戶端 Pod 時,必須在客戶端 Pod 出現 之前 創建服務。 否則,這些客戶端 Pod 將不會設定其環境變量。
如果僅使用 DNS 查找服務的集群 IP,則無需擔心此設定問題。
DNS
你可以(幾乎總是應該)使用附加組件 為 Kubernetes 集群設置 DNS 服務。
支持集群的 DNS 服務器(例如 CoreDNS)監視 Kubernetes API 中的新服務,並為每個服務創建一組 DNS 記錄。 如果在整個集群中都啟用了 DNS,則所有 Pod 都應該能夠通過其 DNS 名稱自動解析服務。
例如,如果你在 Kubernetes 命名空間 my-ns
中有一個名為 my-service
的服務, 則控制平面和 DNS 服務共同為 my-service.my-ns
創建 DNS 記錄。 my-ns
命名空間中的 Pod 應該能夠通過按名檢索 my-service
來找到服務 (my-service.my-ns
也可以工作)。
其他命名空間中的 Pod 必須將名稱限定為 my-service.my-ns
。 這些名稱將解析為為服務分配的集群 IP。
Kubernetes 還支持命名端口的 DNS SRV(服務)記錄。 如果 my-service.my-ns
服務具有名為 http
的端口,且協議設置為 TCP, 則可以對 _http._tcp.my-service.my-ns
執行 DNS SRV 查詢查詢以發現該端口號, "http"
以及 IP 地址。
Kubernetes DNS 服務器是唯一的一種能夠訪問 ExternalName
類型的 Service 的方式。 更多關於 ExternalName
信息可以查看 DNS Pod 和 Service。
無頭服務(Headless Services)
有時不需要或不想要負載均衡,以及單獨的 Service IP。 遇到這種情況,可以通過指定 Cluster IP(spec.clusterIP
)的值為 "None"
來創建 Headless
Service。
你可以使用無頭 Service 與其他服務發現機制進行接口,而不必與 Kubernetes 的實現捆綁在一起。
對這無頭 Service 並不會分配 Cluster IP,kube-proxy 不會處理它們, 而且平台也不會為它們進行負載均衡和路由。 DNS 如何實現自動配置,依賴於 Service 是否定義了選擇算符。
帶選擇算符的服務
對定義了選擇算符的無頭服務,Endpoint 控制器在 API 中創建了 Endpoints 記錄, 並且修改 DNS 配置返回 A 記錄(IP 地址),通過這個地址直接到達 Service
的后端 Pod 上。
無選擇算符的服務
對沒有定義選擇算符的無頭服務,Endpoint 控制器不會創建 Endpoints
記錄。 然而 DNS 系統會查找和配置,無論是:
- 對於
ExternalName
類型的服務,查找其 CNAME 記錄 - 對所有其他類型的服務,查找與 Service 名稱相同的任何
Endpoints
的記錄
發布服務(服務類型)
對一些應用的某些部分(如前端),可能希望將其暴露給 Kubernetes 集群外部 的 IP 地址。
Kubernetes ServiceTypes
允許指定你所需要的 Service 類型,默認是 ClusterIP
。
Type
的取值以及行為如下:
-
ClusterIP
:通過集群的內部 IP 暴露服務,選擇該值時服務只能夠在集群內部訪問。 這也是默認的ServiceType
。 -
NodePort
:通過每個節點上的 IP 和靜態端口(NodePort
)暴露服務。NodePort
服務會路由到自動創建的ClusterIP
服務。 通過請求<節點 IP>:<節點端口>
,你可以從集群的外部訪問一個NodePort
服務。 -
LoadBalancer
:使用雲提供商的負載均衡器向外部暴露服務。 外部負載均衡器可以將流量路由到自動創建的NodePort
服務和ClusterIP
服務上。 -
ExternalName
:通過返回CNAME
和對應值,可以將服務映射到externalName
字段的內容(例如,foo.bar.example.com
)。 無需創建任何類型代理。說明: 你需要使用 kube-dns 1.7 及以上版本或者 CoreDNS 0.0.8 及以上版本才能使用
ExternalName
類型。
你也可以使用 Ingress 來暴露自己的服務。 Ingress 不是一種服務類型,但它充當集群的入口點。 它可以將路由規則整合到一個資源中,因為它可以在同一IP地址下公開多個服務。
NodePort 類型
如果你將 type
字段設置為 NodePort
,則 Kubernetes 控制平面將在 --service-node-port-range
標志指定的范圍內分配端口(默認值:30000-32767)。 每個節點將那個端口(每個節點上的相同端口號)代理到你的服務中。 你的服務在其 .spec.ports[*].nodePort
字段中要求分配的端口。
如果你想指定特定的 IP 代理端口,則可以設置 kube-proxy 中的 --nodeport-addresses
參數 或者將kube-proxy 配置文件 中的等效 nodePortAddresses
字段設置為特定的 IP 塊。 該標志采用逗號分隔的 IP 塊列表(例如,10.0.0.0/8
、192.0.2.0/25
)來指定 kube-proxy 應該認為是此節點本地的 IP 地址范圍。
例如,如果你使用 --nodeport-addresses=127.0.0.0/8
標志啟動 kube-proxy, 則 kube-proxy 僅選擇 NodePort Services 的本地回路接口。 --nodeport-addresses
的默認值是一個空列表。 這意味着 kube-proxy 應該考慮 NodePort 的所有可用網絡接口。 (這也與早期的 Kubernetes 版本兼容)。
如果需要特定的端口號,你可以在 nodePort
字段中指定一個值。 控制平面將為你分配該端口或報告 API 事務失敗。 這意味着你需要自己注意可能發生的端口沖突。 你還必須使用有效的端口號,該端口號在配置用於 NodePort 的范圍內。
使用 NodePort 可以讓你自由設置自己的負載均衡解決方案, 配置 Kubernetes 不完全支持的環境, 甚至直接暴露一個或多個節點的 IP。
需要注意的是,Service 能夠通過 <NodeIP>:spec.ports[*].nodePort
和 spec.clusterIp:spec.ports[*].port
而對外可見。 如果設置了 kube-proxy 的 --nodeport-addresses
參數或 kube-proxy 配置文件中的等效字段, <NodeIP>
將被過濾 NodeIP。
例如:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
selector:
app: MyApp
ports:
# 默認情況下,為了方便起見,`targetPort` 被設置為與 `port` 字段相同的值。
- port: 80
targetPort: 80
# 可選字段
# 默認情況下,為了方便起見,Kubernetes 控制平面會從某個范圍內分配一個端口號(默認:30000-32767)
nodePort: 30007
LoadBalancer 類型
在使用支持外部負載均衡器的雲提供商的服務時,設置 type
的值為 "LoadBalancer"
, 將為 Service 提供負載均衡器。 負載均衡器是異步創建的,關於被提供的負載均衡器的信息將會通過 Service 的 status.loadBalancer
字段發布出去。
實例:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
clusterIP: 10.0.171.239
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 192.0.2.127
來自外部負載均衡器的流量將直接重定向到后端 Pod 上,不過實際它們是如何工作的,這要依賴於雲提供商。
某些雲提供商允許設置 loadBalancerIP
。 在這些情況下,將根據用戶設置的 loadBalancerIP
來創建負載均衡器。 如果沒有設置 loadBalancerIP
字段,將會給負載均衡器指派一個臨時 IP。 如果設置了 loadBalancerIP
,但雲提供商並不支持這種特性,那么設置的 loadBalancerIP
值將會被忽略掉。
說明:
在 Azure 上,如果要使用用戶指定的公共類型 loadBalancerIP
,則 首先需要創建靜態類型的公共 IP 地址資源。 此公共 IP 地址資源應與集群中其他自動創建的資源位於同一資源組中。 例如,MC_myResourceGroup_myAKSCluster_eastus
。
將分配的 IP 地址設置為 loadBalancerIP。確保你已更新雲提供程序配置文件中的 securityGroupName。 有關對 CreatingLoadBalancerFailed
權限問題進行故障排除的信息, 請參閱 與 Azure Kubernetes 服務(AKS)負載平衡器一起使用靜態 IP 地址 或在 AKS 集群上使用高級聯網時出現 CreatingLoadBalancerFailed。
混合協議類型的負載均衡器
FEATURE STATE: Kubernetes v1.20 [alpha]
默認情況下,對於 LoadBalancer 類型的服務,當定義了多個端口時,所有 端口必須具有相同的協議,並且該協議必須是受雲提供商支持的協議。
如果為 kube-apiserver 啟用了 MixedProtocolLBService
特性門控, 則當定義了多個端口時,允許使用不同的協議。
說明: 可用於 LoadBalancer 類型服務的協議集仍然由雲提供商決定。
禁用負載均衡器節點端口分配
FEATURE STATE: Kubernetes v1.20 [alpha]
從 v1.20 版本開始, 你可以通過設置 spec.allocateLoadBalancerNodePorts
為 false
對類型為 LoadBalancer 的服務禁用節點端口分配。 這僅適用於直接將流量路由到 Pod 而不是使用節點端口的負載均衡器實現。 默認情況下,spec.allocateLoadBalancerNodePorts
為 true
, LoadBalancer 類型的服務繼續分配節點端口。 如果現有服務已被分配節點端口,將參數 spec.allocateLoadBalancerNodePorts
設置為 false
時,這些服務上已分配置的節點端口不會被自動釋放。 你必須顯式地在每個服務端口中刪除 nodePorts
項以釋放對應端口。 你必須啟用 ServiceLBNodePortControl
特性門控才能使用該字段。
設置負載均衡器實現的類別
FEATURE STATE: Kubernetes v1.22 [beta]
spec.loadBalancerClass
允許你不使用雲提供商的默認負載均衡器實現,轉而使用指定的負載均衡器實現。 這個特性從 v1.21 版本開始可以使用,你在 v1.21 版本中使用這個字段必須啟用 ServiceLoadBalancerClass
特性門控,這個特性門控從 v1.22 版本及以后默認打開。 默認情況下,.spec.loadBalancerClass
的取值是 nil
,如果集群使用 --cloud-provider
配置了雲提供商, LoadBalancer
類型服務會使用雲提供商的默認負載均衡器實現。 如果設置了 .spec.loadBalancerClass
,則假定存在某個與所指定的類相匹配的 負載均衡器實現在監視服務變化。 所有默認的負載均衡器實現(例如,由雲提供商所提供的)都會忽略設置了此字段 的服務。.spec.loadBalancerClass
只能設置到類型為 LoadBalancer
的 Service 之上,而且一旦設置之后不可變更。
.spec.loadBalancerClass
的值必須是一個標簽風格的標識符, 可以有選擇地帶有類似 "internal-vip
" 或 "example.com/internal-vip
" 這類 前綴。沒有前綴的名字是保留給最終用戶的。
內部負載均衡器
在混合環境中,有時有必要在同一(虛擬)網絡地址塊內路由來自服務的流量。
在水平分割 DNS 環境中,你需要兩個服務才能將內部和外部流量都路由到你的端點(Endpoints)。
如要設置內部負載均衡器,請根據你所使用的雲運營商,為服務添加以下注解之一。
[...]
metadata:
name: my-service
annotations:
cloud.google.com/load-balancer-type: "Internal"
[...]
AWS TLS 支持
為了對在 AWS 上運行的集群提供 TLS/SSL 部分支持,你可以向 LoadBalancer
服務添加三個注解:
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
第一個指定要使用的證書的 ARN。 它可以是已上載到 IAM 的第三方頒發者的證書, 也可以是在 AWS Certificate Manager 中創建的證書。
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: (https|http|ssl|tcp)
第二個注解指定 Pod 使用哪種協議。 對於 HTTPS 和 SSL,ELB 希望 Pod 使用證書 通過加密連接對自己進行身份驗證。
HTTP 和 HTTPS 選擇第7層代理:ELB 終止與用戶的連接,解析標頭,並在轉發請求時向 X-Forwarded-For
標頭注入用戶的 IP 地址(Pod 僅在連接的另一端看到 ELB 的 IP 地址)。
TCP 和 SSL 選擇第4層代理:ELB 轉發流量而不修改報頭。
在某些端口處於安全狀態而其他端口未加密的混合使用環境中,可以使用以下注解:
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443,8443"
在上例中,如果服務包含 80
、443
和 8443
三個端口, 那么 443
和 8443
將使用 SSL 證書, 而 80
端口將轉發 HTTP 數據包。
從 Kubernetes v1.9 起可以使用 預定義的 AWS SSL 策略 為你的服務使用 HTTPS 或 SSL 偵聽器。 要查看可以使用哪些策略,可以使用 aws
命令行工具:
aws elb describe-load-balancer-policies --query 'PolicyDescriptions[].PolicyName'
然后,你可以使用 "service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy
" 注解; 例如:
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy: "ELBSecurityPolicy-TLS-1-2-2017-01"
AWS 上的 PROXY 協議支持
為了支持在 AWS 上運行的集群,啟用 PROXY 協議。 你可以使用以下服務注解:
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*"
從 1.3.0 版開始,此注解的使用適用於 ELB 代理的所有端口,並且不能進行其他配置。
AWS 上的 ELB 訪問日志
有幾個注解可用於管理 AWS 上 ELB 服務的訪問日志。
注解 service.beta.kubernetes.io/aws-load-balancer-access-log-enabled
控制是否啟用訪問日志。
注解 service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval
控制發布訪問日志的時間間隔(以分鍾為單位)。你可以指定 5 分鍾或 60 分鍾的間隔。
注解 service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name
控制存儲負載均衡器訪問日志的 Amazon S3 存儲桶的名稱。
注解 service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix
指定為 Amazon S3 存儲桶創建的邏輯層次結構。
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-access-log-enabled: "true"
# 指定是否為負載均衡器啟用訪問日志
service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval: "60"
# 發布訪問日志的時間間隔。你可以將其設置為 5 分鍾或 60 分鍾。
service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name: "my-bucket"
# 用來存放訪問日志的 Amazon S3 Bucket 名稱
service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix: "my-bucket-prefix/prod"
# 你為 Amazon S3 Bucket 所創建的邏輯層次結構,例如 `my-bucket-prefix/prod`
AWS 上的連接排空
可以將注解 service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled
設置為 "true"
來管理 ELB 的連接排空。 注解 service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout
也可以用於設置最大時間(以秒為單位),以保持現有連接在注銷實例之前保持打開狀態。
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled: "true"
service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout: "60"
其他 ELB 注解
還有其他一些注解,用於管理經典彈性負載均衡器,如下所述。
metadata:
name: my-service
annotations:
# 按秒計的時間,表示負載均衡器關閉連接之前連接可以保持空閑
# (連接上無數據傳輸)的時間長度
service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "60"
# 指定該負載均衡器上是否啟用跨區的負載均衡能力
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
# 逗號分隔列表值,每一項都是一個鍵-值耦對,會作為額外的標簽記錄於 ELB 中
service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags: "environment=prod,owner=devops"
# 將某后端視為健康、可接收請求之前需要達到的連續成功健康檢查次數。
# 默認為 2,必須介於 2 和 10 之間
service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold: ""
# 將某后端視為不健康、不可接收請求之前需要達到的連續不成功健康檢查次數。
# 默認為 6,必須介於 2 和 10 之間
service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold: "3"
# 對每個實例進行健康檢查時,連續兩次檢查之間的大致間隔秒數
# 默認為 10,必須介於 5 和 300 之間
service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval: "20"
# 時長秒數,在此期間沒有響應意味着健康檢查失敗
# 此值必須小於 service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval
# 默認值為 5,必須介於 2 和 60 之間
service.beta.kubernetes.io/aws-load-balancer-healthcheck-timeout: "5"
# 由已有的安全組所構成的列表,可以配置到所創建的 ELB 之上。
# 與注解 service.beta.kubernetes.io/aws-load-balancer-extra-security-groups 不同,
# 這一設置會替代掉之前指定給該 ELB 的所有其他安全組,也會覆蓋掉為此
# ELB 所唯一創建的安全組。
# 此列表中的第一個安全組 ID 被用來作為決策源,以允許入站流量流入目標工作節點
# (包括服務流量和健康檢查)。
# 如果多個 ELB 配置了相同的安全組 ID,為工作節點安全組添加的允許規則行只有一個,
# 這意味着如果你刪除了這些 ELB 中的任何一個,都會導致該規則記錄被刪除,
# 以至於所有共享該安全組 ID 的其他 ELB 都無法訪問該節點。
# 此注解如果使用不當,會導致跨服務的不可用狀況。
service.beta.kubernetes.io/aws-load-balancer-security-groups: "sg-53fae93f"
# 額外的安全組列表,將被添加到所創建的 ELB 之上。
# 添加時,會保留為 ELB 所專門創建的安全組。
# 這樣會確保每個 ELB 都有一個唯一的安全組 ID 和與之對應的允許規則記錄,
# 允許請求(服務流量和健康檢查)發送到目標工作節點。
# 這里頂一個安全組可以被多個服務共享。
service.beta.kubernetes.io/aws-load-balancer-extra-security-groups: "sg-53fae93f,sg-42efd82e"
# 用逗號分隔的一個鍵-值偶對列表,用來為負載均衡器選擇目標節點
service.beta.kubernetes.io/aws-load-balancer-target-node-labels: "ingress-gw,gw-name=public-api"
AWS 上網絡負載均衡器支持
FEATURE STATE: Kubernetes v1.15 [beta]
要在 AWS 上使用網絡負載均衡器,可以使用注解 service.beta.kubernetes.io/aws-load-balancer-type
,將其取值設為 nlb
。
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
說明: NLB 僅適用於某些實例類。有關受支持的實例類型的列表, 請參見 AWS文檔 中關於所支持的實例類型的 Elastic Load Balancing 說明。
與經典彈性負載平衡器不同,網絡負載平衡器(NLB)將客戶端的 IP 地址轉發到該節點。 如果服務的 .spec.externalTrafficPolicy
設置為 Cluster
,則客戶端的IP地址不會傳達到最終的 Pod。
通過將 .spec.externalTrafficPolicy
設置為 Local
,客戶端IP地址將傳播到最終的 Pod, 但這可能導致流量分配不均。 沒有針對特定 LoadBalancer 服務的任何 Pod 的節點將無法通過自動分配的 .spec.healthCheckNodePort
進行 NLB 目標組的運行狀況檢查,並且不會收到任何流量。
為了獲得均衡流量,請使用 DaemonSet 或指定 Pod 反親和性 使其不在同一節點上。
你還可以將 NLB 服務與內部負載平衡器 注解一起使用。
為了使客戶端流量能夠到達 NLB 后面的實例,使用以下 IP 規則修改了節點安全組:
Rule | Protocol | Port(s) | IpRange(s) | IpRange Description |
---|---|---|---|---|
Health Check | TCP | NodePort(s) (.spec.healthCheckNodePort for .spec.externalTrafficPolicy = Local ) |
Subnet CIDR | kubernetes.io/rule/nlb/health=
|
Client Traffic | TCP | NodePort(s) | .spec.loadBalancerSourceRanges (defaults to 0.0.0.0/0 ) |
kubernetes.io/rule/nlb/client=
|
MTU Discovery | ICMP | 3,4 | .spec.loadBalancerSourceRanges (defaults to 0.0.0.0/0 ) |
kubernetes.io/rule/nlb/mtu=
|
為了限制哪些客戶端IP可以訪問網絡負載平衡器,請指定 loadBalancerSourceRanges
。
spec:
loadBalancerSourceRanges:
- "143.231.0.0/16"
說明: 如果未設置 .spec.loadBalancerSourceRanges
,則 Kubernetes 允許從 0.0.0.0/0
到節點安全組的流量。 如果節點具有公共 IP 地址,請注意,非 NLB 流量也可以到達那些修改后的安全組中的所有實例。
騰訊 Kubernetes 引擎(TKE)上的 CLB 注解
以下是在 TKE 上管理雲負載均衡器的注解。
metadata:
name: my-service
annotations:
# 綁定負載均衡器到指定的節點。
service.kubernetes.io/qcloud-loadbalancer-backends-label: key in (value1, value2)
# 為已有負載均衡器添加 ID。
service.kubernetes.io/tke-existed-lbid:lb-6swtxxxx
# 負載均衡器(LB)的自定義參數尚不支持修改 LB 類型。
service.kubernetes.io/service.extensiveParameters: ""
# 自定義負載均衡監聽器。
service.kubernetes.io/service.listenerParameters: ""
# 指定負載均衡類型。
# 可用參數: classic (Classic Cloud Load Balancer) 或 application (Application Cloud Load Balancer)
service.kubernetes.io/loadbalance-type: xxxxx
# 指定公用網絡帶寬計費方法。
# 可用參數: TRAFFIC_POSTPAID_BY_HOUR(bill-by-traffic) 和 BANDWIDTH_POSTPAID_BY_HOUR (bill-by-bandwidth).
service.kubernetes.io/qcloud-loadbalancer-internet-charge-type: xxxxxx
# 指定帶寬參數 (取值范圍: [1,2000] Mbps).
service.kubernetes.io/qcloud-loadbalancer-internet-max-bandwidth-out: "10"
# 當設置該注解時,負載平衡器將只注冊正在運行 Pod 的節點,
# 否則所有節點將會被注冊。
service.kubernetes.io/local-svc-only-bind-node-with-pod: true
ExternalName 類型
類型為 ExternalName 的服務將服務映射到 DNS 名稱,而不是典型的選擇器,例如 my-service
或者 cassandra
。 你可以使用 spec.externalName
參數指定這些服務。
例如,以下 Service 定義將 prod
名稱空間中的 my-service
服務映射到 my.database.example.com
:
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
說明: ExternalName 服務接受 IPv4 地址字符串,但作為包含數字的 DNS 名稱,而不是 IP 地址。 類似於 IPv4 地址的外部名稱不能由 CoreDNS 或 ingress-nginx 解析,因為外部名稱旨在指定規范的 DNS 名稱。 要對 IP 地址進行硬編碼,請考慮使用 headless Services。
當查找主機 my-service.prod.svc.cluster.local
時,集群 DNS 服務返回 CNAME
記錄, 其值為 my.database.example.com
。 訪問 my-service
的方式與其他服務的方式相同,但主要區別在於重定向發生在 DNS 級別,而不是通過代理或轉發。 如果以后你決定將數據庫移到集群中,則可以啟動其 Pod,添加適當的選擇器或端點以及更改服務的 type
。
警告:
對於一些常見的協議,包括 HTTP 和 HTTPS, 你使用 ExternalName 可能會遇到問題。 如果你使用 ExternalName,那么集群內客戶端使用的主機名 與 ExternalName 引用的名稱不同。
對於使用主機名的協議,此差異可能會導致錯誤或意外響應。 HTTP 請求將具有源服務器無法識別的 Host:
標頭;TLS 服 務器將無法提供與客戶端連接的主機名匹配的證書。
說明: 本部分感謝 Alen Komljen的 Kubernetes Tips - Part1 博客文章。
外部 IP
如果外部的 IP 路由到集群中一個或多個 Node 上,Kubernetes Service 會被暴露給這些 externalIPs。 通過外部 IP(作為目的 IP 地址)進入到集群,打到 Service 的端口上的流量, 將會被路由到 Service 的 Endpoint 上。 externalIPs
不會被 Kubernetes 管理,它屬於集群管理員的職責范疇。
根據 Service 的規定,externalIPs
可以同任意的 ServiceType
來一起指定。 在上面的例子中,my-service
可以在 "80.11.12.10:80
"(externalIP:port
) 上被客戶端訪問。
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
不足之處
為 VIP 使用用戶空間代理,將只適合小型到中型規模的集群,不能夠擴展到上千 Service 的大型集群。 查看最初設計方案 獲取更多細節。
使用用戶空間代理,隱藏了訪問 Service 的數據包的源 IP 地址。 這使得一些類型的防火牆無法起作用。 iptables 代理不會隱藏 Kubernetes 集群內部的 IP 地址,但卻要求客戶端請求 必須通過一個負載均衡器或 Node 端口。
Type
字段支持嵌套功能 —— 每一層需要添加到上一層里面。 不會嚴格要求所有雲提供商(例如,GCE 就沒必要為了使一個 LoadBalancer
能工作而分配一個 NodePort
,但是 AWS 需要 ),但當前 API 是強制要求的。
虛擬IP實施
對很多想使用 Service 的人來說,前面的信息應該足夠了。 然而,有很多內部原理性的內容,還是值去理解的。
避免沖突
Kubernetes 最主要的哲學之一,是用戶不應該暴露那些能夠導致他們操作失敗、但又不是他們的過錯的場景。 對於 Service 資源的設計,這意味着如果用戶的選擇有可能與他人沖突,那就不要讓用戶自行選擇端口號。 這是一個隔離性的失敗。
為了使用戶能夠為他們的 Service 選擇一個端口號,我們必須確保不能有2個 Service 發生沖突。 Kubernetes 通過為每個 Service 分配它們自己的 IP 地址來實現。
為了保證每個 Service 被分配到一個唯一的 IP,需要一個內部的分配器能夠原子地更新 etcd 中的一個全局分配映射表, 這個更新操作要先於創建每一個 Service。 為了使 Service 能夠獲取到 IP,這個映射表對象必須在注冊中心存在, 否則創建 Service 將會失敗,指示一個 IP 不能被分配。
在控制平面中,一個后台 Controller 的職責是創建映射表 (需要支持從使用了內存鎖的 Kubernetes 的舊版本遷移過來)。 同時 Kubernetes 會通過控制器檢查不合理的分配(如管理員干預導致的) 以及清理已被分配但不再被任何 Service 使用的 IP 地址。
Service IP 地址
不像 Pod 的 IP 地址,它實際路由到一個固定的目的地,Service 的 IP 實際上 不能通過單個主機來進行應答。 相反,我們使用 iptables
(Linux 中的數據包處理邏輯)來定義一個 虛擬 IP 地址(VIP),它可以根據需要透明地進行重定向。 當客戶端連接到 VIP 時,它們的流量會自動地傳輸到一個合適的 Endpoint。 環境變量和 DNS,實際上會根據 Service 的 VIP 和端口來進行填充。
kube-proxy支持三種代理模式: 用戶空間,iptables和IPVS;它們各自的操作略有不同。
Userspace
作為一個例子,考慮前面提到的圖片處理應用程序。 當創建后端 Service 時,Kubernetes master 會給它指派一個虛擬 IP 地址,比如 10.0.0.1。 假設 Service 的端口是 1234,該 Service 會被集群中所有的 kube-proxy
實例觀察到。 當代理看到一個新的 Service, 它會打開一個新的端口,建立一個從該 VIP 重定向到 新端口的 iptables,並開始接收請求連接。
當一個客戶端連接到一個 VIP,iptables 規則開始起作用,它會重定向該數據包到 "服務代理" 的端口。 "服務代理" 選擇一個后端,並將客戶端的流量代理到后端上。
這意味着 Service 的所有者能夠選擇任何他們想使用的端口,而不存在沖突的風險。 客戶端可以連接到一個 IP 和端口,而不需要知道實際訪問了哪些 Pod。
iptables
再次考慮前面提到的圖片處理應用程序。 當創建后端 Service 時,Kubernetes 控制面板會給它指派一個虛擬 IP 地址,比如 10.0.0.1。 假設 Service 的端口是 1234,該 Service 會被集群中所有的 kube-proxy
實例觀察到。 當代理看到一個新的 Service, 它會配置一系列的 iptables 規則,從 VIP 重定向到每個 Service 規則。 該特定於服務的規則連接到特定於 Endpoint 的規則,而后者會重定向(目標地址轉譯)到后端。
當客戶端連接到一個 VIP,iptables 規則開始起作用。一個后端會被選擇(或者根據會話親和性,或者隨機), 數據包被重定向到這個后端。 不像用戶空間代理,數據包從來不拷貝到用戶空間,kube-proxy 不是必須為該 VIP 工作而運行, 並且客戶端 IP 是不可更改的。
當流量打到 Node 的端口上,或通過負載均衡器,會執行相同的基本流程, 但是在那些案例中客戶端 IP 是可以更改的。
IPVS
在大規模集群(例如 10000 個服務)中,iptables 操作會顯着降低速度。 IPVS 專為負載平衡而設計,並基於內核內哈希表。 因此,你可以通過基於 IPVS 的 kube-proxy 在大量服務中實現性能一致性。 同時,基於 IPVS 的 kube-proxy 具有更復雜的負載均衡算法(最小連接、局部性、 加權、持久性)。
API 對象
Service 是 Kubernetes REST API 中的頂級資源。你可以在以下位置找到有關 API 對象的更多詳細信息: Service 對象 API.
受支持的協議
TCP
你可以將 TCP 用於任何類型的服務,這是默認的網絡協議。
UDP
你可以將 UDP 用於大多數服務。 對於 type=LoadBalancer 服務,對 UDP 的支持取決於提供此功能的雲提供商。
SCTP
FEATURE STATE: Kubernetes v1.20 [stable]
一旦你使用了支持 SCTP 流量的網絡插件,你就可以使用 SCTP 於更多的服務。 對於 type = LoadBalancer 的服務,SCTP 的支持取決於提供此設施的雲供應商(大多數不支持)。
警告
支持多宿主 SCTP 關聯
警告:
支持多宿主SCTP關聯要求 CNI 插件能夠支持為一個 Pod 分配多個接口和IP地址。
用於多宿主 SCTP 關聯的 NAT 在相應的內核模塊中需要特殊的邏輯。
Windows
說明: 基於 Windows 的節點不支持 SCTP。
用戶空間 kube-proxy
警告: 當 kube-proxy 處於用戶空間模式時,它不支持 SCTP 關聯的管理。
HTTP
如果你的雲提供商支持它,則可以在 LoadBalancer 模式下使用服務來設置外部 HTTP/HTTPS 反向代理,並將其轉發到該服務的 Endpoints。
說明: 你還可以使用 Ingress 代替 Service 來公開 HTTP/HTTPS 服務。
PROXY 協議
如果你的雲提供商支持它, 則可以在 LoadBalancer 模式下使用 Service 在 Kubernetes 本身之外配置負載均衡器, 該負載均衡器將轉發前綴為 PROXY 協議 的連接。
負載平衡器將發送一系列初始字節,描述傳入的連接,類似於此示例
PROXY TCP4 192.0.2.202 10.0.42.7 12345 7\r\n
上述是來自客戶端的數據。