diff --git a/content/zh-cn/docs/concepts/services-networking/service.md b/content/zh-cn/docs/concepts/services-networking/service.md index be8ece1709..e00babba3e 100644 --- a/content/zh-cn/docs/concepts/services-networking/service.md +++ b/content/zh-cn/docs/concepts/services-networking/service.md @@ -240,14 +240,16 @@ in the next version of your backend software, without breaking clients. 例如,你可以在新版本中更改 Pod 中后端软件公开的端口号,而不会破坏客户端。 -服务的默认协议是 TCP;你还可以使用任何其他[受支持的协议](#protocol-support)。 +服务的默认协议是 TCP(/zh-cn/docs/reference/networking/service-protocols/#protocol-tcp); +你还可以使用任何其他[受支持的协议](/zh-cn/docs/reference/networking/service-protocols/)。 由于许多服务需要公开多个端口,因此 Kubernetes 在服务对象上支持多个端口定义。 每个端口定义可以具有相同的 `protocol`,也可以具有不同的协议。 @@ -518,263 +520,6 @@ domain prefixed names such as `mycompany.com/my-custom-protocol`. 其值可以是 [IANA 标准服务名称](https://www.iana.org/assignments/service-names) 或以域名为前缀的名称,如 `mycompany.com/my-custom-protocol`。 - -## 虚拟 IP 和 Service 代理 {#virtual-ips-and-service-proxies} - -在 Kubernetes 集群中,每个 Node 运行一个 `kube-proxy` 进程。 -`kube-proxy` 负责为 Service 实现了一种 VIP(虚拟 IP)的形式,而不是 -[`ExternalName`](#externalname) 的形式。 - - -### 为什么不使用 DNS 轮询? {#why-not-use-round-robin-dns} - -时不时会有人问到为什么 Kubernetes 依赖代理将入站流量转发到后端。那其他方法呢? -例如,是否可以配置具有多个 A 值(或 IPv6 为 AAAA)的 DNS 记录,并依靠轮询名称解析? - -使用服务代理有以下几个原因: - -* DNS 实现的历史由来已久,它不遵守记录 TTL,并且在名称查找结果到期后对其进行缓存。 -* 有些应用程序仅执行一次 DNS 查找,并无限期地缓存结果。 -* 即使应用和库进行了适当的重新解析,DNS 记录上的 TTL 值低或为零也可能会给 - DNS 带来高负载,从而使管理变得困难。 - - -在本页下文中,你可以了解各种 kube-proxy 实现是如何工作的。 -总的来说,你应该注意当运行 `kube-proxy` 时,内核级别的规则可能会被修改(例如,可能会创建 iptables 规则), -在某些情况下直到你重新引导才会清理这些内核级别的规则。 -因此,运行 kube-proxy 只能由了解在计算机上使用低级别、特权网络代理服务后果的管理员来完成。 -尽管 `kube-proxy` 可执行文件支持 `cleanup` 功能,但此功能不是官方特性,因此只能按原样使用。 - - -### 配置 {#configuration} - -请注意,kube-proxy 可以以不同的模式启动,具体取决于其配置。 - -- kube-proxy 的配置是通过 ConfigMap 完成的,并且 kube-proxy 的 ConfigMap 有效地弃用了 kube-proxy 几乎所有标志的行为。 -- kube-proxy 的 ConfigMap 不支持实时重新加载配置。 -- kube-proxy 的 ConfigMap 参数不能在启动时被全部校验和验证。 - 例如,如果你的操作系统不允许你运行 iptables 命令,则标准内核 kube-proxy 实现将无法工作。 - 同样,如果你的操作系统不支持 `netsh`,它将无法在 Windows 用户空间模式下运行。 - - -### userspace 代理模式 {#proxy-mode-userspace} - -在这种(遗留)模式下,kube-proxy 会监视 Kubernetes 控制平面对 Service 对象和 Endpoints 对象的添加和移除操作。 -对每个 Service,它会在本地 Node 上打开一个端口(随机选择)。 -任何连接到“代理端口”的请求,都会被代理到 Service 的后端 `Pods` 中的某个上面(如 `Endpoints` 所报告的一样)。 -使用哪个后端 Pod,是 kube-proxy 基于 `SessionAffinity` 来确定的。 - -最后,它配置 iptables 规则,捕获到达该 Service 的 `clusterIP`(是虚拟 IP) -和 `Port` 的请求,并重定向到代理端口,代理端口再代理请求到后端Pod。 - -默认情况下,用户空间模式下的 kube-proxy 通过轮转算法选择后端。 - -![userspace 代理模式下 Service 概览图](/images/docs/services-userspace-overview.svg) - - -### iptables 代理模式 {#proxy-mode-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 [就绪探测器](/zh-cn/docs/concepts/workloads/pods/pod-lifecycle/#container-probes) -验证后端 Pod 可以正常工作,以便 iptables 模式下的 kube-proxy 仅看到测试正常的后端。 -这样做意味着你避免将流量通过 kube-proxy 发送到已知已失败的 Pod。 - -![iptables 代理模式下 Service 概览图](/images/docs/services-iptables-overview.svg) - - -### IPVS 代理模式 {#proxy-mode-ipvs} - -{{< feature-state for_k8s_version="v1.11" state="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) - -{{< note >}} - -要在 IPVS 模式下运行 kube-proxy,必须在启动 kube-proxy 之前使 IPVS 在节点上可用。 - -当 kube-proxy 以 IPVS 代理模式启动时,它将验证 IPVS 内核模块是否可用。 -如果未检测到 IPVS 内核模块,则 kube-proxy 将退回到以 iptables 代理模式运行。 -{{< /note >}} - - - -![IPVS 代理的 Services 概述图](/images/docs/services-ipvs-overview.svg) - -在这些代理模型中,绑定到服务 IP 的流量: -在客户端不了解 Kubernetes 或服务或 Pod 的任何信息的情况下,将 Port 代理到适当的后端。 - -如果要确保每次都将来自特定客户端的连接传递到同一 Pod, -则可以通过将 `service.spec.sessionAffinity` 设置为 "ClientIP" -(默认值是 "None"),来基于客户端的 IP 地址选择会话亲和性。 -你还可以通过适当设置 `service.spec.sessionAffinityConfig.clientIP.timeoutSeconds` -来设置最大会话停留时间。(默认值为 10800 秒,即 3 小时)。 - -{{< note >}} - -在 Windows 上,不支持为服务设置最大会话停留时间。 -{{< /note >}} -## 流量策略 {#traffic-policies} - - -### 外部流量策略 {#external-traffic-policy} - - -你可以通过设置 `spec.externalTrafficPolicy` 字段来控制来自于外部的流量是如何路由的。 -可选值有 `Cluster` 和 `Local`。字段设为 `Cluster` 会将外部流量路由到所有就绪的端点, -设为 `Local` 会只路由到当前节点上就绪的端点。 -如果流量策略设置为 `Local`,而且当前节点上没有就绪的端点,kube-proxy 不会转发请求相关服务的任何流量。 - -{{< note >}} -{{< feature-state for_k8s_version="v1.22" state="alpha" >}} - - -如果你启用了 kube-proxy 的 `ProxyTerminatingEndpoints` -[特性门控](/zh-cn/docs/reference/command-line-tools-reference/feature-gates/), -kube-proxy 会检查节点是否有本地的端点,以及是否所有的本地端点都被标记为终止中。 - - -如果本地有端点,而且所有端点处于终止中的状态,那么 kube-proxy 会忽略任何设为 `Local` 的外部流量策略。 -在所有本地端点处于终止中的状态的同时,kube-proxy 将请求指定服务的流量转发到位于其它节点的状态健康的端点, -如同外部流量策略设为 `Cluster`。 - - -针对处于正被终止状态的端点这一转发行为使得外部负载均衡器可以优雅地排出由 -`NodePort` 服务支持的连接,就算是健康检查节点端口开始失败也是如此。 -否则,当节点还在负载均衡器的节点池内,在 Pod 终止过程中的流量会被丢掉,这些流量可能会丢失。 - -{{< /note >}} - - -### 内部流量策略 {#internal-traffic-policy} - -{{< feature-state for_k8s_version="v1.22" state="beta" >}} - - -你可以设置 `spec.internalTrafficPolicy` 字段来控制内部来源的流量是如何转发的。可设置的值有 `Cluster` 和 `Local`。 -将字段设置为 `Cluster` 会将内部流量路由到所有就绪端点,设置为 `Local` 只会路由到当前节点上就绪的端点。 -如果流量策略是 `Local`,而且当前节点上没有就绪的端点,那么 kube-proxy 会丢弃流量。 - +`type` 字段被设计为嵌套功能 - 每个级别都添加到前一个级别。 +这并不是所有云提供商都严格要求的(例如:Google Compute Engine +不需要分配节点端口来使 `type: LoadBalancer` 工作,但另一个云提供商集成可能会这样做)。 +虽然不需要严格的嵌套,但是 Service 的 Kubernetes API 设计无论如何都需要它。 + -## 不足之处 {#shortcomings} +## 粘性会话 {#session-stickiness} -为 VIP 使用用户空间代理,将只适合小型到中型规模的集群,不能够扩展到上千 Service 的大型集群。 -查看[最初设计方案](https://github.com/kubernetes/kubernetes/issues/1107) 获取更多细节。 - -使用用户空间代理,隐藏了访问 Service 的数据包的源 IP 地址。 -这使得一些类型的防火墙无法起作用。 -iptables 代理不会隐藏 Kubernetes 集群内部的 IP 地址, -但却要求客户端请求必须通过一个负载均衡器或 Node 端口。 - -`Type` 字段支持嵌套功能 —— 每一层需要添加到上一层里面。 -不会严格要求所有云提供商(例如,GCE 就没必要为了使一个 `LoadBalancer` -能工作而分配一个 `NodePort`,但是 AWS 需要 ),但针对服务的 Kubernetes API 设计是强制要求的。 - - -## 虚拟 IP 实施 {#the-gory-details-of-virtual-ips} - -对很多想使用 Service 的人来说,前面的信息应该足够了。 -然而,有很多内部原理性的内容,还是值去理解的。 - - -### 避免冲突 {#avoiding-collisions} - -Kubernetes 最主要的哲学之一,是用户不应该暴露那些能够导致他们操作失败、但又不是他们的过错的场景。 -对于 Service 资源的设计,这意味着如果用户的选择有可能与他人冲突,那就不要让用户自行选择端口号。 -这是一个隔离性的失败。 - -为了使用户能够为他们的 Service 选择一个端口号,我们必须确保不能有 2 个 Service 发生冲突。 -Kubernetes 通过在为 API 服务器配置的 `service-cluster-ip-range` CIDR -范围内为每个服务分配自己的 IP 地址来实现。 - -为了保证每个 Service 被分配到一个唯一的 IP,需要一个内部的分配器能够原子地更新 -{{< glossary_tooltip term_id="etcd" >}} 中的一个全局分配映射表, -这个更新操作要先于创建每一个 Service。 -为了使 Service 能够获取到 IP,这个映射表对象必须在注册中心存在, -否则创建 Service 将会失败,指示一个 IP 不能被分配。 - -在控制平面中,一个后台 Controller 的职责是创建映射表 -(需要支持从使用了内存锁的 Kubernetes 的旧版本迁移过来)。 -同时 Kubernetes 会通过控制器检查不合理的分配(如管理员干预导致的) -以及清理已被分配但不再被任何 Service 使用的 IP 地址。 - - -#### `type: ClusterIP` 服务的 IP 地址范围 {#service-ip-static-sub-range} - -{{< feature-state for_k8s_version="v1.25" state="beta" >}} -但是,这种 `ClusterIP` 分配策略存在一个问题,因为用户还可以[为服务选择自己的地址](#choosing-your-own-ip-address)。 -如果内部分配器为另一个服务选择相同的 IP 地址,这可能会导致冲突。 - - -`ServiceIPStaticSubrange` [特性门控](/zh-cn/docs/reference/command-line-tools-reference/feature-gates/)在 -v1.25 及后续版本中默认启用,其分配策略根据配置的 `service-cluster-ip-range` 的大小,使用以下公式 -`min(max(16, cidrSize / 16), 256)` 进行划分,该公式可描述为 -“在不小于 16 且不大于 256 之间有一个步进量(Graduated Step)”,将 -`ClusterIP` 范围分成两段。动态 IP 分配将优先从上半段地址中选择, -从而降低与下半段地址分配的 IP 冲突的风险。 -这允许用户将 `service-cluster-ip-range` 的下半段地址用于他们的服务, -与所分配的静态 IP 的冲突风险非常低。 - - -### Service IP 地址 {#ips-and-vips} - -不像 Pod 的 IP 地址,它实际路由到一个固定的目的地,Service 的 IP 实际上不能通过单个主机来进行应答。 -相反,我们使用 `iptables`(Linux 中的数据包处理逻辑)来定义一个虚拟 IP 地址(VIP), -它可以根据需要透明地进行重定向。 -当客户端连接到 VIP 时,它们的流量会自动地传输到一个合适的 Endpoint。 -环境变量和 DNS,实际上会根据 Service 的 VIP 和端口来进行填充。 - -kube-proxy 支持三种代理模式: 用户空间、iptables 和 IPVS;它们各自的操作略有不同。 - -#### Userspace {#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 具有更复杂的负载均衡算法(最小连接、局部性、加权、持久性)。 +如果你想确保来自特定客户端的连接每次都传递到同一个 Pod,你可以配置根据客户端 IP 地址来执行的会话亲和性。 +阅读[会话亲和性](/zh-cn/docs/reference/networking/virtual-ips/#session-affinity)了解更多。 ## API 对象 {#api-object} @@ -2421,130 +1882,19 @@ Service 是 Kubernetes REST API 中的顶级资源。你可以找到有关 [Service 对象 API](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#service-v1-core) 的更多详细信息。 -## 受支持的协议 {#protocol-support} - -### TCP + + -你可以将 TCP 用于任何类型的服务,这是默认的网络协议。 +## 虚拟 IP 寻址机制 {#virtual-ip-addressing-mechanism} -### UDP - - -你可以将 UDP 用于大多数服务。 对于 type=LoadBalancer 服务,对 UDP 的支持取决于提供此功能的云提供商。 - - -### SCTP - -{{< feature-state for_k8s_version="v1.20" state="stable" >}} - -一旦你使用了支持 SCTP 流量的网络插件,你就可以使用 SCTP 于更多的服务。 -对于 type = LoadBalancer 的服务,SCTP 的支持取决于提供此设施的云供应商(大多数不支持)。 - - -#### 警告 {#caveat-sctp-overview} - -##### 支持多宿主 SCTP 关联 {#caveat-sctp-multihomed} - -{{< warning >}} - -支持多宿主 SCTP 关联要求 CNI 插件能够支持为一个 Pod 分配多个接口和 IP 地址。 - -用于多宿主 SCTP 关联的 NAT 在相应的内核模块中需要特殊的逻辑。 -{{< /warning >}} - - -##### Windows {#caveat-sctp-windows-os} - -{{< note >}} - -基于 Windows 的节点不支持 SCTP。 -{{< /note >}} - - -##### 用户空间 kube-proxy {#caveat-sctp-kube-proxy-userspace} - -{{< warning >}} - -当 kube-proxy 处于用户空间模式时,它不支持 SCTP 关联的管理。 -{{< /warning >}} - -### HTTP - - -如果你的云提供商支持它,则可以在 LoadBalancer 模式下使用服务来设置外部 -HTTP/HTTPS 反向代理,并将其转发到该服务的 Endpoints。 - -{{< note >}} - -你还可以使用 {{< glossary_tooltip text="Ingress" term_id="ingress" >}} 代替 -Service 来公开 HTTP/HTTPS 服务。 -{{< /note >}} - - -### PROXY 协议 {#proxy-protocol} - -如果你的云提供商支持它, -则可以在 LoadBalancer 模式下使用 Service 在 Kubernetes 本身之外配置负载均衡器, -该负载均衡器将转发前缀为 -[PROXY 协议](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) -的连接。 - -负载均衡器将发送一系列初始字节,描述传入的连接,类似于此示例: - -``` -PROXY TCP4 192.0.2.202 10.0.42.7 12345 7\r\n -``` - - -上述是来自客户端的数据。 +阅读[虚拟 IP 和 Service 代理](/zh-cn/docs/reference/networking/virtual-ips/)以了解 +Kubernetes 提供的使用虚拟 IP 地址公开服务的机制。 ## {{% heading "whatsnext" %}} @@ -2552,7 +1902,18 @@ followed by the data from the client. * Follow the [Connecting Applications with Services](/docs/tutorials/services/connect-applications-service/) tutorial * Read about [Ingress](/docs/concepts/services-networking/ingress/) * Read about [EndpointSlices](/docs/concepts/services-networking/endpoint-slices/) + +For more context: +* Read [Virtual IPs and Service Proxies](/docs/reference/networking/virtual-ips/) +* Read the [API reference](/docs/reference/kubernetes-api/service-resources/service-v1/) for the Service API +* Read the [API reference](/docs/reference/kubernetes-api/service-resources/endpoints-v1/) for the Endpoints API +* Read the [API reference](/docs/reference/kubernetes-api/service-resources/endpoint-slice-v1/) for the EndpointSlice API --> * 遵循[使用 Service 连接到应用](/zh-cn/docs/tutorials/services/connect-applications-service/)教程 * 阅读了解 [Ingress](/zh-cn/docs/concepts/services-networking/ingress/) * 阅读了解[端点切片(Endpoint Slices)](/zh-cn/docs/concepts/services-networking/endpoint-slices/) + +更多上下文: +* 阅读[虚拟 IP 和 Service 代理](/zh-cn/docs/reference/networking/virtual-ips/) +* 阅读 Service API 的 [API 参考](/zh-cn/docs/reference/kubernetes-api/service-resources/service-v1/) +* 阅读 EndpointSlice API 的 [API 参考](/zh-cn/docs/reference/kubernetes-api/service-resources/endpoint-slice-v1/) \ No newline at end of file