From 43694f3c3ae12f760a5f3552fddc07b3329fa051 Mon Sep 17 00:00:00 2001 From: Linus Lee <708863861@qq.com> Date: Mon, 17 Dec 2018 10:27:36 +0800 Subject: [PATCH] zh_trans: Fix homepage kubernetes feature display invalidation problem (#11755) * Update service.md * Update service.md * Update service.md * Update service.md --- .../concepts/services-networking/service.md | 742 ++++++++++++++++-- 1 file changed, 659 insertions(+), 83 deletions(-) diff --git a/content/zh/docs/concepts/services-networking/service.md b/content/zh/docs/concepts/services-networking/service.md index 6e9705b221..e1f96c7bb7 100644 --- a/content/zh/docs/concepts/services-networking/service.md +++ b/content/zh/docs/concepts/services-networking/service.md @@ -1,47 +1,104 @@ --- -approvers: +reviewers: - bprashanth -title: Service -redirect_from: -- "/docs/user-guide/services/" -- "/docs/user-guide/services/index.html" +title: Services +feature: + title: 服务发现与负载均衡 + description: > + 无需修改您的应用程序即可使用陌生的服务发现机制。Kubernetes 为容器提供了自己的 IP 地址和一个 DNS 名称,并且可以在它们之间实现负载平衡。 + +content_template: templates/concept +weight: 10 --- + + + +{{% capture overview %}} + + Kubernetes [`Pod`](/docs/user-guide/pods) 是有生命周期的,它们可以被创建,也可以被销毁,然而一旦被销毁生命就永远结束。 通过 [`ReplicaSets`](/docs/concepts/workloads/controllers/replicaset/) 能够动态地创建和销毁 `Pod`(例如,需要进行扩缩容,或者执行 [滚动升级](/docs/user-guide/kubectl/v1.7/#rolling-update))。 每个 `Pod` 都会获取它自己的 IP 地址,即使这些 IP 地址不总是稳定可依赖的。 这会导致一个问题:在 Kubernetes 集群中,如果一组 `Pod`(称为 backend)为其它 `Pod` (称为 frontend)提供服务,那么那些 frontend 该如何发现,并连接到这组 `Pod` 中的哪些 backend 呢? + +关于 `Services` -关于 `Service` - - + Kubernetes `Service` 定义了这样一种抽象:逻辑上的一组 `Pod`,一种可以访问它们的策略 —— 通常称为微服务。 这一组 `Pod` 能够被 `Service` 访问到,通常是通过 [`Label Selector`](/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`。 -{{< toc >}} +{{% /capture %}} +{{% capture body %}} + + ## 定义 Service - - 一个 `Service` 在 Kubernetes 中是一个 REST 对象,和 `Pod` 类似。 像所有的 REST 对象一样, `Service` 定义可以基于 POST 方式,请求 apiserver 创建新的实例。 例如,假定有一组 `Pod`,它们对外暴露了 9376 端口,同时还被打上 `"app=MyApp"` 标签。 @@ -60,13 +117,29 @@ spec: targetPort: 9376 ``` - + 上述配置将创建一个名称为 “my-service” 的 `Service` 对象,它会将请求代理到使用 TCP 端口 9376,并且具有标签 `"app=MyApp"` 的 `Pod` 上。 这个 `Service` 将被指派一个 IP 地址(通常称为 “Cluster IP”),它会被服务的代理使用(见下面)。 该 `Service` 的 selector 将会持续评估,处理结果将被 POST 到一个名称为 “my-service” 的 `Endpoints` 对象上。 - + 需要注意的是, `Service` 能够将一个接收端口映射到任意的 `targetPort`。 默认情况下,`targetPort` 将被设置为与 `port` 字段相同的值。 @@ -75,16 +148,32 @@ spec: 对于部署和设计 `Service` ,这种方式会提供更大的灵活性。 例如,可以在 backend 软件下一个版本中,修改 Pod 暴露的端口,并不会中断客户端的调用。 - + Kubernetes `Service` 能够支持 `TCP` 和 `UDP` 协议,默认 `TCP` 协议。 +{{< note >}} +自 Kubernetes 1.12 以来,SCTP 的支持是 alpha 功能。 +{{< /note >}} + ### 没有 selector 的 Service - - Servcie 抽象了该如何访问 Kubernetes `Pod`,但也能够抽象其它类型的 backend,例如: * 希望在生产环境中使用外部的数据库集群,但测试环境使用自己的数据库。 @@ -105,6 +194,10 @@ spec: targetPort: 9376 ``` + 由于这个 `Service` 没有 selector,就不会创建相关的 `Endpoints` 对象。可以手动将 `Service` 映射到指定的 `Endpoints`: @@ -120,57 +213,76 @@ subsets: - port: 9376 ``` + +{{< note >}} +注意:Endpoint IP 地址不能是 loopback(127.0.0.0/8)、 link-local(169.254.0.0/16)、或者 link-local 多播(224.0.0.0/24)。它们不能是其他 Kubernetes 服务的集群 IP,因为 `kube-proxy` 组件不支持虚拟 IP 作为目的地。 +{{< /note >}} -注意: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,也没有使用 DNS 名称代替。 +有关更多信息,请参阅本文档后面的[`ExternalName`](#externalname)。 -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`](#externalname) 的形式。 - -在 Kubernetes 集群中,每个 Node 运行一个 `kube-proxy` 进程。`kube-proxy` 负责为 `Service` 实现了一种 VIP(虚拟 IP)的形式,而不是 `ExternalName` 的形式。 -在 Kubernetes v1.0 版本,代理完全在 userspace。在 Kubernetes v1.1 版本,新增了 iptables 代理,但并不是默认的运行模式。 -从 Kubernetes v1.2 起,默认就是 iptables 代理。 +在 Kubernetes v1.0 版本,`Services` 是 "L4" (IP 层上的 TCP/UDP) 构造,代理完全在 userspace。在 Kubernetes v1.1 版本,新增了 `Ingress` API (beta) "L 7"(HTTP) 服务与 iptables 代理,自 Kubernetes v1.2 以来成为默认的操作模式。 +在 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` 所报告的一样)。 @@ -190,12 +302,24 @@ spec: ![userspace代理模式下Service概览图](/images/docs/services-userspace-overview.svg) - + ### iptables 代理模式 - - 这种模式,kube-proxy 会监视 Kubernetes master 对 `Service` 对象和 `Endpoints` 对象的添加和移除。 对每个 `Service`,它会安装 iptables 规则,从而捕获到达该 `Service` 的 `clusterIP`(虚拟 IP)和端口的请求,进而将请求重定向到 `Service` 的一组 backend 中的某个上面。 对于每个 `Endpoints` 对象,它也会安装 iptables 规则,这个规则会选择一个 backend `Pod`。 @@ -214,7 +338,68 @@ spec: ![iptables代理模式下Service概览图](/images/docs/services-iptables-overview.svg) + + ## 多端口 Service @@ -242,23 +427,43 @@ spec: 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、缓存域名查询结果 @@ -267,20 +472,42 @@ spec: 我们尽力阻止用户做那些对他们没有好处的事情,如果很多人都来问这个问题,我们可能会选择实现它。 - + ## 服务发现 - - Kubernetes 支持2种基本的服务发现模式 —— 环境变量和 DNS。 - - + ### 环境变量 - - 当 `Pod` 运行在 `Node` 上,kubelet 会为每个活跃的 `Service` 添加一组环境变量。 它同时支持 [Docker links兼容](https://docs.docker.com/userguide/dockerlinks/) 变量(查看 [makeLinkVariables](http://releases.k8s.io/{{< param "githubbranch" >}}/pkg/kubelet/envvars/envvars.go#L49))、简单的 `{SVCNAME}_SERVICE_HOST` 和 `{SVCNAME}_SERVICE_PORT` 变量,这里 `Service` 的名称需大写,横线被转换成下划线。 @@ -301,9 +528,29 @@ REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11 *这意味着需要有顺序的要求* —— `Pod` 想要访问的任何 `Service` 必须在 `Pod` 自己之前被创建,否则这些环境变量就不会被赋值。DNS 并没有这个限制。 + - +### DNS 一个可选(尽管强烈推荐)[集群插件](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/README.md) 是 DNS 服务器。 DNS 服务器监视着创建新 `Service` 的 Kubernetes API,从而为每一个 `Service` 创建一组 DNS 记录。 @@ -326,7 +573,20 @@ Kubernetes 也支持对端口名称的 DNS SRV(Service)记录。 Kubernetes DNS 服务器是唯一的一种能够访问 `ExternalName` 类型的 Service 的方式。 更多信息可以查看[DNS Pod 和 Service](/docs/concepts/services-networking/dns-pod-service/)。 - + ## Headless Service @@ -345,7 +605,12 @@ Kubernetes DNS 服务器是唯一的一种能够访问 `ExternalName` 类型的 对这类 `Service` 并不会分配 Cluster IP,kube-proxy 不会处理它们,而且平台也不会为它们进行负载均衡和路由。 DNS 如何实现自动配置,依赖于 `Service` 是否定义了 selector。 - + ### 配置 Selector @@ -353,7 +618,15 @@ DNS 如何实现自动配置,依赖于 `Service` 是否定义了 selector。 对定义了 selector 的 Headless Service,Endpoint 控制器在 API 中创建了 `Endpoints` 记录,并且修改 DNS 配置返回 A 记录(地址),通过这个地址直接到达 `Service` 的后端 `Pod` 上。 - + ### 不配置 Selector @@ -365,7 +638,29 @@ DNS 如何实现自动配置,依赖于 `Service` 是否定义了 selector。 * `ExternalName` 类型 Service 的 CNAME 记录 * 记录:与 Service 共享一个名称的任何 `Endpoints`,以及所有其它类型 - + ## 发布服务 —— 服务类型 @@ -383,7 +678,23 @@ Kubernetes `ServiceTypes` 允许指定一个需要的类型的 Service,默认 * `ExternalName`:通过返回 `CNAME` 和它的值,可以将服务映射到 `externalName` 字段的内容(例如, `foo.bar.example.com`)。 没有任何类型代理被创建,这只有 Kubernetes 1.7 或更高版本的 `kube-dns` 才支持。 - + ### NodePort 类型 @@ -402,12 +713,51 @@ Kubernetes `ServiceTypes` 允许指定一个需要的类型的 Service,默认 需要注意的是,Service 将能够通过 `:spec.ports[*].nodePort` 和 `spec.clusterIp:spec.ports[*].port` 而对外可见。 - + ### LoadBalancer 类型 - - 使用支持外部负载均衡器的云提供商的服务,设置 `type` 的值为 `"LoadBalancer"`,将为 `Service` 提供负载均衡器。 负载均衡器是异步创建的,关于被提供的负载均衡器的信息将会通过 `Service` 的 `status.loadBalancer` 字段被发布出去。 @@ -439,7 +789,59 @@ status: 某些云提供商允许设置 `loadBalancerIP`。如果没有设置 `loadBalancerIP`,将会给负载均衡器指派一个临时 IP。 如果设置了 `loadBalancerIP`,但云提供商并不支持这种特性,那么设置的 `loadBalancerIP` 值将会被忽略掉。 - + ### AWS 内部负载均衡器 在混合云环境中,有时从虚拟私有云(VPC)环境中的服务路由流量是非常有必要的。 @@ -457,7 +859,61 @@ metadata: 在水平分割的 DNS 环境中,需要两个 `Service` 来将外部和内部的流量路由到 Endpoint 上。 - + ### AWS SSL 支持 对运行在 AWS 上部分支持 SSL 的集群,从 1.3 版本开始,可以为 `LoadBalancer` 类型的 `Service` 增加两个 annotation: @@ -490,7 +946,31 @@ HTTP 和 HTTPS 将选择7层代理:ELB 将中断与用户的连接,当转发 TCP 和 SSL 将选择4层代理:ELB 将转发流量,并不修改 Header 信息。 - + ### 外部 IP @@ -518,7 +998,20 @@ spec: - 80.11.12.10 ``` - + ## 不足之处 @@ -536,7 +1029,20 @@ iptables 代理不会隐藏 Kubernetes 集群内部的 IP 地址,但却要求 `Type` 字段支持嵌套功能 —— 每一层需要添加到上一层里面。 不会严格要求所有云提供商(例如,GCE 就没必要为了使一个 `LoadBalancer` 能工作而分配一个 `NodePort`,但是 AWS 需要 ),但当前 API 是强制要求的。 - + ## 未来工作 @@ -549,14 +1055,37 @@ iptables 代理不会隐藏 Kubernetes 集群内部的 IP 地址,但却要求 我们打算为 `Service` 实现更加灵活的请求进入模式,这些 `Service` 包含当前 `ClusterIP`、`NodePort` 和 `LoadBalancer` 模式,或者更多。 - + ## VIP 的那些骇人听闻的细节 对很多想使用 `Service` 的人来说,前面的信息应该足够了。 然而,有很多内部原理性的内容,还是值去理解的。 - + ### 避免冲突 @@ -575,7 +1104,18 @@ Kubernetes 最主要的哲学之一,是用户不应该暴露那些能够导致 为了使 `Service` 能够获取到 IP,这个映射表对象必须在注册中心存在,否则创建 `Service` 将会失败,指示一个 IP 不能被分配。 一个后台 Controller 的职责是创建映射表(从 Kubernetes 的旧版本迁移过来,旧版本中是通过在内存中加锁的方式实现),并检查由于管理员干预和清除任意 IP 造成的不合理分配,这些 IP 被分配了但当前没有 `Service` 使用它们。 - + ### IP 和 VIP @@ -584,7 +1124,22 @@ Kubernetes 最主要的哲学之一,是用户不应该暴露那些能够导致 当客户端连接到 VIP 时,它们的流量会自动地传输到一个合适的 Endpoint。 环境变量和 DNS,实际上会根据 `Service` 的 VIP 和端口来进行填充。 - + #### Userspace @@ -601,7 +1156,23 @@ Kubernetes 最主要的哲学之一,是用户不应该暴露那些能够导致 这意味着 `Service` 的所有者能够选择任何他们想使用的端口,而不存在冲突的风险。 客户端可以简单地连接到一个 IP 和端口,而不需要知道实际访问了哪些 `Pod`。 - + #### Iptables @@ -617,7 +1188,12 @@ Kubernetes 最主要的哲学之一,是用户不应该暴露那些能够导致 不像 userspace 代理,数据包从来不拷贝到用户空间,kube-proxy 不是必须为该 VIP 工作而运行,并且客户端 IP 是不可更改的。 当流量打到 Node 的端口上,或通过负载均衡器,会执行相同的基本流程,但是在那些案例中客户端 IP 是可以更改的。 - + ## API 对象