From 5bffffb3cb0a655e12cddadc7774048b7944c0f0 Mon Sep 17 00:00:00 2001 From: Song Shukun Date: Wed, 16 Mar 2022 23:13:42 +0900 Subject: [PATCH] [zh] Update connect-applications-service.md --- .../connect-applications-service.md | 171 ++++++++---------- 1 file changed, 76 insertions(+), 95 deletions(-) diff --git a/content/zh/docs/concepts/services-networking/connect-applications-service.md b/content/zh/docs/concepts/services-networking/connect-applications-service.md index e75422a41b..d24745a3f0 100644 --- a/content/zh/docs/concepts/services-networking/connect-applications-service.md +++ b/content/zh/docs/concepts/services-networking/connect-applications-service.md @@ -9,30 +9,25 @@ weight: 30 -## Kubernetes 连接容器模型 +## Kubernetes 连接容器的模型 既然有了一个持续运行、可复制的应用,我们就能够将它暴露到网络上。 -在讨论 Kubernetes 网络连接的方式之前,非常值得与 Docker 中 “正常” 方式的网络进行对比。 -默认情况下,Docker 使用私有主机网络连接,只能与同在一台机器上的容器进行通信。 -为了实现容器的跨节点通信,必须在机器自己的 IP 上为这些容器分配端口,为容器进行端口转发或者代理。 - -多个开发人员或是提供容器的团队之间协调端口的分配很难做到规模化,那些难以控制的集群级别的问题,都会交由用户自己去处理。 Kubernetes 假设 Pod 可与其它 Pod 通信,不管它们在哪个主机上。 -Kubernetes 给 Pod 分配属于自己的集群私有 IP 地址,所以没必要在 Pod 或映射到的容器的端口和主机端口之间显式地创建连接。 -这表明了在 Pod 内的容器都能够连接到本地的每个端口,集群中的所有 Pod 不需要通过 NAT 转换就能够互相看到。 -文档的剩余部分详述如何在一个网络模型之上运行可靠的服务。 +Kubernetes 给每一个 Pod 分配一个集群私有 IP 地址,所以没必要在 +Pod 与 Pod 之间创建连接或将容器的端口映射到主机端口。 +这意味着同一个 Pod 内的所有容器能通过 localhost 上的端口互相连通,集群中的所有 Pod +也不需要通过 NAT 转换就能够互相看到。 +本文档的剩余部分详述如何在上述网络模型之上运行可靠的服务。 -该指南使用一个简单的 Nginx server 来演示并证明谈到的概念。 +本指南使用一个简单的 Nginx 服务器来演示概念验证原型。 @@ -45,7 +40,7 @@ Create an nginx Pod, and note that it has a container port specification: ## 在集群中暴露 Pod 我们在之前的示例中已经做过,然而让我们以网络连接的视角再重做一遍。 -创建一个 Nginx Pod,并且注意,它有一个容器端口的规范: +创建一个 Nginx Pod,注意其中包含一个容器端口的规约: {{< codenew file="service/networking/run-my-nginx.yaml" >}} @@ -77,16 +72,17 @@ kubectl get pods -l run=my-nginx -o yaml | grep podIP ``` -应该能够通过 ssh 登录到集群中的任何一个节点上,使用 curl 也能调通所有 IP 地址。 +你应该能够通过 ssh 登录到集群中的任何一个节点上,并使用诸如 `curl` 之类的工具向这两个 IP 地址发出查询请求。 需要注意的是,容器不会使用该节点上的 80 端口,也不会使用任何特定的 NAT 规则去路由流量到 Pod 上。 -这意味着可以在同一个节点上运行多个 Pod,使用相同的容器端口,并且可以从集群中任何其他的 Pod 或节点上使用 IP 的方式访问到它们。 -像 Docker 一样,端口能够被发布到主机节点的接口上,但是出于网络模型的原因应该从根本上减少这种用法。 +这意味着可以在同一个节点上运行多个 Nginx Pod,使用相同的 `containerPort`,并且可以从集群中任何其他的 +Pod 或节点上使用 IP 的方式访问到它们。 +如果你想的话,你依然可以将宿主节点的某个端口的流量转发到 Pod 中,但是出于网络模型的原因,你不必这么做。 -如果对此好奇,可以获取更多关于 [如何实现网络模型](/zh/docs/concepts/cluster-administration/networking/#how-to-achieve-this) 的内容。 +如果对此好奇,请参考 [Kubernetes 网络模型](/zh/docs/concepts/cluster-administration/networking/#the-kubernetes-network-model)。 ## 创建 Service -我们有 Pod 在一个扁平的、集群范围的地址空间中运行 Nginx 服务,可以直接连接到这些 Pod,但如果某个节点死掉了会发生什么呢? +我们有一组在一个扁平的、集群范围的地址空间中运行 Nginx 服务的 Pod。 +理论上,你可以直接连接到这些 Pod,但如果某个节点死掉了会发生什么呢? Pod 会终止,Deployment 将创建新的 Pod,且使用不同的 IP。这正是 Service 要解决的问题。 -Kubernetes Service 从逻辑上定义了运行在集群中的一组 Pod,这些 Pod 提供了相同的功能。 +Kubernetes Service 是集群中提供相同功能的一组 Pod 的抽象表达。 当每个 Service 创建时,会被分配一个唯一的 IP 地址(也称为 clusterIP)。 -这个 IP 地址与一个 Service 的生命周期绑定在一起,当 Service 存在的时候它也不会改变。 +这个 IP 地址与 Service 的生命周期绑定在一起,只要 Service 存在,它就不会改变。 可以配置 Pod 使它与 Service 进行通信,Pod 知道与 Service 通信将被自动地负载均衡到该 Service 中的某些 Pod 上。 可以使用 `kubectl expose` 命令为 2个 Nginx 副本创建一个 Service: @@ -120,7 +117,7 @@ service/my-nginx exposed This is equivalent to `kubectl apply -f` the following yaml: --> -这等价于使用 `kubectl create -f` 命令创建,对应如下的 yaml 文件: +这等价于使用 `kubectl create -f` 命令及如下的 yaml 文件创建: {{< codenew file="service/networking/nginx-svc.yaml" >}} @@ -134,11 +131,11 @@ View [Service](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/ API object to see the list of supported fields in service definition. Check your Service: --> -上述规约将创建一个 Service,对应具有标签 `run: my-nginx` 的 Pod,目标 TCP 端口 80, -并且在一个抽象的 Service 端口(`targetPort`:容器接收流量的端口;`port`:抽象的 Service -端口,可以使任何其它 Pod 访问该 Service 的端口)上暴露。 -查看 [Service API 对象](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#service-v1-core) -了解 Service 定义支持的字段列表。 +上述规约将创建一个 Service,该 Service 会将所有具有标签 `run: my-nginx` 的 Pod 的 TCP +80 端口暴露到一个抽象的 Service 端口上(`targetPort`:容器接收流量的端口;`port`:可任意取值的抽象的 Service +端口,其他 Pod 通过该端口访问 Service)。 +查看 [Service](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#service-v1-core) +API 对象以了解 Service 所能接受的字段列表。 查看你的 Service 资源: ```shell @@ -158,7 +155,7 @@ matching the Service's selector will automatically get added to the endpoints. Check the endpoints, and note that the IPs are the same as the Pods created in the first step: --> -正如前面所提到的,一个 Service 由一组 backend Pod 组成。这些 Pod 通过 `endpoints` 暴露出来。 +正如前面所提到的,一个 Service 由一组 Pod 提供支撑。这些 Pod 通过 `endpoints` 暴露出来。 Service Selector 将持续评估,结果被 POST 到一个名称为 `my-nginx` 的 Endpoint 对象上。 当 Pod 终止后,它会自动从 Endpoint 中移除,新的能够匹配上 Service Selector 的 Pod 将自动地被添加到 Endpoint 中。 检查该 Endpoint,注意到 IP 地址与在第一步创建的 Pod 是相同的。 @@ -194,7 +191,7 @@ never hits the wire. If you're curious about how this works you can read more about the [service proxy](/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies). --> -现在,能够从集群中任意节点上使用 curl 命令请求 Nginx Service `:` 。 +现在,你应该能够从集群中任意节点上使用 curl 命令向 `:` 发送请求以访问 Nginx Service。 注意 Service IP 完全是虚拟的,它从来没有走过网络,如果对它如何工作的原理感到好奇, 可以进一步阅读[服务代理](/zh/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies) 的内容。 @@ -204,12 +201,12 @@ about the [service proxy](/docs/concepts/services-networking/service/#virtual-ip Kubernetes supports 2 primary modes of finding a Service - environment variables and DNS. The former works out of the box while the latter requires the -[CoreDNS cluster addon](https://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/dns/coredns). +[CoreDNS cluster addon](https://releases.k8s.io/{{< param "fullversion" >}}/cluster/addons/dns/coredns). --> ## 访问 Service -Kubernetes支持两种查找服务的主要模式: 环境变量和DNS。 前者开箱即用,而后者则需要[CoreDNS集群插件] -[CoreDNS 集群插件](https://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/dns/coredns). +Kubernetes支持两种查找服务的主要模式: 环境变量和 DNS。前者开箱即用,而后者则需要 +[CoreDNS 集群插件](https://releases.k8s.io/{{< param "fullversion" >}}/cluster/addons/dns/coredns). ### 环境变量 -当 Pod 在 Node 上运行时,kubelet 会为每个活跃的 Service 添加一组环境变量。 -这会有一个顺序的问题。想了解为何,检查正在运行的 Nginx Pod 的环境变量(Pod 名称将不会相同): +当 Pod 在节点上运行时,kubelet 会针对每个活跃的 Service 为 Pod 添加一组环境变量。 +这就引入了一个顺序的问题。为解释这个问题,让我们先检查正在运行的 Nginx Pod +的环境变量(你的环境中的 Pod 名称将会与下面示例命令中的不同): ```shell kubectl exec my-nginx-3800858182-jr4a2 -- printenv | grep SERVICE @@ -254,10 +252,11 @@ replicas. This will give you scheduler-level Service spreading of your Pods variables: --> -注意,还没有谈及到 Service。这是因为创建副本先于 Service。 -这样做的另一个缺点是,调度器可能在同一个机器上放置所有 Pod,如果该机器宕机则所有的 Service 都会挂掉。 -正确的做法是,我们杀掉 2 个 Pod,等待 Deployment 去创建它们。 -这次 Service 会 *先于* 副本存在。这将实现调度器级别的 Service,能够使 Pod 分散创建(假定所有的 Node 都具有同样的容量),以及正确的环境变量: +能看到环境变量中并没有你创建的 Service 相关的值。这是因为副本的创建先于 Service。 +这样做的另一个缺点是,调度器可能会将所有 Pod 部署到同一台机器上,如果该机器宕机则整个 Service 都会离线。 +要改正的话,我们可以先终止这 2 个 Pod,然后等待 Deployment 去重新创建它们。 +这次 Service 会*先于*副本存在。这将实现调度器级别的 Pod 按 Service +分布(假定所有的节点都具有同样的容量),并提供正确的环境变量: ```shell kubectl scale deployment my-nginx --replicas=0; kubectl scale deployment my-nginx --replicas=2; @@ -274,7 +273,7 @@ my-nginx-3800858182-j4rm4 1/1 Running 0 5s 10.244.3.8 You may notice that the pods have different names, since they are killed and recreated. --> -可能注意到,Pod 具有不同的名称,因为它们被杀掉后并被重新创建。 +你可能注意到,Pod 具有不同的名称,这是因为它们是被重新创建的。 ```shell kubectl exec my-nginx-3800858182-e9ihh -- printenv | grep SERVICE @@ -293,8 +292,8 @@ KUBERNETES_SERVICE_PORT_HTTPS=443 Kubernetes offers a DNS cluster addon Service that automatically assigns dns names to other Services. You can check if it's running on your cluster: --> -Kubernetes 提供了一个 DNS 插件 Service,它使用 skydns 自动为其它 Service 指派 DNS 名字。 -如果它在集群中处于运行状态,可以通过如下命令来检查: +Kubernetes 提供了一个自动为其它 Service 分配 DNS 名字的 DNS 插件 Service。 +你可以通过如下命令检查它是否在工作: ```shell kubectl get services kube-dns --namespace=kube-system @@ -305,18 +304,15 @@ kube-dns ClusterIP 10.0.0.10 53/UDP,53/TCP 8m ``` -如果没有在运行,可以[启用它](https://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/dns/kube-dns/README.md#how-do-i-configure-it)。 -本段剩余的内容,将假设已经有一个 Service,它具有一个长久存在的 IP(my-nginx), -一个为该 IP 指派名称的 DNS 服务器。 这里我们使用 CoreDNS 集群插件(应用名为 `kube-dns`), -所以可以通过标准做法,使在集群中的任何 Pod 都能与该 Service 通信(例如:`gethostbyname()`)。 +本段剩余的内容假设你已经有一个拥有持久 IP 地址的 Service(my-nginx),以及一个为其 +IP 分配名称的 DNS 服务器。 这里我们使用 CoreDNS 集群插件(应用名为 `kube-dns`), +所以在集群中的任何 Pod 中,你都可以使用标准方法(例如:`gethostbyname()`)与该 Service 通信。 如果 CoreDNS 没有在运行,你可以参照 -[CoreDNS README](https://github.com/coredns/deployment/tree/master/kubernetes) 或者 -[安装 CoreDNS](/zh/docs/tasks/administer-cluster/coredns/#installing-coredns) 来启用它。 +[CoreDNS README](https://github.com/coredns/deployment/tree/master/kubernetes) +或者[安装 CoreDNS](/zh/docs/tasks/administer-cluster/coredns/#installing-coredns) 来启用它。 让我们运行另一个 curl 应用来进行测试: ```shell @@ -351,21 +347,21 @@ Till now we have only accessed the nginx server from within the cluster. Before * An nginx server configured to use the certificates * A [secret](/docs/concepts/configuration/secret/) that makes the certificates accessible to pods -You can acquire all these from the [nginx https example](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/https-nginx/). This requires having go and make tools installed. If you don't want to install those, then follow the manual steps later. In short: +You can acquire all these from the [nginx https example](https://github.com/kubernetes/examples/tree/master/staging/https-nginx/). This requires having go and make tools installed. If you don't want to install those, then follow the manual steps later. In short: --> ## 保护 Service {#securing-the-service} 到现在为止,我们只在集群内部访问了 Nginx 服务器。在将 Service 暴露到因特网之前,我们希望确保通信信道是安全的。 -为实现这一目的,可能需要: +为实现这一目的,需要: -* 用于 HTTPS 的自签名证书(除非已经有了一个识别身份的证书) +* 用于 HTTPS 的自签名证书(除非已经有了一个身份证书) * 使用证书配置的 Nginx 服务器 -* 使证书可以访问 Pod 的 [Secret](/zh/docs/concepts/configuration/secret/) +* 使 Pod 可以访问证书的 [Secret](/zh/docs/concepts/configuration/secret/) -你可以从 [Nginx https 示例](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/https-nginx/) -获取所有上述内容。你需要安装 go 和 make 工具。如果你不想安装这些软件,可以按照 -后文所述的手动执行步骤执行操作。简要过程如下: +你可以从 +[Nginx https 示例](https://github.com/kubernetes/examples/tree/master/staging/https-nginx/)获取所有上述内容。 +你需要安装 go 和 make 工具。如果你不想安装这些软件,可以按照后文所述的手动执行步骤执行操作。简要过程如下: ```shell make keys KEY=/tmp/nginx.key CERT=/tmp/nginx.crt @@ -385,19 +381,6 @@ nginxsecret kubernetes.io/tls 2 1m 以下是 configmap: ```shell @@ -420,9 +403,9 @@ Following are the manual steps to follow in case you run into problems running m 以下是你在运行 make 时遇到问题时要遵循的手动步骤(例如,在 Windows 上): ```shell -# Create a public private key pair +# 创建公钥和相对应的私钥 openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /d/tmp/nginx.key -out /d/tmp/nginx.crt -subj "/CN=my-nginx/O=my-nginx" -# Convert the keys to base64 encoding +# 对密钥实施 base64 编码 cat /d/tmp/nginx.crt | base64 cat /d/tmp/nginx.key | base64 ``` @@ -447,7 +430,7 @@ data: -现在使用文件创建 Secrets: +现在使用文件创建 Secret: ```shell kubectl apply -f nginxsecrets.yaml @@ -462,7 +445,7 @@ nginxsecret kubernetes.io/tls 2 1m -现在修改 nginx 副本,启动一个使用在秘钥中的证书的 HTTPS 服务器和 Service,暴露端口(80 和 443): +现在修改 nginx 副本以启动一个使用 Secret 中的证书的 HTTPS 服务器以及相应的用于暴露其端口(80 和 443)的 Service: {{< codenew file="service/networking/nginx-secure-app.yaml" >}} @@ -470,7 +453,7 @@ Now modify your nginx replicas to start an https server using the certificate in Noteworthy points about the nginx-secure-app manifest: - It contains both Deployment and Service specification in the same file. -- The [nginx server](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/https-nginx/default.conf) +- The [nginx server](https://github.com/kubernetes/examples/tree/master/staging/https-nginx/default.conf) serves HTTP traffic on port 80 and HTTPS traffic on 443, and nginx Service exposes both ports. - Each container has access to the keys through a volume mounted at `/etc/nginx/ssl`. @@ -478,10 +461,10 @@ Noteworthy points about the nginx-secure-app manifest: --> 关于 nginx-secure-app 清单,值得注意的几点如下: -- 它在相同的文件中包含了 Deployment 和 Service 的规约 -- [nginx 服务器](https://github.com/kubernetes/kubernetes/tree/{{< param "githubbranch" >}}/staging/https-nginx/default.conf) - 处理 80 端口上的 HTTP 流量,以及 443 端口上的 HTTPS 流量,Nginx Service 暴露了这两个端口。 -- 每个容器访问挂载在 /etc/nginx/ssl 卷上的秘钥。这需要在 Nginx 服务器启动之前安装好。 +- 它将 Deployment 和 Service 的规约放在了同一个文件中。 +- [Nginx 服务器](https://github.com/kubernetes/examples/tree/master/staging/https-nginx/default.conf)通过 + 80 端口处理 HTTP 流量,通过 443 端口处理 HTTPS 流量,而 Nginx Service 则暴露了这两个端口。 +- 每个容器能通过挂载在 `/etc/nginx/ssl` 的卷访问秘钥。卷和密钥需要在 Nginx 服务器启动*之前*配置好。 ```shell kubectl delete deployments,svc my-nginx; kubectl create -f ./nginx-secure-app.yaml @@ -508,7 +491,7 @@ Let's test this from a pod (the same secret is being reused for simplicity, the 注意最后一步我们是如何提供 `-k` 参数执行 curl 命令的,这是因为在证书生成时, 我们不知道任何关于运行 nginx 的 Pod 的信息,所以不得不在执行 curl 命令时忽略 CName 不匹配的情况。 通过创建 Service,我们连接了在证书中的 CName 与在 Service 查询时被 Pod 使用的实际 DNS 名字。 -让我们从一个 Pod 来测试(为了简化使用同一个秘钥,Pod 仅需要使用 nginx.crt 去访问 Service): +让我们从一个 Pod 来测试(为了方便,这里使用同一个 Secret,Pod 仅需要使用 nginx.crt 去访问 Service): {{< codenew file="service/networking/curlpod.yaml" >}} @@ -538,10 +521,10 @@ node has a public IP. --> ## 暴露 Service -对我们应用的某些部分,可能希望将 Service 暴露在一个外部 IP 地址上。 +对应用的某些部分,你可能希望将 Service 暴露在一个外部 IP 地址上。 Kubernetes 支持两种实现方式:NodePort 和 LoadBalancer。 -在上一段创建的 Service 使用了 `NodePort`,因此 Nginx https 副本已经就绪, -如果使用一个公网 IP,能够处理 Internet 上的流量。 +在上一段创建的 Service 使用了 `NodePort`,因此,如果你的节点有一个公网 +IP,那么 Nginx HTTPS 副本已经能够处理因特网上的流量。 ```shell kubectl get svc my-nginx -o yaml | grep nodePort -C 5 @@ -579,18 +562,18 @@ kubectl get nodes -o yaml | grep ExternalIP -C 1 type: ExternalIP allocatable: ... -$ curl https://: -k +$ curl https://: -k ...

Welcome to nginx!

``` -让我们重新创建一个 Service,使用一个云负载均衡器,只需要将 `my-nginx` Service 的 `Type` -由 `NodePort` 改成 `LoadBalancer`。 +让我们重新创建一个 Service 以使用云负载均衡器。 +将 `my-nginx` Service 的 `Type` 由 `NodePort` 改成 `LoadBalancer`: ```shell kubectl edit svc my-nginx @@ -616,17 +599,15 @@ output, in fact, so you'll need to do `kubectl describe service my-nginx` to see it. You'll see something like this: --> -在 `EXTERNAL-IP` 列指定的 IP 地址是在公网上可用的。`CLUSTER-IP` 只在集群/私有云网络中可用。 +在 `EXTERNAL-IP` 列中的 IP 地址能在公网上被访问到。`CLUSTER-IP` 只能从集群/私有云网络中访问。 -注意,在 AWS 上类型 `LoadBalancer` 创建一个 ELB,它使用主机名(比较长),而不是 IP。 -它太长以至于不能适配标准 `kubectl get svc` 的输出,事实上需要通过执行 `kubectl describe service my-nginx` 命令来查看它。 +注意,在 AWS 上,类型 `LoadBalancer` 的服务会创建一个 ELB,且 ELB 使用主机名(比较长),而不是 IP。 +ELB 的主机名太长以至于不能适配标准 `kubectl get svc` 的输出,所以需要通过执行 +`kubectl describe service my-nginx` 命令来查看它。 可以看到类似如下内容: ```shell kubectl describe service my-nginx -``` - -``` ... LoadBalancer Ingress: a320587ffd19711e5a37606cf4a74574-1142138393.us-east-1.elb.amazonaws.com ...