From 1e731dc4e6b6b36ac128695531029eec27da3215 Mon Sep 17 00:00:00 2001 From: chenghen Date: Fri, 27 Sep 2019 17:50:33 +0900 Subject: [PATCH] 1. Sync the service-networking folder from 1.14 version 2. Sync the service-networking folder files with 1.16 version en document 3. Changed some files structure for easily review 4. Add the necessary documents 5. Add the runtime-class file --- .../docs/concepts/containers/runtime-class.md | 392 ++++ .../concepts/services-networking/_index.md | 4 + ...ries-to-pod-etc-hosts-with-host-aliases.md | 141 +- .../connect-applications-service.md | 385 +++- .../services-networking/dns-pod-service.md | 487 ++--- .../ingress-controllers.md | 118 ++ .../concepts/services-networking/ingress.md | 729 ++++++++ .../services-networking/network-policies.md | 333 +++- .../concepts/services-networking/service.md | 1652 +++++++++++++++-- content/zh/docs/reference/glossary/ingress.md | 24 + content/zh/docs/reference/glossary/service.md | 25 + content/zh/examples/service/access/Dockerfile | 4 + .../zh/examples/service/access/frontend.conf | 11 + .../zh/examples/service/access/frontend.yaml | 39 + .../service/access/hello-application.yaml | 20 + .../service/access/hello-service.yaml | 12 + content/zh/examples/service/access/hello.yaml | 24 + .../service/load-balancer-example.yaml | 21 + .../service/networking}/curlpod.yaml | 5 +- .../service/networking/custom-dns.yaml | 20 + .../networking/dual-stack-default-svc.yaml | 11 + .../networking/dual-stack-ipv4-svc.yaml | 12 + .../networking/dual-stack-ipv6-lb-svc.yaml | 15 + .../networking/dual-stack-ipv6-svc.yaml | 12 + .../service/networking}/hostaliases-pod.yaml | 1 + .../service/networking}/ingress.yaml | 0 .../service/networking}/nginx-secure-app.yaml | 0 .../service/networking}/nginx-svc.yaml | 0 .../service/networking}/run-my-nginx.yaml | 0 .../zh/examples/service/nginx-service.yaml | 16 + 30 files changed, 3967 insertions(+), 546 deletions(-) create mode 100644 content/zh/docs/concepts/containers/runtime-class.md create mode 100644 content/zh/docs/concepts/services-networking/_index.md create mode 100644 content/zh/docs/concepts/services-networking/ingress-controllers.md create mode 100644 content/zh/docs/concepts/services-networking/ingress.md create mode 100755 content/zh/docs/reference/glossary/ingress.md create mode 100755 content/zh/docs/reference/glossary/service.md create mode 100644 content/zh/examples/service/access/Dockerfile create mode 100644 content/zh/examples/service/access/frontend.conf create mode 100644 content/zh/examples/service/access/frontend.yaml create mode 100644 content/zh/examples/service/access/hello-application.yaml create mode 100644 content/zh/examples/service/access/hello-service.yaml create mode 100644 content/zh/examples/service/access/hello.yaml create mode 100644 content/zh/examples/service/load-balancer-example.yaml rename content/zh/{docs/concepts/services-networking => examples/service/networking}/curlpod.yaml (87%) create mode 100644 content/zh/examples/service/networking/custom-dns.yaml create mode 100644 content/zh/examples/service/networking/dual-stack-default-svc.yaml create mode 100644 content/zh/examples/service/networking/dual-stack-ipv4-svc.yaml create mode 100644 content/zh/examples/service/networking/dual-stack-ipv6-lb-svc.yaml create mode 100644 content/zh/examples/service/networking/dual-stack-ipv6-svc.yaml rename content/zh/{docs/concepts/services-networking => examples/service/networking}/hostaliases-pod.yaml (93%) rename content/zh/{docs/concepts/services-networking => examples/service/networking}/ingress.yaml (100%) rename content/zh/{docs/concepts/services-networking => examples/service/networking}/nginx-secure-app.yaml (100%) rename content/zh/{docs/concepts/services-networking => examples/service/networking}/nginx-svc.yaml (100%) rename content/zh/{docs/concepts/services-networking => examples/service/networking}/run-my-nginx.yaml (100%) create mode 100644 content/zh/examples/service/nginx-service.yaml diff --git a/content/zh/docs/concepts/containers/runtime-class.md b/content/zh/docs/concepts/containers/runtime-class.md new file mode 100644 index 0000000000000..5ad67c0270d0d --- /dev/null +++ b/content/zh/docs/concepts/containers/runtime-class.md @@ -0,0 +1,392 @@ +--- +title: 容器运行时类(Runtime Class) +content_template: templates/concept +weight: 20 +--- + +{{% capture overview %}} + +{{< feature-state for_k8s_version="v1.14" state="beta" >}} + + + +这个文档主要说明了 RuntimeClass 资源和 kubernetes 指定容器运行时的功能。 + +{{< warning >}} + + +Kubernetes1.14 的 β 版的升级包含了 RuntimeClass 的 *破坏性* 的变更。 +如果用户在使用 Kubernetes1.14 以前的 RuntimeClass 版本, +请参考文档[从 RuntimeClass 的 α 版升级到β版](#upgrading-runtimeclass-from-alpha-to-beta)。 +{{< /warning >}} + +{{% /capture %}} + + +{{% capture body %}} + + + +## 关于RuntimeClass + +RuntimeClass 是可以让用户选择容器运行时的功能。用户通过设定容器运行时可以选择 Pod 的容器运行在那种容器运行时之上。 + + +## 使用场景 +用户可以为不同的 Pod 设定不同的 RuntimeClass ,以达到动态调整容器安全和容器性能间的平衡的目的。例如, +如果用户的一部分工作需要确保高安全性,那么可以选择调度Pod使用到硬件虚拟化的容器运行时。 +受益于硬件虚拟化带来的附加的容器隔离特性的同时,也会带来性能上的额外开销。 + +用户也可以通过这种方式,为Pod提供不同设定的同一种容器运行时。 + + + +### 设定 + +首先要先确认 RuntimeClass 功能的 Feature Gate 被设定为开启(默认是有效状态)。设定 Feature Gate 为有效的文档请参考[Feature Gates](/docs/reference/command-line-tools-reference/feature-gates/)。 +`RuntimeClass`的 Feature Gate 开启需要 ApiServer 和 kubelet 同时将相关配置开启。 + +1. 配置节点的 CRI。(依赖于容器运行时) +2. 创建相应的 RuntimeClass 资源。 + + +#### 1. 实现节点上的CRI设定。 + +通过 RuntimeClass 进行设定的有效化,依赖于 Container Runtime Interface (CRI) 组件。 +在用户环境中,CRI 的设定方法请参考([见下面](#cri-configuration))文档。 + +{{< note >}} +<!-- +RuntimeClass assumes a homogeneous node configuration across the cluster by default (which means +that all nodes are configured the same way with respect to container runtimes). To support +heterogenous node configurations, see [Scheduling](#scheduling) below. +--> + +默认情况下,RuntimeClass 被假设为所有节点上的配置均为一致。(这意味着所有的 Node 节点的容器运行时必须以相同的方式进行设定)。 +要支持不同配置构节点配置,请参见下面的[Scheduling](#scheduling)。 + +{{< /note >}} + + +配置需要具有相应的 `handler` 名称,被用于 RuntimeClass 的设定。 +被定义的 Handler 名称必须是有效的 DNS-1123 标准。(只能使用英文字母,数字 和 `-`)。 + + +#### 2. 创建对应的RuntimeClass资源 + +为了便于识别各个项目,安装配置的第一步需要每个项目有一个关联的 `handler` 名称。这样就可以为每个 `handler` 创建对应的 RuntimeClass 资源了。 + +所以当前 RuntimeClass 资源有两个重要的设定项。一个是 RuntimeClass 的名称( `metadata.name` )和 Handler (`handler`)。RuntimeClass 的资源定义可以参考下面的内容。 + +```yaml +apiVersion: node.k8s.io/v1beta1 # RuntimeClass is defined in the node.k8s.io API group +kind: RuntimeClass +metadata: + name: myclass # The name the RuntimeClass will be referenced by + # RuntimeClass is a non-namespaced resource +handler: myconfiguration # The name of the corresponding CRI configuration +``` + +{{< note >}} + +推荐只有集群管理员具有针对 RuntimeClass 的各项操作权限(create/update/patch/delete)。 +这通常是默认值。具体内容可以[授权概况](/docs/reference/access-authn-authz/authorization/)文档了解详细信息。 +{{< /note >}} + + +### 使用方法 + +一旦集群中的 RuntimeClass 的设定完成,接下来的使用就变得非常简单了。只需要设定 PodSpec 的 `runtimeClassName` 设定项。 +例如: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: mypod +spec: + runtimeClassName: myclass + # ... +``` + + + +这个设定将让Kubelet使用指定的 RuntimeClass 来运行 Pod。如果 RuntimeClass 不存在, 或者 CRI 不能执行相应的 Handler,Pod 将会变成`Failed`[状态](/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase)。 +请参考对应的相关[事件](/docs/tasks/debug-application-cluster/debug-application-introspection/)文档,确定错误信息。 + +如果 `runtimeClassName` 没有被设定的情况下,将会使用默认的 RuntimeHandler,这里的运行效果和 RuntimeClass 功能被禁止的情况下是一样的。 + + +### CRI的设定 + +CRI 运行时的相关设定详细内容请参考[CRI的安装](/docs/setup/cri/)。 + + +#### dockershim + +Kubernetes 的内置 dockershim CRI 不支持容器运行时 handlers。 + + +#### [containerd](https://containerd.io/) + +运行时 handler 可以通过 containerd 的配置文件 `/etc/containerd/config.toml` 进行设定。 +有效的 handlers 被设定在 runtimes 部分的下一层级。 + +``` +[plugins.cri.containerd.runtimes.${HANDLER_NAME}] +``` + + +`containerd` 的具体设定请参考下面的文档信息。 +https://github.com/containerd/cri/blob/master/docs/config.md + +#### [cri-o](https://cri-o.io/) + + +运行时处理程序通过cri-o的配置在 `/etc/crio/crio.conf` 中进行配置。 +有效的处理程序在[crio.runtime表](https://github.com/kubernetes-sigs/cri-o/blob/master/docs/crio.conf.5.md#crioruntime-table)下配置。 + +``` +[crio.runtime.runtimes.${HANDLER_NAME}] + runtime_path = "${PATH_TO_BINARY}" +``` + + +有关更多详细信息,请参见cri-o的配置文档: +https://github.com/kubernetes-sigs/cri-o/blob/master/cmd/crio/config.go + + + +### 调度 + +{{< feature-state for_k8s_version="v1.16" state="beta" >}} + + + +从Kubernetes v1.16开始,RuntimeClass 通过 `scheduling` 字段添加了对异构集群的支持。 +通过使用这些字段,可以确保将与此 RuntimeClass一 起运行的 Pod 调度到支持它的节点上。 +要使用计划支持,您必须启用 RuntimeClass [admission controller] [](默认值,自1.16开始)。 + +为了确保 Pod 被调度到支持特定 RuntimeClass 的节点上, +那组节点应该具有一个公共标签,然后由 `runtimeclass.scheduling.nodeSelector` 字段选择该标签。 +RuntimeClass 的 nodeSelector 在调度时与 Pod 的 nodeSelector 合并,有效地进行节点选择,并且调度到相应节点。 +如果有冲突,则将拒绝该 Pod 被调度。 + + + +如果受支持的节点被污染以防止其他 RuntimeClass 容器在该节点上运行,则可以向RuntimeClass添加 `tolerations` 设定。 +与 `nodeSelector` 一样,容忍度在接纳时与容器的容忍度合并,从而有效地吸收了每个容忍度的节点集的并集。 + +要了解有关配置节点选择器和容差的更多信息,请参阅[分配 Pod 到节点](/docs/concepts/configuration/assign-pod-node/)。 + +[准入控制器]: /docs/reference/access-authn-authz/admission-controllers/ + + + +### Pod 开销 + +{{< feature-state for_k8s_version="v1.16" state="alpha" >}} + + + +从 Kubernetes v1.16 开始,RuntimeClass 包含了对指定与运行 Pod 相关的开销的支持, +这是[`Pod 开销`](/docs/concepts/configuration/pod-overhead.md)功能的一部分。 +要使用 `PodOverhead` ,您必须确保 PodOverhead [功能](/docs/reference/command-line-tools-reference/feature-gates/) 已启用(默认情况下处于关闭状态)。 + +Pod 的开销是在 RuntimeClass 中通过 `Overhead` 字段定义的。 通过使用这些字段, +您可以使用此 RuntimeClass 指定运行 Pod 的开销,并确保在Kubernetes中考虑了这些开销。 + + + +### 将 RuntimeClass 从 Alpha 升级到 Beta + +RuntimeClass Beta 功能包括以下更改: + +- `node.k8s.io` API 组和 `runtimeclasses.node.k8s.io` 资源已从 `CustomResourceDefinition` 迁移到内置API。 +- 已在 RuntimeClass 定义中内联了 `spec`(即不再有RuntimeClassSpec)。 +- `runtimeHandler` 字段已重命名为 `handler`。 +- 所有 API 版本中现在都需要 `handler` 字段。 这意味着 Alpha API 中的 `runtimeHandler` 字段也是必须设定项。 +- `handler`字段必须是有效的DNS标签([RFC 1123](https://tools.ietf.org/html/rfc1123)),这意味着它不再包含 `.` 字符(在所有版本中)。 + 有效的处理程序匹配以下正则表达式:`^ [a-z0-9]([-a-z0-9] * [a-z0-9])?$`。 + + + +**需要采取的措施:** 要从 RuntimeClass 功能的 Alpha 版本升级到 Beta 版本,需要执行以下操作: + +- 在升级到v1.14之后,必须重新创建 RuntimeClass 资源,并且应该手动删除 runtimeclasses.node.k8s.io 的 CRD: + ``` + kubectl delete customresourcedefinitions.apiextensions.k8s.io runtimeclasses.node.k8s.io + ``` +- 在处理程序中具有未指定或为空的 `runtimeHandler` 字段或使用 `.` 字符的 Alpha RuntimeClass 不再有效, + 必须将其迁移到有效的处理程序配置中(请参见上文)。 + + + +### 进一步阅读 + +- [运行时类设计](https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/runtime-class.md) +- [RuntimeClass 计划设计](https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/runtime-class-scheduling.md) +- 了解有关 [Pod 开销](/docs/concepts/configuration/pod-overhead/) 概念 +- [Pod 开销功能设计](https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/20190226-pod-overhead.md) + +{{% /capture %}} diff --git a/content/zh/docs/concepts/services-networking/_index.md b/content/zh/docs/concepts/services-networking/_index.md new file mode 100644 index 0000000000000..b8cc1a2f5860c --- /dev/null +++ b/content/zh/docs/concepts/services-networking/_index.md @@ -0,0 +1,4 @@ +--- +title: "服务、负载均衡和联网" +weight: 80 +--- diff --git a/content/zh/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases.md b/content/zh/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases.md index b6862ef5c690b..26b5f5a70bfdc 100644 --- a/content/zh/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases.md +++ b/content/zh/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases.md @@ -1,49 +1,139 @@ --- -approvers: -- rickypai -- thockin title: 使用 HostAliases 向 Pod /etc/hosts 文件添加条目 -redirect_from: -- "/docs/user-guide/add-entries-to-pod-etc-hosts-with-host-aliases/" -- "/docs/user-guide/add-entries-to-pod-etc-hosts-with-host-aliases.md" +content_template: templates/concept +weight: 60 --- {{< toc >}} +{{% capture overview %}} + 当 DNS 配置以及其它选项不合理的时候,通过向 Pod 的 /etc/hosts 文件中添加条目,可以在 Pod 级别覆盖对主机名的解析。在 1.7 版本,用户可以通过 PodSpec 的 HostAliases 字段来添加这些自定义的条目。 建议通过使用 HostAliases 来进行修改,因为该文件由 Kubelet 管理,并且可以在 Pod 创建/重启过程中被重写。 +{{% /capture %}} +{{% capture body %}} + ## 默认 hosts 文件内容 让我们从一个 Nginx Pod 开始,给该 Pod 分配一个 IP: +```shell +kubectl run nginx --image nginx --generator=run-pod/v1 +``` + +```shell +pod/nginx created ``` -$ kubectl get pods --output=wide + + +检查Pod IP: + +```shell +kubectl get pods --output=wide +``` + +```shell NAME READY STATUS RESTARTS AGE IP NODE nginx 1/1 Running 0 13s 10.200.0.4 worker0 ``` + + +主机文件的内容如下所示: + +```shell +kubectl exec nginx -- cat /etc/hosts +``` +```none +# Kubernetes-managed hosts file. +127.0.0.1 localhost +::1 localhost ip6-localhost ip6-loopback +fe00::0 ip6-localnet +fe00::0 ip6-mcastprefix +fe00::1 ip6-allnodes +fe00::2 ip6-allrouters +10.200.0.4 nginx +``` + 默认,hosts 文件只包含 ipv4 和 ipv6 的样板内容,像 `localhost` 和主机名称。 + + ## 通过 HostAliases 增加额外的条目 +除了默认的样板内容,我们可以向 hosts 文件添加额外的条目,将 `foo.local`、 `bar.local` 解析为`127.0.0.1`, +将 `foo.remote`、 `bar.remote` 解析为 `10.1.2.3`,我们可以在 `.spec.hostAliases` 下为 Pod 添加 HostAliases。 + +{{< codenew file="service/networking/hostaliases-pod.yaml" >}} + -除了默认的样板内容,我们可以向 hosts 文件添加额外的条目,将 `foo.local`、 `bar.local` 解析为`127.0.0.1`,将 `foo.remote`、 `bar.remote` 解析为 `10.1.2.3`,我们可以在 `.spec.hostAliases` 下为 Pod 添加 HostAliases。 +可以使用以下命令启动此Pod: + +```shell +kubectl apply -f hostaliases-pod.yaml +``` -{{< code file="hostaliases-pod.yaml" >}} +```shell +pod/hostaliases-pod created +``` + + +检查Pod IP 和状态: + +```shell +kubectl get pod --output=wide +``` + +```shell +NAME READY STATUS RESTARTS AGE IP NODE +hostaliases-pod 0/1 Completed 0 6s 10.200.0.5 worker0 +``` + + hosts 文件的内容看起来类似如下这样: +```shell +kubectl logs hostaliases-pod ``` -$ kubectl logs hostaliases-pod + +```none # Kubernetes-managed hosts file. 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback @@ -51,25 +141,40 @@ fe00::0 ip6-localnet fe00::0 ip6-mcastprefix fe00::1 ip6-allnodes fe00::2 ip6-allrouters -10.200.0.4 hostaliases-pod -127.0.0.1 foo.local -127.0.0.1 bar.local -10.1.2.3 foo.remote -10.1.2.3 bar.remote -``` +10.200.0.5 hostaliases-pod +# Entries added by HostAliases. +127.0.0.1 foo.local bar.local +10.1.2.3 foo.remote bar.remote +``` + 在最下面额外添加了一些条目。 -## 限制 + ## 为什么 Kubelet 管理 hosts文件? kubelet [管理](https://github.com/kubernetes/kubernetes/issues/14633) Pod 中每个容器的 hosts 文件,避免 Docker 在容器已经启动之后去 [修改](https://github.com/moby/moby/issues/17190) 该文件。 因为该文件是托管性质的文件,无论容器重启或 Pod 重新调度,用户修改该 hosts 文件的任何内容,都会在 Kubelet 重新安装后被覆盖。因此,不建议修改该文件的内容。 + +{{% /capture %}} + 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 ae8609a469c96..19df8fd369b64 100644 --- a/content/zh/docs/concepts/services-networking/connect-applications-service.md +++ b/content/zh/docs/concepts/services-networking/connect-applications-service.md @@ -1,14 +1,23 @@ --- -approvers: -- caesarxuchao -- lavalamp -- thockin title: 应用连接到 Service +content_template: templates/concept +weight: 30 --- -{{< toc >}} +{{% capture overview %}} + ## Kubernetes 连接容器模型 @@ -29,37 +38,57 @@ Kubernetes 假设 Pod 可与其它 Pod 通信,不管它们在哪个主机上 该指南使用一个简单的 Nginx server 来演示并证明谈到的概念。同样的原则也体现在一个更加完整的 [Jenkins CI 应用](http://kubernetes.io/blog/2015/07/strong-simple-ssl-for-kubernetes.html) 中。 +{{% /capture %}} + +{{% capture body %}} + + ## 在集群中暴露 Pod 我们在之前的示例中已经做过,然而再让我重试一次,这次聚焦在网络连接的视角。 创建一个 Nginx Pod,指示它具有一个容器端口的说明: -{{< code file="run-my-nginx.yaml" >}} - +{{< codenew file="service/networking/run-my-nginx.yaml" >}} + 这使得可以从集群中任何一个节点来访问它。检查节点,该 Pod 正在运行: ```shell -$ kubectl create -f ./run-my-nginx.yaml -$ kubectl get pods -l run=my-nginx -o wide +kubectl apply -f ./run-my-nginx.yaml +kubectl get pods -l run=my-nginx -o wide +``` +``` NAME READY STATUS RESTARTS AGE IP NODE my-nginx-3800858182-jr4a2 1/1 Running 0 13s 10.244.3.4 kubernetes-minion-905m my-nginx-3800858182-kna2y 1/1 Running 0 13s 10.244.2.5 kubernetes-minion-ljyd ``` - + 检查 Pod 的 IP 地址: ```shell -$ kubectl get pods -l run=my-nginx -o yaml | grep podIP +kubectl get pods -l run=my-nginx -o yaml | grep podIP podIP: 10.244.3.4 podIP: 10.244.2.5 ``` + 应该能够通过 ssh 登录到集群中的任何一个节点上,使用 curl 也能调通所有 IP 地址。 需要注意的是,容器不会使用该节点上的 80 端口,也不会使用任何特定的 NAT 规则去路由流量到 Pod 上。 @@ -69,6 +98,15 @@ $ kubectl get pods -l run=my-nginx -o yaml | grep podIP 如果对此好奇,可以获取更多关于 [如何实现网络模型](/docs/concepts/cluster-administration/networking/#how-to-achieve-this) 的内容。 + ## 创建 Service @@ -83,28 +121,52 @@ Kubernetes Service 从逻辑上定义了运行在集群中的一组 Pod,这些 可以使用 `kubectl expose` 命令为 2个 Nginx 副本创建一个 Service: ```shell -$ kubectl expose deployment/my-nginx -service "my-nginx" exposed +kubectl expose deployment/my-nginx +``` +``` +service/my-nginx exposed ``` - + 这等价于使用 `kubectl create -f` 命令创建,对应如下的 yaml 文件: -{{< code file="nginx-svc.yaml" >}} - +{{< codenew file="service/networking/nginx-svc.yaml" >}} + 上述规约将创建一个 Service,对应具有标签 `run: my-nginx` 的 Pod,目标 TCP 端口 80,并且在一个抽象的 Service 端口(`targetPort`:容器接收流量的端口;`port`:抽象的 Service 端口,可以使任何其它 Pod 访问该 Service 的端口)上暴露。 查看 [Service API 对象](/docs/api-reference/{{< param "version" >}}/#service-v1-core) 了解 Service 定义支持的字段列表。 +查看你的 Service 资源: ```shell -$ kubectl get svc my-nginx -NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE -my-nginx 10.0.162.149 80/TCP 21s +kubectl get svc my-nginx +``` +``` +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +my-nginx ClusterIP 10.0.162.149 80/TCP 21s ``` - + 正如前面所提到的,一个 Service 由一组 backend Pod 组成。这些 Pod 通过 `endpoints` 暴露出来。 Service Selector 将持续评估,结果被 POST 到一个名称为 `my-nginx` 的 Endpoint 对象上。 @@ -112,48 +174,98 @@ Service Selector 将持续评估,结果被 POST 到一个名称为 `my-nginx` 检查该 Endpoint,注意到 IP 地址与在第一步创建的 Pod 是相同的。 ```shell -$ kubectl describe svc my-nginx +kubectl describe svc my-nginx +``` +``` Name: my-nginx Namespace: default Labels: run=my-nginx +Annotations: Selector: run=my-nginx Type: ClusterIP IP: 10.0.162.149 Port: 80/TCP Endpoints: 10.244.2.5:80,10.244.3.4:80 Session Affinity: None -No events. - -$ kubectl get ep my-nginx +Events: +``` +```shell +kubectl get ep my-nginx +``` +``` NAME ENDPOINTS AGE my-nginx 10.244.2.5:80,10.244.3.4:80 1m ``` - + 现在,能够从集群中任意节点上使用 curl 命令请求 Nginx Service `:` 。 -注意 Service IP 完全是虚拟的,它从来没有走过网络,如果对它如何工作的原理感到好奇,可以阅读更多关于 [服务代理](/docs/user-guide/services/#virtual-ips-and-service-proxies) 的内容。 +注意 Service IP 完全是虚拟的,它从来没有走过网络,如果对它如何工作的原理感到好奇, +可以阅读更多关于 [服务代理](/docs/user-guide/services/#virtual-ips-and-service-proxies) 的内容。 + ## 访问 Service -Kubernetes 支持两种主要的服务发现模式 —— 环境变量和 DNS。前者在单个节点上可用使用,然而后者必须使用 [kube-dns 集群插件](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/dns/README.md)。 +Kubernetes支持两种查找服务的主要模式: 环境变量和DNS。 前者开箱即用,而后者则需要[CoreDNS集群插件] +[CoreDNS 集群插件](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/dns/coredns). +{{< note >}} + +如果不需要服务环境变量(因为可能与预期的程序冲突,可能要处理的变量太多,或者仅使用DNS等),则可以通过在 +[pod spec](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#pod-v1-core)上将 `enableServiceLinks` 标志设置为 `false` 来禁用此模式。 + +{{< /note >}} + + + ### 环境变量 -当 Pod 在 Node 上运行时,kubelet 会为每个活跃的 Service 添加一组环境变量。这会有一个顺序的问题。想了解为何,检查正在运行的 Nginx Pod 的环境变量(Pod 名称将不会相同): +当 Pod 在 Node 上运行时,kubelet 会为每个活跃的 Service 添加一组环境变量。 +这会有一个顺序的问题。想了解为何,检查正在运行的 Nginx Pod 的环境变量(Pod 名称将不会相同): ```shell -$ kubectl exec my-nginx-3800858182-jr4a2 -- printenv | grep SERVICE +kubectl exec my-nginx-3800858182-jr4a2 -- printenv | grep SERVICE +``` +``` KUBERNETES_SERVICE_HOST=10.0.0.1 KUBERNETES_SERVICE_PORT=443 KUBERNETES_SERVICE_PORT_HTTPS=443 ``` - + 注意,还没有谈及到 Service。这是因为创建副本先于 Service。 这样做的另一个缺点是,调度器可能在同一个机器上放置所有 Pod,如果该机器宕机则所有的 Service 都会挂掉。 @@ -161,20 +273,26 @@ KUBERNETES_SERVICE_PORT_HTTPS=443 这次 Service 会 *先于* 副本存在。这将实现调度器级别的 Service,能够使 Pod 分散创建(假定所有的 Node 都具有同样的容量),以及正确的环境变量: ```shell -$ kubectl scale deployment my-nginx --replicas=0; kubectl scale deployment my-nginx --replicas=2; +kubectl scale deployment my-nginx --replicas=0; kubectl scale deployment my-nginx --replicas=2; -$ kubectl get pods -l run=my-nginx -o wide +kubectl get pods -l run=my-nginx -o wide +``` +``` NAME READY STATUS RESTARTS AGE IP NODE my-nginx-3800858182-e9ihh 1/1 Running 0 5s 10.244.2.7 kubernetes-minion-ljyd my-nginx-3800858182-j4rm4 1/1 Running 0 5s 10.244.3.8 kubernetes-minion-905m ``` - + 可能注意到,Pod 具有不同的名称,因为它们被杀掉后并被重新创建。 ```shell -$ kubectl exec my-nginx-3800858182-e9ihh -- printenv | grep SERVICE +kubectl exec my-nginx-3800858182-e9ihh -- printenv | grep SERVICE +``` +``` KUBERNETES_SERVICE_PORT=443 MY_NGINX_SERVICE_HOST=10.0.162.149 KUBERNETES_SERVICE_HOST=10.0.0.1 @@ -184,29 +302,44 @@ KUBERNETES_SERVICE_PORT_HTTPS=443 ### DNS - + Kubernetes 提供了一个 DNS 插件 Service,它使用 skydns 自动为其它 Service 指派 DNS 名字。 如果它在集群中处于运行状态,可以通过如下命令来检查: ```shell -$ kubectl get services kube-dns --namespace=kube-system -NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kube-dns 10.0.0.10 53/UDP,53/TCP 8m +kubectl get services kube-dns --namespace=kube-system +``` +``` +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kube-dns ClusterIP 10.0.0.10 53/UDP,53/TCP 8m ``` + - -如果没有在运行,可以 [启用它](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/dns/README.md#how-do-i-configure-it)。 +如果没有在运行,可以 [启用它](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/dns/kube-dns/README.md#how-do-i-configure-it)。 本段剩余的内容,将假设已经有一个 Service,它具有一个长久存在的 IP(my-nginx),一个为该 IP 指派名称的 DNS 服务器(kube-dns 集群插件),所以可以通过标准做法,使在集群中的任何 Pod 都能与该 Service 通信(例如:gethostbyname)。 让我们运行另一个 curl 应用来进行测试: ```shell -$ kubectl run curl --image=radial/busyboxplus:curl -i --tty +kubectl run curl --image=radial/busyboxplus:curl -i --tty +``` +``` Waiting for pod default/curl-131556218-9fnch to be running, status is Pending, pod ready: false Hit enter for command prompt ``` + 然后,按回车并执行命令 `nslookup my-nginx`: @@ -219,13 +352,21 @@ Name: my-nginx Address 1: 10.0.162.149 ``` + +## Service 安全 +到现在为止,我们只在集群内部访问了 Nginx server。在将 Service 暴露到 Internet 之前,我们希望确保通信信道是安全的。对于这可能需要: * https 自签名证书(除非已经有了一个识别身份的证书) * 使用证书配置的 Nginx server @@ -234,66 +375,144 @@ Address 1: 10.0.162.149 可以从 [Nginx https 示例](https://github.com/kubernetes/kubernetes/tree/{{< param "githubbranch" >}}/examples/https-nginx/) 获取所有上述内容,简明示例如下: ```shell -$ make keys secret KEY=/tmp/nginx.key CERT=/tmp/nginx.crt SECRET=/tmp/secret.json -$ kubectl create -f /tmp/secret.json -secret "nginxsecret" created -$ kubectl get secrets +make keys secret KEY=/tmp/nginx.key CERT=/tmp/nginx.crt SECRET=/tmp/secret.json +kubectl apply -f /tmp/secret.json +``` +``` +secret/nginxsecret created +``` +```shell +kubectl get secrets +``` +``` NAME TYPE DATA AGE default-token-il9rc kubernetes.io/service-account-token 1 1d nginxsecret Opaque 2 1m ``` + +以下是您在运行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 +cat /d/tmp/nginx.crt | base64 +cat /d/tmp/nginx.key | base64 +``` -现在修改 Nginx 副本,启动一个使用在秘钥中的证书的 https 服务器和 Servcie,都暴露端口(80 和 443): + +使用前面命令的输出来创建yaml文件,如下所示。 base64编码的值应全部放在一行上。 + +```yaml +apiVersion: "v1" +kind: "Secret" +metadata: + name: "nginxsecret" + namespace: "default" +data: + nginx.crt: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURIekNDQWdlZ0F3SUJBZ0lKQUp5M3lQK0pzMlpJTUEwR0NTcUdTSWIzRFFFQkJRVUFNQ1l4RVRBUEJnTlYKQkFNVENHNW5hVzU0YzNaak1SRXdEd1lEVlFRS0V3aHVaMmx1ZUhOMll6QWVGdzB4TnpFd01qWXdOekEzTVRKYQpGdzB4T0RFd01qWXdOekEzTVRKYU1DWXhFVEFQQmdOVkJBTVRDRzVuYVc1NGMzWmpNUkV3RHdZRFZRUUtFd2h1CloybHVlSE4yWXpDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBSjFxSU1SOVdWM0IKMlZIQlRMRmtobDRONXljMEJxYUhIQktMSnJMcy8vdzZhU3hRS29GbHlJSU94NGUrMlN5ajBFcndCLzlYTnBwbQppeW1CL3JkRldkOXg5UWhBQUxCZkVaTmNiV3NsTVFVcnhBZW50VWt1dk1vLzgvMHRpbGhjc3paenJEYVJ4NEo5Ci82UVRtVVI3a0ZTWUpOWTVQZkR3cGc3dlVvaDZmZ1Voam92VG42eHNVR0M2QURVODBpNXFlZWhNeVI1N2lmU2YKNHZpaXdIY3hnL3lZR1JBRS9mRTRqakxCdmdONjc2SU90S01rZXV3R0ljNDFhd05tNnNTSzRqYUNGeGpYSnZaZQp2by9kTlEybHhHWCtKT2l3SEhXbXNhdGp4WTRaNVk3R1ZoK0QrWnYvcW1mMFgvbVY0Rmo1NzV3ajFMWVBocWtsCmdhSXZYRyt4U1FVQ0F3RUFBYU5RTUU0d0hRWURWUjBPQkJZRUZPNG9OWkI3YXc1OUlsYkROMzhIYkduYnhFVjcKTUI4R0ExVWRJd1FZTUJhQUZPNG9OWkI3YXc1OUlsYkROMzhIYkduYnhFVjdNQXdHQTFVZEV3UUZNQU1CQWY4dwpEUVlKS29aSWh2Y05BUUVGQlFBRGdnRUJBRVhTMW9FU0lFaXdyMDhWcVA0K2NwTHI3TW5FMTducDBvMm14alFvCjRGb0RvRjdRZnZqeE04Tzd2TjB0clcxb2pGSW0vWDE4ZnZaL3k4ZzVaWG40Vm8zc3hKVmRBcStNZC9jTStzUGEKNmJjTkNUekZqeFpUV0UrKzE5NS9zb2dmOUZ3VDVDK3U2Q3B5N0M3MTZvUXRUakViV05VdEt4cXI0Nk1OZWNCMApwRFhWZmdWQTRadkR4NFo3S2RiZDY5eXM3OVFHYmg5ZW1PZ05NZFlsSUswSGt0ejF5WU4vbVpmK3FqTkJqbWZjCkNnMnlwbGQ0Wi8rUUNQZjl3SkoybFIrY2FnT0R4elBWcGxNSEcybzgvTHFDdnh6elZPUDUxeXdLZEtxaUMwSVEKQ0I5T2wwWW5scE9UNEh1b2hSUzBPOStlMm9KdFZsNUIyczRpbDlhZ3RTVXFxUlU9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" + nginx.key: "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ2RhaURFZlZsZHdkbFIKd1V5eFpJWmVEZWNuTkFhbWh4d1NpeWF5N1AvOE9ta3NVQ3FCWmNpQ0RzZUh2dGtzbzlCSzhBZi9WemFhWm9zcApnZjYzUlZuZmNmVUlRQUN3WHhHVFhHMXJKVEVGSzhRSHA3VkpMcnpLUC9QOUxZcFlYTE0yYzZ3MmtjZUNmZitrCkU1bEVlNUJVbUNUV09UM3c4S1lPNzFLSWVuNEZJWTZMMDUrc2JGQmd1Z0ExUE5JdWFubm9UTWtlZTRuMG4rTDQKb3NCM01ZUDhtQmtRQlAzeE9JNHl3YjREZXUraURyU2pKSHJzQmlIT05Xc0RadXJFaXVJMmdoY1kxeWIyWHI2UAozVFVOcGNSbC9pVG9zQngxcHJHclk4V09HZVdPeGxZZmcvbWIvNnBuOUYvNWxlQlkrZStjSTlTMkQ0YXBKWUdpCkwxeHZzVWtGQWdNQkFBRUNnZ0VBZFhCK0xkbk8ySElOTGo5bWRsb25IUGlHWWVzZ294RGQwci9hQ1Zkank4dlEKTjIwL3FQWkUxek1yall6Ry9kVGhTMmMwc0QxaTBXSjdwR1lGb0xtdXlWTjltY0FXUTM5SjM0VHZaU2FFSWZWNgo5TE1jUHhNTmFsNjRLMFRVbUFQZytGam9QSFlhUUxLOERLOUtnNXNrSE5pOWNzMlY5ckd6VWlVZWtBL0RBUlBTClI3L2ZjUFBacDRuRWVBZmI3WTk1R1llb1p5V21SU3VKdlNyblBESGtUdW1vVlVWdkxMRHRzaG9reUxiTWVtN3oKMmJzVmpwSW1GTHJqbGtmQXlpNHg0WjJrV3YyMFRrdWtsZU1jaVlMbjk4QWxiRi9DSmRLM3QraTRoMTVlR2ZQegpoTnh3bk9QdlVTaDR2Q0o3c2Q5TmtEUGJvS2JneVVHOXBYamZhRGR2UVFLQmdRRFFLM01nUkhkQ1pKNVFqZWFKClFGdXF4cHdnNzhZTjQyL1NwenlUYmtGcVFoQWtyczJxWGx1MDZBRzhrZzIzQkswaHkzaE9zSGgxcXRVK3NHZVAKOWRERHBsUWV0ODZsY2FlR3hoc0V0L1R6cEdtNGFKSm5oNzVVaTVGZk9QTDhPTm1FZ3MxMVRhUldhNzZxelRyMgphRlpjQ2pWV1g0YnRSTHVwSkgrMjZnY0FhUUtCZ1FEQmxVSUUzTnNVOFBBZEYvL25sQVB5VWs1T3lDdWc3dmVyClUycXlrdXFzYnBkSi9hODViT1JhM05IVmpVM25uRGpHVHBWaE9JeXg5TEFrc2RwZEFjVmxvcG9HODhXYk9lMTAKMUdqbnkySmdDK3JVWUZiRGtpUGx1K09IYnRnOXFYcGJMSHBzUVpsMGhucDBYSFNYVm9CMUliQndnMGEyOFVadApCbFBtWmc2d1BRS0JnRHVIUVV2SDZHYTNDVUsxNFdmOFhIcFFnMU16M2VvWTBPQm5iSDRvZUZKZmcraEppSXlnCm9RN3hqWldVR3BIc3AyblRtcHErQWlSNzdyRVhsdlhtOElVU2FsbkNiRGlKY01Pc29RdFBZNS9NczJMRm5LQTQKaENmL0pWb2FtZm1nZEN0ZGtFMXNINE9MR2lJVHdEbTRpb0dWZGIwMllnbzFyb2htNUpLMUI3MkpBb0dBUW01UQpHNDhXOTVhL0w1eSt5dCsyZ3YvUHM2VnBvMjZlTzRNQ3lJazJVem9ZWE9IYnNkODJkaC8xT2sybGdHZlI2K3VuCnc1YytZUXRSTHlhQmd3MUtpbGhFZDBKTWU3cGpUSVpnQWJ0LzVPbnlDak9OVXN2aDJjS2lrQ1Z2dTZsZlBjNkQKckliT2ZIaHhxV0RZK2Q1TGN1YSt2NzJ0RkxhenJsSlBsRzlOZHhrQ2dZRUF5elIzT3UyMDNRVVV6bUlCRkwzZAp4Wm5XZ0JLSEo3TnNxcGFWb2RjL0d5aGVycjFDZzE2MmJaSjJDV2RsZkI0VEdtUjZZdmxTZEFOOFRwUWhFbUtKCnFBLzVzdHdxNWd0WGVLOVJmMWxXK29xNThRNTBxMmk1NVdUTThoSDZhTjlaMTltZ0FGdE5VdGNqQUx2dFYxdEYKWSs4WFJkSHJaRnBIWll2NWkwVW1VbGc9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K" +``` -{{< code file="nginx-secure-app.yaml" >}} + +现在使用文件创建 secrets: +```shell +kubectl apply -f nginxsecrets.yaml +kubectl get secrets +``` +``` +NAME TYPE DATA AGE +default-token-il9rc kubernetes.io/service-account-token 1 1d +nginxsecret Opaque 2 1m +``` + -关于 nginx-secure-app manifest 值得注意的点如下: +现在修改 Nginx 副本,启动一个使用在秘钥中的证书的 https 服务器和 Servcie,都暴露端口(80 和 443): + +{{< codenew file="service/networking/nginx-secure-app.yaml" >}} + + +关于 nginx-secure-app manifest 值得注意的点如下: - 它在相同的文件中包含了 Deployment 和 Service 的规格 - [Nginx server](https://github.com/kubernetes/kubernetes/tree/{{< param "githubbranch" >}}/examples/https-nginx/default.conf) 处理 80 端口上的 http 流量,以及 443 端口上的 https 流量,Nginx Service 暴露了这两个端口。 - 每个容器访问挂载在 /etc/nginx/ssl 卷上的秘钥。这需要在 Nginx server 启动之前安装好。 ```shell -$ kubectl delete deployments,svc my-nginx; kubectl create -f ./nginx-secure-app.yaml +kubectl delete deployments,svc my-nginx; kubectl create -f ./nginx-secure-app.yaml ``` - + 这时可以从任何节点访问到 Nginx server。 ```shell -$ kubectl get pods -o yaml | grep -i podip +kubectl get pods -o yaml | grep -i podip podIP: 10.244.3.5 node $ curl -k https://10.244.3.5 ...

Welcome to nginx!

``` - + 注意最后一步我们是如何提供 `-k` 参数执行 curl命令的,这是因为在证书生成时,我们不知道任何关于运行 Nginx 的 Pod 的信息,所以不得不在执行 curl 命令时忽略 CName 不匹配的情况。 通过创建 Service,我们连接了在证书中的 CName 与在 Service 查询时被 Pod使用的实际 DNS 名字。 让我们从一个 Pod 来测试(为了简化使用同一个秘钥,Pod 仅需要使用 nginx.crt 去访问 Service): -{{< code file="curlpod.yaml" >}} +{{< codenew file="service/networking/curlpod.yaml" >}} ```shell -$ kubectl create -f ./curlpod.yaml -$ kubectl get pods -l app=curlpod +kubectl apply -f ./curlpod.yaml +kubectl get pods -l app=curlpod +``` +``` NAME READY STATUS RESTARTS AGE curl-deployment-1515033274-1410r 1/1 Running 0 1m -$ kubectl exec curl-deployment-1515033274-1410r -- curl https://my-nginx --cacert /etc/nginx/ssl/nginx.crt +``` +```shell +kubectl exec curl-deployment-1515033274-1410r -- curl https://my-nginx --cacert /etc/nginx/ssl/nginx.crt ... Welcome to nginx! ... ``` + ## 暴露 Service @@ -302,7 +521,7 @@ Kubernetes 支持两种实现方式:NodePort 和 LoadBalancer。 在上一段创建的 Service 使用了 `NodePort`,因此 Nginx https 副本已经就绪,如果使用一个公网 IP,能够处理 Internet 上的流量。 ```shell -$ kubectl get svc my-nginx -o yaml | grep nodePort -C 5 +kubectl get svc my-nginx -o yaml | grep nodePort -C 5 uid: 07191fb3-f61a-11e5-8ae5-42010af00002 spec: clusterIP: 10.0.162.149 @@ -319,8 +538,9 @@ spec: targetPort: 443 selector: run: my-nginx - -$ kubectl get nodes -o yaml | grep ExternalIP -C 1 +``` +```shell +kubectl get nodes -o yaml | grep ExternalIP -C 1 - address: 104.197.41.11 type: ExternalIP allocatable: @@ -335,22 +555,35 @@ $ curl https://: -k

Welcome to nginx!

``` - + 让我们重新创建一个 Service,使用一个云负载均衡器,只需要将 `my-nginx` Service 的 `Type` 由 `NodePort` 改成 `LoadBalancer`。 ```shell -$ kubectl edit svc my-nginx -$ kubectl get svc my-nginx -NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE -my-nginx 10.0.162.149 162.222.184.144 80/TCP,81/TCP,82/TCP 21s - -$ curl https:// -k +kubectl edit svc my-nginx +kubectl get svc my-nginx +``` +``` +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +my-nginx ClusterIP 10.0.162.149 162.222.184.144 80/TCP,81/TCP,82/TCP 21s +``` +``` +curl https:// -k ... Welcome to nginx! ``` + 在 `EXTERNAL-IP` 列指定的 IP 地址是在公网上可用的。`CLUSTER-IP` 只在集群/私有云网络中可用。 @@ -359,13 +592,25 @@ $ curl https:// -k 可以看到类似如下内容: ```shell -$ kubectl describe service my-nginx +kubectl describe service my-nginx ... LoadBalancer Ingress: a320587ffd19711e5a37606cf4a74574-1142138393.us-east-1.elb.amazonaws.com ... ``` -## 进一步阅读 +{{% /capture %}} + +{{% capture whatsnext %}} + + Kubernetes 也支持联合 Service,能够跨多个集群和云提供商,为 Service 提供逐步增强的可用性、更优的容错、更好的可伸缩性。 查看 [联合 Service 用户指南](/docs/concepts/cluster-administration/federation-service-discovery/) 获取更进一步信息。 + +{{% /capture %}} \ No newline at end of file diff --git a/content/zh/docs/concepts/services-networking/dns-pod-service.md b/content/zh/docs/concepts/services-networking/dns-pod-service.md index b26c85edf0f95..ae53b2ca8f0d8 100644 --- a/content/zh/docs/concepts/services-networking/dns-pod-service.md +++ b/content/zh/docs/concepts/services-networking/dns-pod-service.md @@ -1,23 +1,48 @@ --- -approvers: -- davidopp -- thockin -title: DNS Pod 与 Service -redirect_from: -- "/docs/admin/dns/" -- "/docs/admin/dns.html" +title: Pod 与 Service 的 DNS +content_template: templates/concept +weight: 20 --- +{{% capture overview %}} + +该页面概述了Kubernetes对DNS的支持。 +{{% /capture %}} +{{% capture body %}} + ## 介绍 -Kubernetes 从 1.3 版本起, DNS 是内置的服务,通过插件管理器 [集群插件](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/README.md) 自动被启动。 +Kubernetes DNS 在群集上调度 DNS Pod 和服务,并配置 kubelet 以告知各个容器使用 DNS 服务的 IP 来解析 DNS 名称。 -Kubernetes DNS 在集群中调度 DNS Pod 和 Service ,配置 kubelet 以通知个别容器使用 DNS Service 的 IP 解析 DNS 名字。 + ## 怎样获取 DNS 名字? @@ -29,52 +54,87 @@ Kubernetes DNS 在集群中调度 DNS Pod 和 Service ,配置 kubelet 以通 运行在Namespace `bar` 中的一个 Pod,可以简单地通过 DNS 查询 `foo` 来找到该 Service。 运行在 Namespace `quux` 中的一个 Pod 可以通过 DNS 查询 `foo.bar` 找到该 Service。 - +以下各节详细介绍了受支持的记录类型和支持的布局。 其中代码部分的布局,名称或查询命令均被视为实现细节,如有更改,恕不另行通知。 +有关最新规范请查看 +[Kubernetes 基于 DNS 的服务发现](https://github.com/kubernetes/dns/blob/master/docs/specification.md). ## 支持的 DNS 模式 下面各段详细说明支持的记录类型和布局。 如果任何其它的布局、名称或查询,碰巧也能够使用,这就需要研究下它们的实现细节,以免后续修改它们又不能使用了。 + ### Service #### A 记录 -“正常” Service(除了 Headless Service)会以 `my-svc.my-namespace.svc.cluster.local` 这种名字的形式被指派一个 DNS A 记录。这会解析成该 Service 的 Cluster IP。 +“正常” Service(除了 Headless Service)会以 `my-svc.my-namespace.svc.cluster-domain.example` 这种名字的形式被指派一个 DNS A 记录。 +这会解析成该 Service 的 Cluster IP。 -“Headless” Service(没有Cluster IP)也会以 `my-svc.my-namespace.svc.cluster.local` 这种名字的形式被指派一个 DNS A 记录。 +“Headless” Service(没有Cluster IP)也会以 `my-svc.my-namespace.svc.cluster-domain.example` 这种名字的形式被指派一个 DNS A 记录。 不像正常 Service,它会解析成该 Service 选择的一组 Pod 的 IP。 希望客户端能够使用这一组 IP,否则就使用标准的 round-robin 策略从这一组 IP 中进行选择。 + #### SRV 记录 命名端口需要创建 SRV 记录,这些端口是正常 Service或 [Headless Services](/docs/concepts/services-networking/service/#headless-services) 的一部分。 -对每个命名端口,SRV 记录具有 `_my-port-name._my-port-protocol.my-svc.my-namespace.svc.cluster.local` 这种形式。 -对普通 Service,这会被解析成端口号和 CNAME:`my-svc.my-namespace.svc.cluster.local`。 -对 Headless Service,这会被解析成多个结果,Service 对应的每个 backend Pod 各一个,包含 `auto-generated-name.my-svc.my-namespace.svc.cluster.local` 这种形式 Pod 的端口号和 CNAME。 +对每个命名端口,SRV 记录具有 `_my-port-name._my-port-protocol.my-svc.my-namespace.svc.cluster-domain.example` 这种形式。 +对普通 Service,这会被解析成端口号和 CNAME:`my-svc.my-namespace.svc.cluster-domain.example`。 +对 Headless Service,这会被解析成多个结果,Service 对应的每个 backend Pod 各一个, +包含 `auto-generated-name.my-svc.my-namespace.svc.cluster-domain.example` 这种形式 Pod 的端口号和 CNAME。 -#### 后向兼容性 -上一版本的 kube-dns 使用 `my-svc.my-namespace.cluster.local` 这种形式的名字(后续会增加 'svc' 这一级),以后这将不再被支持。 +## Pods + -#### 基于 Pod hostname、subdomain 字段的 A 记录和主机名 +### Pod的 hostname 和 subdomain 字段 当前,创建 Pod 后,它的主机名是该 Pod 的 `metadata.name` 值。 @@ -82,18 +142,15 @@ Services](/docs/concepts/services-networking/service/#headless-services) 的一 如果为 Pod 配置了 annotation,会优先使用 Pod 的名称作为主机名。 例如,给定一个 Pod,它具有 annotation `pod.beta.kubernetes.io/hostname: my-pod-name`,该 Pod 的主机名被设置为 “my-pod-name”。 - - 在 v1.3 版本中,PodSpec 具有 `hostname` 字段,可以用来指定 Pod 的主机名。这个字段的值优先于 annotation `pod.beta.kubernetes.io/hostname`。 在 v1.2 版本中引入了 beta 特性,用户可以为 Pod 指定 annotation,其中 `pod.beta.kubernetes.io/subdomain` 指定了 Pod 的子域名。 最终的域名将是 “...svc.”。 举个例子,Pod 的主机名 annotation 设置为 “foo”,子域名 annotation 设置为 “bar”,在 Namespace “my-namespace” 中对应的 FQDN 为 “foo.bar.my-namespace.svc.cluster.local”。 - - 在 v1.3 版本中,PodSpec 具有 `subdomain` 字段,可以用来指定 Pod 的子域名。 这个字段的值优先于 annotation `pod.beta.kubernetes.io/subdomain` 的值。 +实例: ```yaml apiVersion: v1 kind: Service @@ -104,9 +161,9 @@ spec: name: busybox clusterIP: None ports: - - name: foo # Actually, no port is needed. - port: 1234 - targetPort: 1234 + - name: foo # Actually, no port is needed. + port: 1234 + targetPort: 1234 --- apiVersion: v1 kind: Pod @@ -118,7 +175,7 @@ spec: hostname: busybox-1 subdomain: default-subdomain containers: - - image: busybox + - image: busybox:1.28 command: - sleep - "3600" @@ -134,44 +191,103 @@ spec: hostname: busybox-2 subdomain: default-subdomain containers: - - image: busybox + - image: busybox:1.28 command: - sleep - "3600" name: busybox ``` - + 如果 Headless Service 与 Pod 在同一个 Namespace 中,它们具有相同的子域名,集群的 KubeDNS 服务器也会为该 Pod 的完整合法主机名返回 A 记录。 -在同一个 Namespace 中,给定一个主机名为 “busybox-1” 的 Pod,子域名设置为 “default-subdomain”,名称为 “default-subdomain” 的 Headless Service ,Pod 将看到自己的 FQDN 为 “busybox-1.default-subdomain.my-namespace.svc.cluster.local”。 +例如,在同一个 Namespace 中,给定一个主机名为 “busybox-1” 的 Pod,子域名设置为 “default-subdomain”,名称为 “default-subdomain” 的 Headless Service ,Pod 将看到自己的 FQDN 为 “busybox-1.default-subdomain.my-namespace.svc.cluster.local”。 DNS 会为那个名字提供一个 A 记录,指向该 Pod 的 IP。 “busybox1” 和 “busybox2” 这两个 Pod 分别具有它们自己的 A 记录。 + + +端点对象可以为任何端点地址及其 IP 指定 `hostname`。 + +{{< note >}} + + -在Kubernetes v1.2 版本中,`Endpoints` 对象也具有 annotation `endpoints.beta.kubernetes.io/hostnames-map`。 -它的值是 map[string(IP)][endpoints.HostRecord] 的 JSON 格式,例如: '{"10.245.1.6":{HostName: "my-webserver"}}'。 +因为没有为 Pod 名称创建A记录,所以要创建 Pod 的 A 记录需要 `hostname` 。 -如果是 Headless Service 的 `Endpoints`,会以 ...svc. 的格式创建 A 记录。 -对示例中的 JSON 字符串,如果 `Endpoints` 是为名称为 “bar” 的 Headless Service 而创建的,其中一个 `Endpoints` 的 IP 是 “10.245.1.6”,则会创建一个名称为 “my-webserver.bar.my-namespace.svc.cluster.local” 的 A 记录,该 A 记录查询将返回 “10.245.1.6”。 +没有 `hostname` 但带有 `subdomain` 的 Pod 只会为指向Pod的IP地址的 headless 服务创建 A 记录(`default-subdomain.my-namespace.svc.cluster-domain.example`)。 +另外,除非在服务上设置了 `publishNotReadyAddresses=True`,否则 Pod 需要准备好 A 记录。 +{{< /note >}} -`Endpoints` annotation 通常没必要由最终用户指定,但可以被内部的 Service Controller 用来提供上述功能。 + -在 v1.3 版本中,`Endpoints` 对象可以为任何 endpoint 指定 `hostname` 和 IP。 -`hostname` 字段优先于通过 `endpoints.beta.kubernetes.io/hostnames-map` annotation 指定的主机名。 +- "`Default`": Pod从运行所在的节点继承名称解析配置。 + 参考 [相关讨论](/docs/tasks/administer-cluster/dns-custom-nameservers/#inheriting-dns-from-the-node) 获取更多信息。 +- "`ClusterFirst`": 与配置的群集域后缀不匹配的任何DNS查询(例如 “www.kubernetes.io” )都将转发到从节点继承的上游名称服务器。 群集管理员可能配置了额外的存根域和上游DNS服务器。 + See [相关讨论](/docs/tasks/administer-cluster/dns-custom-nameservers/#impacts-on-pods) 获取如何 DNS 的查询和处理信息的相关资料。 +- "`ClusterFirstWithHostNet`": 对于与 hostNetwork 一起运行的 Pod,应显式设置其DNS策略 "`ClusterFirstWithHostNet`"。 +- "`None`": 它允许 Pod 忽略 Kubernetes 环境中的 DN S设置。 应该使用 Pod Spec 中的 `dnsConfig` 字段提供所有 DNS 设置。 -在 v1.3 版本中,下面的 annotation 是过时的:`pod.beta.kubernetes.io/hostname`、`pod.beta.kubernetes.io/subdomain`、`endpoints.beta.kubernetes.io/hostnames-map`。 +{{< note >}} + +"Default" 不是默认的 DNS 策略。 如果未明确指定 `dnsPolicy`,则使用 “ClusterFirst”。 +{{< /note >}} -## 如何测试它是否可以使用? -### 创建一个简单的 Pod 作为测试环境 + -创建 `busybox.yaml` 文件,内容如下: +下面的示例显示了一个Pod,其DNS策略设置为 "`ClusterFirstWithHostNet`",因为它已将 `hostNetwork` 设置为 `true`。 ```yaml apiVersion: v1 @@ -181,239 +297,132 @@ metadata: namespace: default spec: containers: - - image: busybox + - image: busybox:1.28 command: - sleep - "3600" imagePullPolicy: IfNotPresent name: busybox restartPolicy: Always + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet ``` + -### 等待这个 Pod 变成运行状态 +### Pod 的 DNS 设定 -获取它的状态,执行如下命令: +Pod 的 DNS 配置可让用户对 Pod 的 DNS 设置进行更多控制。 -``` -kubectl get pods busybox -``` +`dnsConfig` 字段是可选的,它可以与任何 `dnsPolicy` 设置一起使用。 +但是,当 Pod 的 `dnsPolicy` 设置为 "`None`" 时,必须指定 `dnsConfig` 字段。 +用户可以在 `dnsConfig` 字段中指定以下属性: + -可以看到如下内容: +- `nameservers`: 将用作于 Pod 的 DNS 服务器的 IP 地址列表。最多可以指定3个 IP 地址。 当 Pod 的 `dnsPolicy` 设置为 "`None`" 时,列表必须至少包含一个IP地址,否则此属性是可选的。列出的服务器将合并到从指定的 DNS 策略生成的基本名称服务器,并删除重复的地址。 +- `searches`: 用于在 Pod 中查找主机名的 DNS 搜索域的列表。此属性是可选的。指定后,提供的列表将合并到根据所选 DNS 策略生成的基本搜索域名中。 + 重复的域名将被删除。 +   Kubernetes最多允许6个搜索域。 +- `options`: 对象的可选列表,其中每个对象可能具有 `name` 属性(必需)和 `value` 属性(可选)。 此属性中的内容将合并到从指定的 DNS 策略生成的选项。 + 重复的条目将被删除。 -``` -NAME READY STATUS RESTARTS AGE -busybox 1/1 Running 0 -``` + +以下是具有自定义DNS设置的Pod示例: +{{< codenew file="service/networking/custom-dns.yaml" >}} -### 验证 DNS 已经生效 + -一旦 Pod 处于运行中状态,可以在测试环境中执行如下 nslookup 查询: +创建上面的Pod后,容器 `test` 会在其 `/etc/resolv.conf` 文件中获取以下内容: ``` -kubectl exec -ti busybox -- nslookup kubernetes.default +nameserver 1.2.3.4 +search ns1.svc.cluster-domain.example my.dns.search.suffix +options ndots:2 edns0 ``` -可以看到类似如下的内容: + +对于IPv6设置,搜索路径和名称服务器应按以下方式设置: +```shell +kubectl exec -it dns-example -- cat /etc/resolv.conf ``` -Server: 10.0.0.10 -Address 1: 10.0.0.10 - -Name: kubernetes.default -Address 1: 10.0.0.1 -``` - - - -如果看到了,说明 DNS 已经可以正确工作了。 - -### 问题排查技巧 - -如果执行 nslookup 命令失败,检查如下内容: -#### 先检查本地 DNS 配置 - -查看配置文件 resolv.conf。(关于更多信息,参考下面的 “从 Node 继承 DNS” 和 “已知问题”。) - -``` -kubectl exec busybox cat /etc/resolv.conf -``` - - - -按照如下方法(注意搜索路径可能会因为云提供商不同而变化)验证搜索路径和 Name Server 的建立: - -``` -search default.svc.cluster.local svc.cluster.local cluster.local google.internal c.gce_project_id.internal -nameserver 10.0.0.10 + +有以下输出: +```shell +nameserver fd00:79:30::a +search default.svc.cluster-domain.example svc.cluster-domain.example cluster-domain.example options ndots:5 ``` + -#### 快速诊断 - -出现类似如下指示的错误,说明 kube-dns 插件或相关 Service 存在问题: - -``` -$ kubectl exec -ti busybox -- nslookup kubernetes.default -Server: 10.0.0.10 -Address 1: 10.0.0.10 - -nslookup: can't resolve 'kubernetes.default' -``` - - - -或者 - -``` -$ kubectl exec -ti busybox -- nslookup kubernetes.default -Server: 10.0.0.10 -Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local - -nslookup: can't resolve 'kubernetes.default' -``` - - - -#### 检查是否 DNS Pod 正在运行 - -使用 `kubectl get pods` 命令验证 DNS Pod 正在运行: - -``` -kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -``` - - - -应该能够看到类似如下信息: - -``` -NAME READY STATUS RESTARTS AGE -... -kube-dns-v19-ezo1y 3/3 Running 0 1h -... -``` - - - -如果看到没有 Pod 运行,或 Pod 失败/结束,DNS 插件不能默认部署到当前的环境,必须手动部署。 - -#### 检查 DNS Pod 中的错误信息 - -使用 `kubectl logs` 命令查看 DNS 后台进程的日志: - -``` -kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c kubedns -kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c dnsmasq -kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c healthz -``` - - - -查看是否有任何可疑的日志。在行开头的字母 W、E、F 分别表示 警告、错误、失败。请搜索具有这些日志级别的日志行,通过 [Kubernetes 问题](https://github.com/kubernetes/kubernetes/issues) 报告意外的错误。 - -#### DNS 服务是否运行? - -通过使用 `kubectl get service` 命令,验证 DNS 服务是否运行: - -``` -kubectl get svc --namespace=kube-system -``` - - - -应该能够看到: - -``` -NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE -... -kube-dns 10.0.0.10 53/UDP,53/TCP 1h -... -``` - - - -如果服务已经创建,或在这个例子中默认被创建,但是并没有看到,可以查看 [调试 Service 页面](/docs/tasks/debug-application-cluster/debug-service/) 获取更多信息。 - -``` -kubectl get ep kube-dns --namespace=kube-system -``` - - - -应该能够看到类似如下信息: - -``` -NAME ENDPOINTS AGE -kube-dns 10.180.3.17:53,10.180.3.17:53 1h -``` - - - -如果没有看到 Endpoint,查看 [调试 Service 文档](/docs/tasks/debug-application-cluster/debug-service/) 中的 Endpoint 段内容。 - -关于更多 Kubernetes DNS 的示例,参考 Kubernetes GitHub 仓库中 [集群 DNS 示例](https://git.k8s.io/kubernetes/examples/cluster-dns)。 - -## Kubernetes Federation(多 Zone 支持) - -在1.3 发行版本中,为多站点 Kubernetes 安装引入了集群 Federation 支持。这需要对 Kubernetes 集群 DNS 服务器处理 DNS 查询的方式,做出一些微小(后向兼容)改变,从而便利了对联合 Service 的查询(跨多个 Kubernetes 集群)。参考 [集群 Federation 管理员指南](/docs/concepts/cluster-administration/federation/) 获取更多关于集群 Federation 和多站点支持的细节。 - - - -## 工作原理 - -运行的 Kubernetes DNS Pod 包含 3 个容器 —— kubedns、dnsmasq 和负责健康检查的 healthz。 -kubedns 进程监视 Kubernetes master 对 Service 和 Endpoint 操作的变更,并维护一个内存查询结构去处理 DNS 请求。dnsmasq 容器增加了一个 DNS 缓存来改善性能。为执行对 dnsmasq 和 kubedns 的健康检查,healthz 容器提供了一个单独的健康检查 Endpoint。 - -DNS Pod 通过一个静态 IP 暴露为一个 Service。一旦 IP 被分配,kubelet 会通过 `--cluster-dns=10.0.0.10` 标志将配置的 DNS 传递给每一个容器。 - -DNS 名字也需要域名,本地域名是可配置的,在 kubelet 中使用 `--cluster-domain=` 标志。 - -Kubernetes 集群 DNS 服务器(根据 [SkyDNS](https://github.com/skynetservices/skydns) 库)支持正向查询(A 记录),Service 查询(SRV 记录)和反向 IP 地址查询(PTR 记录)。 - - - -## 从 Node 继承 DNS -当运行 Pod 时,kubelet 将集群 DNS 服务器和搜索路径追加到 Node 自己的 DNS 设置中。如果 Node 能够在大型环境中解析 DNS 名字,Pod 也应该没问题。参考下面 "已知问题” 中给出的更多说明。 - -如果不想这样,或者希望 Pod 有一个不同的 DNS 配置,可以使用 kubelet 的 `--resolv-conf` 标志。设置为 "" 表示 Pod 将不继承自 DNS。设置为一个合法的文件路径,表示 kubelet 将使用这个文件而不是 `/etc/resolv.conf` 。 - - - -## 已知问题 - -Kubernetes 安装但并不配置 Node 的 resolv.conf 文件,而是默认使用集群 DNS的,因为那个过程本质上就是和特定的发行版本相关的。最终应该会被实现。 - -Linux libc 在限制为3个 DNS `nameserver` 记录和3个 DNS `search` 记录是不可能卡住的([查看 2005 年的一个 Bug](https://bugzilla.redhat.com/show_bug.cgi?id=168253))。Kubernetes 需要使用1个 `nameserver` 记录和3个 `search` 记录。这意味着如果本地安装已经使用了3个 `nameserver` 或使用了3个以上 `search`,那些设置将会丢失。作为部分解决方法, Node 可以运行 `dnsmasq` ,它能提供更多 `nameserver` 条目,但不能运行更多 `search` 条目。可以使用 kubelet 的 `--resolv-conf` 标志。 - -如果使用 3.3 版本的 Alpine 或更早版本作为 base 镜像,由于 Alpine 的一个已知问题,DNS 可能不会正确工作。查看 [这里](https://github.com/kubernetes/kubernetes/issues/30215) 获取更多信息。 +### 可用功能 +Pod DNS 配置和 DNS 策略 "`None`" 的版本对应如下所示。 +| k8s version | Feature support | +| :---------: |:-----------:| +| 1.14 | Stable | +| 1.10 | Beta (on by default)| +| 1.9 | Alpha | -## 参考 +{{% /capture %}} -- [DNS 集群插件文档](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/dns/README.md) +{{% capture whatsnext %}} + +有关管理 DNS 配置的指导,请查看 +[配置 DNS 服务](/docs/tasks/administer-cluster/dns-custom-nameservers/) -## 下一步 +{{% /capture %}} -- [集群中 DNS Service 自动伸缩](/docs/tasks/administer-cluster/dns-horizontal-autoscaling/) diff --git a/content/zh/docs/concepts/services-networking/ingress-controllers.md b/content/zh/docs/concepts/services-networking/ingress-controllers.md new file mode 100644 index 0000000000000..40b92ace95ce5 --- /dev/null +++ b/content/zh/docs/concepts/services-networking/ingress-controllers.md @@ -0,0 +1,118 @@ +--- +title: Ingress 控制器 +content_template: templates/concept +weight: 40 +--- + +{{% capture overview %}} + + + +为了让 Ingress 资源工作,集群必须有一个正在运行的 Ingress 控制器。 + +与其他类型的控制器不同,它们是作为 `kube-controller-manager` 二进制文件的一部分运行的,而 Ingress 控制器不是随集群自动启动的。 +通过此页面可选择最适合您的集群的 ingress 控制器实现。 + +Kubernetes 作为一个项目,目前支持和维护 [GCE](https://git.k8s.io/ingress-gce/README.md) 和 + [nginx](https://git.k8s.io/ingress-nginx/README.md) 控制器。 + +{{% /capture %}} + +{{% capture body %}} + + +## 其他控制器 + +* [Ambassador](https://www.getambassador.io/) API 网关, 一个基于 [Envoy](https://www.envoyproxy.io) 的 ingress + 控制器,有着来自 [Datawire](https://www.datawire.io/) [社区](https://www.getambassador.io/docs)或[商业](https://www.getambassador.io/pro/)的支持。 +* [AppsCode Inc.](https://appscode.com) 为最广泛使用的基于 [HAProxy](http://www.haproxy.org/) 的 ingress 控制器 [Voyager](https://appscode.com/products/voyager) 提供支持和维护. +* [Contour](https://github.com/heptio/contour) 是一个基于 [Envoy](https://www.envoyproxy.io) 的 ingress 控制器,它由 Heptio 提供和支持。 +* Citrix 为其硬件(MPX),虚拟化(VPX)和 [免费容器化 (CPX) ADC](https://www.citrix.com/products/citrix-adc/cpx-express.html) 提供了一个 [Ingress 控制器](https://github.com/citrix/citrix-k8s-ingress-controller),用于[裸金属](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/deployment/baremetal)和[云](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/deployment)部署。 +* F5 Networks 为 [用于 Kubernetes 的 F5 BIG-IP 控制器](http://clouddocs.f5.com/products/connectors/k8s-bigip-ctlr/latest)提供[支持和维护](https://support.f5.com/csp/article/K86859508)。 +* [Gloo](https://gloo.solo.io) 是一个开源的基于 [Envoy](https://www.envoyproxy.io) 的 ingress 控制器,它提供了 API 网关功能,有着来自 [solo.io](https://www.solo.io) 的企业级支持。 +* [HAProxy Technologies](https://www.haproxy.com/) 为 [HAProxy Ingress Controller for Kubernetes](https://github.com/haproxytech/kubernetes-ingress). See the [official documentation](https://www.haproxy.com/documentation/hapee/1-9r1/traffic-management/kubernetes-ingress-controller/) 提供支持和运维服务。 +* 基于 [Istio](https://istio.io/) 的 ingress 控制器[控制 Ingress 流量](https://istio.io/docs/tasks/traffic-management/ingress/)。 +* [Kong](https://konghq.com/) 为[用于 Kubernetes 的 Kong Ingress 控制器](https://github.com/Kong/kubernetes-ingress-controller) 提供[社区](https://discuss.konghq.com/c/kubernetes)或[商业](https://konghq.com/kong-enterprise/)支持和维护。 +* [NGINX, Inc.](https://www.nginx.com/) 为[用于 Kubernetes 的 NGINX Ingress 控制器](https://www.nginx.com/products/nginx/kubernetes-ingress-controller)提供支持和维护。 +* [Skipper](https://opensource.zalando.com/skipper/kubernetes/ingress-controller/) HTTP路由器和反向代理,用于服务组合,包括诸如Kubernetes Ingress之类的用例,被设计为用于构建自定义代理的库。 +* [Traefik](https://github.com/containous/traefik) 是一个全功能的 ingress 控制器 + ([Let's Encrypt](https://letsencrypt.org),secrets,http2,websocket),并且它也有来自 [Containous](https://containo.us/services) 的商业支持。 + + +## 使用多个 Ingress 控制器 + +你可以在集群中部署[任意数量的 ingress 控制器](https://git.k8s.io/ingress-nginx/docs/user-guide/multiple-ingress.md#multiple-ingress-controllers)。 +创建 ingress 时,应该使用适当的 +[`ingress.class`](https://git.k8s.io/ingress-gce/docs/faq/README.md#how-do-i-run-multiple-ingress-controllers-in-the-same-cluster) 注解每个 ingress +以表明在集群中如果有多个 ingress 控制器时,应该使用哪个 ingress 控制器。 + +如果不定义 `ingress.class`,云提供商可能使用默认的 ingress 控制器。 + +理想情况下,所有 ingress 控制器都应满足此规范,但各种 ingress 控制器的操作略有不同。 + +{{< note >}} + +确保您查看了 ingress 控制器的文档,以了解选择它的注意事项。 +{{< /note >}} + +{{% /capture %}} + +{{% capture whatsnext %}} + + + +* 了解更多关于 [Ingress](/docs/concepts/services-networking/ingress/)。 +* [在 Minikube 上使用 NGINX 控制器安装 Ingress](/docs/tasks/access-application-cluster/ingress-minikube)。 +{{% /capture %}} diff --git a/content/zh/docs/concepts/services-networking/ingress.md b/content/zh/docs/concepts/services-networking/ingress.md new file mode 100644 index 0000000000000..c84685aaacafe --- /dev/null +++ b/content/zh/docs/concepts/services-networking/ingress.md @@ -0,0 +1,729 @@ +--- +title: Ingress +content_template: templates/concept +weight: 40 +--- + +{{% capture overview %}} +{{< feature-state for_k8s_version="v1.1" state="beta" >}} +{{< glossary_definition term_id="ingress" length="all" >}} +{{% /capture %}} + +{{% capture body %}} + + + +## 专用术语 + +为了避免歧义,本指南定义了以下术语: + +节点 +:Kubernetes 集群中的单个工作机器。 + +集群 +:运行由Kubernetes管理的容器化应用程序的一组节点。 对于此示例,在大多数常见的Kubernetes部署中,群集中的节点不属于公共网络。 + +边缘路由器 +:为集群强制执行防火墙策略的路由器。这可以是由云提供商管理的网关或物理硬件。 + +集群网络 +:一组逻辑或物理的链接,根据 Kubernetes [网络模型](/docs/concepts/cluster-administration/networking/) 在集群内实现通信。 + +服务: +Kubernetes {{< glossary_tooltip term_id="service" >}} 使用 {{< glossary_tooltip text="标签" term_id="label" >}} 选择器标识一组 Pod。除非另有说明,否则假定服务只具有在集群网络中可路由的虚拟 IP。 + + + +## Ingress 是什么? + +Ingress公开了从群集外部到群集内 {{< link text="services" url="/docs/concepts/services-networking/service/" >}} 的HTTP和HTTPS路由。 +流量路由由Ingress资源上定义的规则控制。 + +```none + internet + | + [ Ingress ] + --|-----|-- + [ Services ] +``` + + + +可以将Ingress配置为提供服务外部可访问的URL,负载平衡流量,终止 SSL / TLS 并提供基于名称的虚拟主机。 [Ingress 控制器](/docs/concepts/services-networking/ingress-controllers)通常负责通过负载平衡器来实现入口,尽管它也可以配置边缘路由器或其他前端以帮助处理流量。 + +Ingress 不会公开任意端口或协议。 将 HTTP 和 HTTPS 以外的服务公开给 Internet 时,通常使用以下类型的服务 [Service.Type=NodePort](/docs/concepts/services-networking/service/#nodeport) 或者 [Service.Type=LoadBalancer](/docs/concepts/services-networking/service/#loadbalancer). + + + +## 环境准备 + +您必须具有[ Ingress 控制器](/docs/concepts/services-networking/ingress-controllers)才能满足Ingress的要求。 仅创建Ingress资源无效。 + +您可以部署一个 Ingress 控制器 + +GCE/Google Kubernetes Engine 是在主节点上部署 Ingress 控制器。 +您可以在 Pod 中部署任意数量的自定义 Ingress 控制器。 +您必须使用适当的类来注释每个 Ingress,如[这里](https://git.k8s.io/ingress-nginx/docs/user-guide/multiple-ingress.md#multiple-ingress-controllers) 和 [这里](https://git.k8s.io/ingress-gce/examples/PREREQUISITES.md#ingress-class) 所示。 + +一定要检查一下这个控制器的 [beta 限制](https://github.com/kubernetes/ingress-gce/blob/master/BETA_LIMITATIONS.md#glbc-beta-limitations)。 +在 GCE/Google Kubernetes Engine 之外的环境中,需要将[控制器部署](https://git.k8s.io/ingress-nginx/README.md) 为 Pod。 + +{{< note >}} + + +确保您查看了 Ingress 控制器的文档,以了解选择它的注意事项。 +{{< /note >}} + + + +## Ingress 资源 + +最小的 Ingress 资源实例: + +```yaml +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: test-ingress + annotations: + nginx.ingress.kubernetes.io/rewrite-target: / +spec: + rules: + - http: + paths: + - path: /testpath + backend: + serviceName: test + servicePort: 80 +``` + + + +与所有其他 Kubernetes 资源一样,Ingress 需要使用 `apiVersion`, `kind`, 和 `metadata`字段。 +有关使用配置文件的一般信息,请参阅[部署应用程序](/docs/tasks/run-application/run-stateless-application-deployment/),[配置容器](/docs/tasks/configure-pod-container/configure-pod-configmap/),[管理资源](/docs/concepts/cluster-administration/manage-deployment/)。 +Ingress 经常根据 Ingress 控制器使用注释来配置一些选项,例如 [rewrite-target注解](https://github.com/kubernetes/ingress-nginx/blob/master/docs/examples/rewrite/README.md) +不同的[Ingress控制器](/docs/concepts/services-networking/ingress-controllers)支持不同的注释。 +查看文档以供您选择 Ingress 控制器,以了解支持哪些注释。 + +Ingress [spec](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status) 具有配置负载平衡器或代理服务器所需的所有信息。 +最重要的是,它包含与所有传入请求匹配的规则列表。 Ingress 资源仅支持用于定向HTTP流量的规则。 + + + +### Ingress 规则 + +每个HTTP规则都包含以下信息: +* host 选项。在此示例中,未指定主机,因此该规则适用于通过指定 IP 地址的所有入站 HTTP 通信。 如果提供了 host 地址(例如foo.bar.com),则规则适用于该主机。 +* 路径列表(例如,`/testpath` ),每个路径都有一个由 `serviceName` 和 `servicePort` 定义的关联后端。在负载均衡器将流量定向到引用的服务之前,主机和路径都必须匹配传入请求的内容。 +* 后端是 [服务文档](/docs/concepts/services-networking/service/) 中所述的服务和端口名称的组合。与规则的主机和路径匹配的对 Ingress 的 HTTP 和 HTTPS 请求将发送到列出的后端。 + + + +### 默认后端 + +没有设定规则的 Ingress 将所有流量发送到单个默认后端。 +默认后端通常是 [Ingress控制器](/docs/concepts/services-networking/ingress-controllers) 的配置选项,并且未在Ingress资源中指定。 + +如果没有主机或路径与 Ingress 对象中的 HTTP 请求匹配,则流量将路由到您的默认后端。 + + + +## Ingress 的类型 + +### 单服务 Ingress + +现有的 Kubernetes 概念允许您暴露单个 Service (查看 [替代方案](#alternatives)), +同样您也可以使用 Ingress 来实现,具体方法是指定一个没有规则的 *默认后端(default backend)*。 + + +{{< codenew file="service/networking/ingress.yaml" >}} + + + +如果使用 `kubectl apply -f` 创建它,则应该能够查看刚刚添加的Ingress的状态: + + +```shell +kubectl get ingress test-ingress +``` + +``` +NAME HOSTS ADDRESS PORTS AGE +test-ingress * 107.178.254.228 80 59s +``` + + + +其中 `107.178.254.228` 是 Ingress 控制器为该 Ingress 分配的 IP 该。 + +{{< note >}} + + +入口控制器和负载平衡器可能需要一两分钟才能分配IP地址。 在此之前,您通常会看到地址字段的值被设定为 ``。 +{{< /note >}} + + + +### 简单分列 + +分列配置根据请求的 HTTP URI 将流量从单个IP地址路由到多个服务。 +通过Ingress,您可以将负载均衡器的数量保持在最低水平。 例如,如下设置: + +```none +foo.bar.com -> 178.91.123.132 -> / foo service1:4200 + / bar service2:8080 +``` + + + +可能需要一个 Ingress 就像: + +```yaml +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: simple-fanout-example + annotations: + nginx.ingress.kubernetes.io/rewrite-target: / +spec: + rules: + - host: foo.bar.com + http: + paths: + - path: /foo + backend: + serviceName: service1 + servicePort: 4200 + - path: /bar + backend: + serviceName: service2 + servicePort: 8080 +``` + + + +当您使用 `kubectl apply -f` 创建 Ingress 时: + +```shell +kubectl describe ingress test +``` + +```shell +kubectl describe ingress simple-fanout-example +``` + +``` +Name: simple-fanout-example +Namespace: default +Address: 178.91.123.132 +Default backend: default-http-backend:80 (10.8.2.3:8080) +Rules: + Host Path Backends + ---- ---- -------- + foo.bar.com + /foo service1:4200 (10.8.0.90:4200) + /bar service2:8080 (10.8.0.91:8080) +Annotations: + nginx.ingress.kubernetes.io/rewrite-target: / +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal ADD 22s loadbalancer-controller default/test +``` + + + +Ingress 控制器提供实现特定的负载均衡器来满足 Ingress,只要 Service (`service1`, `service2`) 存在。 +当它这样做了,你会在地址栏看到负载平衡器的地址。 + +{{< note >}} + + + +取决于你使用的 [Ingress 控制器](/docs/concepts/services-networking/ingress-controllers), +您可能需要创建一个默认的 http-backend [Service](/docs/concepts/services-networking/service/).。 +{{< /note >}} + + + + +### 基于名称的虚拟托管 + +基于名称的虚拟主机支持将 HTTP 流量路由到同一 IP 地址上的多个主机名。 + +```none +foo.bar.com --| |-> foo.bar.com service1:80 + | 178.91.123.132 | +bar.foo.com --| |-> bar.foo.com service2:80 +``` + + + + +下面的 Ingress 让后台的负载均衡器基于 [Host header](https://tools.ietf.org/html/rfc7230#section-5.4) 路由请求。 + +```yaml +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: name-virtual-host-ingress +spec: + rules: + - host: foo.bar.com + http: + paths: + - backend: + serviceName: service1 + servicePort: 80 + - host: bar.foo.com + http: + paths: + - backend: + serviceName: service2 + servicePort: 80 +``` + + + +如果您在规则中未定义任何主机的情况下创建 Ingress 资源,则可以匹配到 Ingress 控制器 IP 地址的任何网络流量,而无需基于名称的虚拟主机。 + +例如,以下Ingress资源会将 `first.bar.com` 请求的流量路由到 `service1`,将 `second.foo.com` 请求的流量路由到 `service2`, +而所有到IP地址但未在请求中定义主机名的流量 (也就是说,不向 `service3` 提供请求报文头)。 + +```yaml +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: name-virtual-host-ingress +spec: + rules: + - host: first.bar.com + http: + paths: + - backend: + serviceName: service1 + servicePort: 80 + - host: second.foo.com + http: + paths: + - backend: + serviceName: service2 + servicePort: 80 + - http: + paths: + - backend: + serviceName: service3 + servicePort: 80 +``` + + + +### TLS + +您可以通过指定包含TLS私钥和证书的 {{< glossary_tooltip term_id="secret" >}} 来加密 Ingress。 +目前,Ingress 只支持单个 TLS 端口,443,并假定 TLS 终止。 +如果 Ingress 中的 TLS 配置部分指定了不同的主机,那么它们将根据通过 SNI TLS 扩展指定的主机名(如果 Ingress 控制器支持 SNI)在同一端口上进行复用。 +TLS Secret 必须包含名为 `tls.crt` 和 `tls.key` 的密钥,这些密钥包含用于 TLS 的证书和私钥,例如: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: testsecret-tls + namespace: default +data: + tls.crt: base64 encoded cert + tls.key: base64 encoded key +type: kubernetes.io/tls +``` + + + +在 Ingress 中引用此秘钥会告诉 Ingress 控制器使用 TLS 保护从客户端到负载均衡器的通道。 +您需要确保创建包含 `sslexample.foo.com` 的 TLS 秘钥的 CN 的证书。 + +```yaml +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: tls-example-ingress +spec: + tls: + - hosts: + - sslexample.foo.com + secretName: testsecret-tls + rules: + - host: sslexample.foo.com + http: + paths: + - path: / + backend: + serviceName: service1 + servicePort: 80 +``` +{{< note >}} + + + +各种 Ingress 控制器所支持的 TLS 功能之间存在间隙。请参阅有关文件 +[nginx](https://git.k8s.io/ingress-nginx/README.md#https), +[GCE](https://git.k8s.io/ingress-gce/README.md#frontend-https), +或任何其他平台特定的 Ingress 控制器,以了解 TLS 如何在您的环境中工作。 +{{< /note >}} + + + +### 负载均衡 + +Ingress 控制器使用一些适用于所有 Ingress 的负载均衡策略设置进行自举,例如负载平衡算法、后端权重方案等。 +更高级的负载平衡概念(例如,持久会话、动态权重)尚未通过 Ingress 公开。 +您可以通过用于服务的负载平衡器来获取这些功能。 + + + +值得注意的是,即使健康检查不是通过 Ingress 直接暴露的,但是在 Kubernetes 中存在并行概念,比如 [就绪检查](/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/),它允许您实现相同的最终结果。 +请检查控制器说明文档,以了解他们是怎样实现健康检查的 ( +[nginx](https://git.k8s.io/ingress-nginx/README.md), +[GCE](https://git.k8s.io/ingress-gce/README.md#health-checks))。 + + + + +## 更新 Ingress + +假设您想向现有的 Ingress 中添加新主机,可以通过编辑资源来更新它: + +```shell +kubectl describe ingress test +``` + +``` +Name: test +Namespace: default +Address: 178.91.123.132 +Default backend: default-http-backend:80 (10.8.2.3:8080) +Rules: + Host Path Backends + ---- ---- -------- + foo.bar.com + /foo service1:80 (10.8.0.90:80) +Annotations: + nginx.ingress.kubernetes.io/rewrite-target: / +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal ADD 35s loadbalancer-controller default/test +``` + +```shell +kubectl edit ingress test +``` + + + +弹出一个编辑器用于编辑现有的 yaml,修改它来增加新的主机: + +```yaml +spec: + rules: + - host: foo.bar.com + http: + paths: + - backend: + serviceName: service1 + servicePort: 80 + path: /foo + - host: bar.baz.com + http: + paths: + - backend: + serviceName: service2 + servicePort: 80 + path: /foo +.. +``` + + + +保存更改后,kubectl 将更新 API 服务器中的资源,该资源将告诉 Ingress 控制器重新配置负载平衡器。 + +验证一下: + +```shell +kubectl describe ingress test +``` + +``` +Name: test +Namespace: default +Address: 178.91.123.132 +Default backend: default-http-backend:80 (10.8.2.3:8080) +Rules: + Host Path Backends + ---- ---- -------- + foo.bar.com + /foo service1:80 (10.8.0.90:80) + bar.baz.com + /foo service2:80 (10.8.0.91:80) +Annotations: + nginx.ingress.kubernetes.io/rewrite-target: / +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal ADD 45s loadbalancer-controller default/test +``` + + + + +您可以通过 `kubectl replace -f` 命令调用修改后的 Ingress YAML 文件来获得同样的结果。 + + + +## 跨可用区失败 + +用于跨故障域传播流量的技术在云提供商之间是不同的。详情请查阅相关 Ingress 控制器的文档。 +请查看相关[Ingress控制器](/docs/concepts/services-networking/ingress-controllers)的文档以了解详细信息。 +您还可以参考[联合文档](/docs/concepts/cluster-administration/federation/),以获取有关在联合群集中部署Ingress的详细信息。 + + + + +## 未来的工作 + +跟踪 [SIG网络](https://github.com/kubernetes/community/tree/master/sig-network) 详细了解Ingress和相关资源的发展。 +您也可以跟踪 [Ingress信息库](https://github.com/kubernetes/ingress/tree/master) 了解 Ingress 控制器进化的更多信息。 + + + +## 替代方案 + +不直接使用 Ingress 资源,也有多种方法暴露 Service: + +* 使用 [Service.Type=LoadBalancer](/docs/concepts/services-networking/service/#loadbalancer) +* 使用 [Service.Type=NodePort](/docs/concepts/services-networking/service/#nodeport) + +{{% /capture %}} + +{{% capture whatsnext %}} + + +* 了解 [ingress 控制器](/docs/concepts/services-networking/ingress-controllers/) +* [使用NGINX控制器在Minikube上设置Ingress](/docs/tasks/access-application-cluster/ingress-minikube) +{{% /capture %}} + diff --git a/content/zh/docs/concepts/services-networking/network-policies.md b/content/zh/docs/concepts/services-networking/network-policies.md index f36633633f243..e5fcd09fb633b 100644 --- a/content/zh/docs/concepts/services-networking/network-policies.md +++ b/content/zh/docs/concepts/services-networking/network-policies.md @@ -1,30 +1,62 @@ --- -approvers: -- thockin -- caseydavenport -- danwinship title: 网络策略 +content_template: templates/concept +weight: 50 --- {{< toc >}} +{{% capture overview %}} + + + 网络策略(NetworkPolicy)是一种关于pod间及pod与其他网络端点间所允许的通信规则的规范。 `NetworkPolicy` 资源使用标签选择pod,并定义选定pod所允许的通信规则。 +{{% /capture %}} + +{{% capture body %}} + + + ## 前提 网络策略通过网络插件来实现,所以用户必须使用支持 `NetworkPolicy` 的网络解决方案 - 简单地创建资源对象,而没有控制器来使它生效的话,是没有任何作用的。 + + ## 隔离和非隔离的Pod 默认情况下,Pod是非隔离的,它们接受任何来源的流量。 Pod可以通过相关的网络策略进行隔离。一旦命名空间中有网络策略选择了特定的Pod,该Pod会拒绝网络策略所不允许的连接。 (命名空间下其他未被网络策略所选择的Pod会继续接收所有的流量) + + ## `NetworkPolicy` 资源 -通过[api参考](/docs/api-reference/{{< param "version" >}}/#networkpolicy-v1-networking)来了解资源定义。 +查看 [网络策略](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#networkpolicy-v1-networking-k8s-io) 来了解资源定义。 下面是一个 `NetworkPolicy` 的示例: @@ -38,8 +70,15 @@ spec: podSelector: matchLabels: role: db + policyTypes: + - Ingress + - Egress ingress: - from: + - ipBlock: + cidr: 172.17.0.0/16 + except: + - 172.17.1.0/24 - namespaceSelector: matchLabels: project: myproject @@ -49,8 +88,35 @@ spec: ports: - protocol: TCP port: 6379 + egress: + - to: + - ipBlock: + cidr: 10.0.0.0/24 + ports: + - protocol: TCP + port: 5978 ``` + + 除非选择支持网络策略的网络解决方案,否则将上述示例发送到API服务器没有任何效果。 __必填字段__: 与所有其他的Kubernetes配置一样,`NetworkPolicy` 需要 `apiVersion`、 `kind`和 `metadata` 字段。 关于配置文件操作的一般信息,请参考 [这里](/docs/user-guide/simple-yaml)、 [这里](/docs/user-guide/configuring-containers)和 [这里](/docs/user-guide/working-with-resources)。 @@ -59,19 +125,140 @@ __spec__: `NetworkPolicy` [spec](https://git.k8s.io/community/contributors/devel __podSelector__: 每个 `NetworkPolicy` 都包括一个 `podSelector` ,它对该策略所应用的一组Pod进行选择。因为 `NetworkPolicy` 目前只支持定义 `ingress` 规则,这里的 `podSelector` 本质上是为该策略定义 "目标pod" 。示例中的策略选择带有 "role=db" 标签的pod。空的 `podSelector` 选择命名空间下的所有pod。 -__ingress__: 每个 `NetworkPolicy` 包含一个 `ingress` 规则的白名单列表。 (其中的)规则允许同时匹配 `from` 和 `ports` 部分的流量。示例策略中包含一条简单的规则: 它匹配一个单一的端口,来自两个来源中的一个, 第一个通过 `namespaceSelector` 指定,第二个通过 `podSelector` 指定。 +__policyTypes__: Each `NetworkPolicy` includes a `policyTypes` list which may include either `Ingress`, `Egress`, or both. The `policyTypes` field indicates whether or not the given policy applies to ingress traffic to selected pod, egress traffic from selected pods, or both. If no `policyTypes` are specified on a NetworkPolicy then by default `Ingress` will always be set and `Egress` will be set if the NetworkPolicy has any egress rules. + +__ingress__: 每个 `NetworkPolicy` 包含一个 `ingress` 规则的白名单列表。(其中的)规则允许同时匹配 `from` 和 `ports` 部分的流量。示例策略中包含一条简单的规则: 它匹配一个单一的端口,来自两个来源中的一个, 第一个通过 `namespaceSelector` 指定,第二个通过 `podSelector` 指定。 + +__egress__: 每个 `NetworkPolicy` 包含一个 `egress` 规则的白名单列表。每个规则都允许匹配 `to` 和 `port` 部分的流量。该示例策略包含一条规则,该规则将单个端口上的流量匹配到 `10.0.0.0/24` 中的任何目的地。 + + 所以,示例网络策略: 1. 隔离 "default" 命名空间下 "role=db" 的pod (如果它们不是已经被隔离的话)。 2. 允许从 "default" 命名空间下带有 "role=frontend" 标签的pod到 "default" 命名空间下的pod的6379 TCP端口的连接。 -3. 允许从带有 "project=myproject" 标签的命名空间下的任何pod到 "default" 命名空间下的pod的6379 TCP端口的连接。 + + * 标签为 "role=frontend" 的 "default" 名称空间中的任何Pod + * 名称空间中带有标签 "project=myproject" 的任何pod + * IP 地址范围为 172.17.0.0–172.17.0.255 和 172.17.2.0–172.17.255.255(即,除了 172.17.1.0/24 之外的所有 172.17.0.0/16) +3. 允许从带有 "project=myproject" 标签的命名空间下的任何 pod 到 "default" 命名空间下的 pod 的6379 TCP端口的连接。 查看 [网络策略入门指南](/docs/getting-started-guides/network-policy/walkthrough) 了解更多示例。 + + +## 选择器 `to` 和 `from` 的行为 + +可以在 `ingress` `from` 部分或 `egress` `to` 部分中指定四种选择器: + +__podSelector__: 这将在与 `NetworkPolicy` 相同的名称空间中选择特定的 Pod,应将其允许作为入口源或出口目的地。 + +__namespaceSelector__: 这将选择特定的名称空间,应将所有 Pod 用作其输入源或输出目的地。 + +__namespaceSelector__ *和* __podSelector__: 一个指定 `namespaceSelector` 和 `podSelector` 的 `to`/`from` 条目选择特定命名空间中的特定 Pod。注意使用正确的YAML语法;这项政策: + +```yaml + ... + ingress: + - from: + - namespaceSelector: + matchLabels: + user: alice + podSelector: + matchLabels: + role: client + ... +``` + +contains a single `from` element allowing connections from Pods with the label `role=client` in namespaces with the label `user=alice`. But *this* policy: + +```yaml + ... + ingress: + - from: + - namespaceSelector: + matchLabels: + user: alice + - podSelector: + matchLabels: + role: client + ... +``` + + + +在 `from` 数组中包含两个元素,允许来自本地命名空间中标有 `role = client` 的 Pod 的连接,*或*来自任何名称空间中标有`user = alice`的任何Pod的连接。 + +如有疑问,请使用 `kubectl describe` 查看 Kubernetes 如何解释该策略。 + +__ipBlock__: 这将选择特定的 IP CIDR 范围以用作入口源或出口目的地。 这些应该是群集外部 IP,因为 Pod IP 存在时间短暂的且随机产生。 + +群集的入口和出口机制通常需要重写数据包的源 IP 或目标 IP。在发生这种情况的情况下,不确定在 NetworkPolicy 处理之前还是之后发生,并且对于网络插件,云提供商,`Service` 实现等的不同组合,其行为可能会有所不同。 + +在进入的情况下,这意味着在某些情况下,您可以根据实际的原始源 IP 过滤传入的数据包,而在其他情况下,NetworkPolicy 所作用的 `源IP` 则可能是 `LoadBalancer` 或 Pod的节点等。 + +对于出口,这意味着从 Pod 到被重写为集群外部 IP 的 `Service` IP 的连接可能会或可能不会受到基于 `ipBlock` 的策略的约束。 + + + ## 默认策略 -用户可以通过创建一个选择所有Pod,但是不允许任何通信的网络策略,来为一个命名空间创建 "默认的" 隔离策略: +默认情况下,如果名称空间中不存在任何策略,则所有进出该名称空间中的Pod的流量都被允许。以下示例使您可以更改该名称空间中的默认行为。 + + + +### 默认拒绝所有入口流量 + +您可以通过创建选择所有容器但不允许任何进入这些容器的入口流量的 NetworkPolicy 来为名称空间创建 "default" 隔离策略。 ```yaml apiVersion: networking.k8s.io/v1 @@ -79,12 +266,25 @@ kind: NetworkPolicy metadata: name: default-deny spec: - podSelector: + podSelector: {} + policyTypes: + - Ingress ``` -这可以确保即使Pod在未被其他任何网络策略所选择的情况下仍能被隔离。 + +这样可以确保即使容器没有选择其他任何 NetworkPolicy,也仍然可以被隔离。此策略不会更改默认的出口隔离行为。 -或者,如果用户希望允许一个命名空间下的所有Pod的所有通信 (即使已经添加了策略,使得一些pod被 "隔离"),仍可以创建一个明确允许所有通信的策略: + + +### 默认允许所有入口流量 + +如果要允许所有流量进入某个命名空间中的所有 Pod(即使添加了导致某些 Pod 被视为“隔离”的策略),则可以创建一个策略来明确允许该命名空间中的所有流量。 ```yaml apiVersion: networking.k8s.io/v1 @@ -92,12 +292,119 @@ kind: NetworkPolicy metadata: name: allow-all spec: - podSelector: + podSelector: {} ingress: - {} + policyTypes: + - Ingress +``` + + + +### 默认拒绝所有出口流量 + +您可以通过创建选择所有容器但不允许来自这些容器的任何出口流量的 NetworkPolicy 来为名称空间创建 "default" egress 隔离策略。 + +```yaml +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: default-deny +spec: + podSelector: {} + policyTypes: + - Egress +``` + + + +这样可以确保即使没有被其他任何 NetworkPolicy 选择的 Pod 也不会被允许流出流量。此策略不会更改默认的 ingress 隔离行为。 + + + +### 默认允许所有出口流量 + +如果要允许来自命名空间中所有 Pod 的所有流量(即使添加了导致某些 Pod 被视为“隔离”的策略),则可以创建一个策略,该策略明确允许该命名空间中的所有出口流量。 + +```yaml +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-all +spec: + podSelector: {} + egress: + - {} + policyTypes: + - Egress +``` + + + +### 默认拒绝所有入口和所有出口流量 + +您可以为名称空间创建 "default" 策略,以通过在该名称空间中创建以下 NetworkPolicy 来阻止所有入站和出站流量。 + +```yaml +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: default-deny +spec: + podSelector: {} + policyTypes: + - Ingress + - Egress ``` -## 下一步呢? + + +这样可以确保即使没有被其他任何 NetworkPolicy 选择的 Pod 也不会被允许进入或流出流量。 + + +## SCTP 支持 + +{{< feature-state for_k8s_version="v1.12" state="alpha" >}} + + +Kubernetes 支持 SCTP 作为 NetworkPolicy 定义中的协议值作为 alpha 功能提供。要启用此功能,集群管理员需要在 apiserver 上启用 `SCTPSupport` 功能门,例如 `“--feature-gates=SCTPSupport=true,...”`。启用功能门后,用户可以将 `NetworkPolicy` 的 `protocol` 字段设置为 `SCTP`。 Kubernetes 相应地为 SCTP 关联设置网络,就像为 TCP 连接一样。 + +CNI插件必须在 `NetworkPolicy` 中将 SCTP 作为 `protocol` 值支持。 + +{{% /capture %}} + +{{% capture whatsnext %}} + + - 查看 [声明网络策略](/docs/tasks/administer-cluster/declare-network-policy/) 来进行更多的示例演练 +- 有关NetworkPolicy资源启用的常见方案的更多信息,请参见 [Recipes](https://github.com/ahmetb/kubernetes-network-policy-recipes)。 +{{% /capture %}} diff --git a/content/zh/docs/concepts/services-networking/service.md b/content/zh/docs/concepts/services-networking/service.md index 6e9705b22129a..8373777532cdd 100644 --- a/content/zh/docs/concepts/services-networking/service.md +++ b/content/zh/docs/concepts/services-networking/service.md @@ -1,54 +1,132 @@ --- -approvers: -- bprashanth title: Service -redirect_from: -- "/docs/user-guide/services/" -- "/docs/user-guide/services/index.html" +feature: + title: 服务发现与负载均衡 + description: > + 无需修改您的应用程序即可使用陌生的服务发现机制。Kubernetes 为容器提供了自己的 IP 地址和一个 DNS 名称,并且可以在它们之间实现负载平衡。 + +content_template: templates/concept +weight: 10 --- +{{% capture overview %}} + +{{< glossary_definition term_id="service" length="short" >}} + + +使用Kubernetes,您无需修改应用程序即可使用不熟悉的服务发现机制。 +Kubernetes为Pods提供自己的IP地址和一组Pod的单个DNS名称,并且可以在它们之间进行负载平衡。 + +{{% /capture %}} + +{{% capture body %}} + + + +## 动机 + +Kubernetes {{< glossary_tooltip term_id="pod" text="Pods" >}} 是有生命周期的。他们可以被创建,而且销毁不会再启动。 +如果您使用 {{}} 来运行您的应用程序,则它可以动态创建和销毁 Pod。 -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 呢? +每个 Pod 都有自己的 IP 地址,但是在 Deployment 中,在同一时刻运行的 Pod 集合可能与稍后运行该应用程序的 Pod 集合不同。 +这导致了一个问题: 如果一组 Pod(称为“后端”)为群集内的其他 Pod(称为“前端”)提供功能,那么前端如何找出并跟踪要连接的 IP 地址,以便前端可以使用工作量的后端部分? +进入 _Services_。 -关于 `Service` + +## Service 资源 {#service-resource} + Kubernetes `Service` 定义了这样一种抽象:逻辑上的一组 `Pod`,一种可以访问它们的策略 —— 通常称为微服务。 -这一组 `Pod` 能够被 `Service` 访问到,通常是通过 [`Label Selector`](/docs/concepts/overview/working-with-objects/labels/#label-selectors)(查看下面了解,为什么可能需要没有 selector 的 `Service`)实现的。 +这一组 `Pod` 能够被 `Service` 访问到,通常是通过 {{< glossary_tooltip text="selector" term_id="selector" >}} +(查看[下面](#services-without-selectors)了解,为什么你可能需要没有 selector 的 `Service`)实现的。 + 举个例子,考虑一个图片处理 backend,它运行了3个副本。这些副本是可互换的 —— frontend 不需要关心它们调用了哪个 backend 副本。 然而组成这一组 backend 程序的 `Pod` 实际上可能会发生变化,frontend 客户端不应该也没必要知道,而且也不需要跟踪这一组 backend 的状态。 `Service` 定义的抽象能够解耦这种关联。 + +### 云原生服务发现 -{{< toc >}} +如果您能够在应用程序中使用 Kubernetes 接口进行服务发现,则可以查询 {{< glossary_tooltip text="API server" term_id="kube-apiserver" >}} 的 endpoint 资源,只要服务中的Pod集合发生更改,端点就会更新。 +对于非本机应用程序,Kubernetes提供了在应用程序和后端Pod之间放置网络端口或负载平衡器的方法。 + +## 定义 Service 一个 `Service` 在 Kubernetes 中是一个 REST 对象,和 `Pod` 类似。 -像所有的 REST 对象一样, `Service` 定义可以基于 POST 方式,请求 apiserver 创建新的实例。 -例如,假定有一组 `Pod`,它们对外暴露了 9376 端口,同时还被打上 `"app=MyApp"` 标签。 +像所有的 REST 对象一样, `Service` 定义可以基于 `POST` 方式,请求 API server 创建新的实例。 + +例如,假定有一组 `Pod`,它们对外暴露了 9376 端口,同时还被打上 `app=MyApp` 标签。 ```yaml -kind: Service apiVersion: v1 +kind: Service metadata: name: my-service spec: @@ -60,42 +138,95 @@ spec: targetPort: 9376 ``` + +上述配置创建一个名称为 "my-service" 的 `Service` 对象,它会将请求代理到使用 TCP 端口 9376,并且具有标签 `"app=MyApp"` 的 `Pod` 上。 +Kubernetes 为该服务分配一个 IP 地址(有时称为 "集群IP" ),该 IP 地址由服务代理使用。 +(请参见下面的 [虚拟 IP 和服务代理](#virtual-ips-and-service-proxies)). +服务选择器的控制器不断扫描与其选择器匹配的 Pod,然后将所有更新发布到也称为 “my-service” 的Endpoint对象。 +{{< note >}} -需要注意的是, `Service` 能够将一个接收端口映射到任意的 `targetPort`。 + +需要注意的是, `Service` 能够将一个接收 `port` 映射到任意的 `targetPort`。 默认情况下,`targetPort` 将被设置为与 `port` 字段相同的值。 -可能更有趣的是,`targetPort` 可以是一个字符串,引用了 backend `Pod` 的一个端口的名称。 -但是,实际指派给该端口名称的端口号,在每个 backend `Pod` 中可能并不相同。 -对于部署和设计 `Service` ,这种方式会提供更大的灵活性。 -例如,可以在 backend 软件下一个版本中,修改 Pod 暴露的端口,并不会中断客户端的调用。 +{{< /note >}} + +Pod中的端口定义具有名称字段,您可以在服务的 `targetTarget` 属性中引用这些名称。 +即使服务中使用单个配置的名称混合使用 Pod,并且通过不同的端口号提供相同的网络协议,此功能也可以使用。 +这为部署和发展服务提供了很大的灵活性。 +例如,您可以更改Pods在新版本的后端软件中公开的端口号,而不会破坏客户端。 +服务的默认协议是TCP;默认协议是TCP。 您还可以使用任何其他 [受支持的协议](#protocol-support)。 -### 没有 selector 的 Service +由于许多服务需要公开多个端口,因此 Kubernetes 在服务对象上支持多个端口定义。 +每个端口定义可以具有相同的 `protocol`,也可以具有不同的协议。 + -在任何这些场景中,都能够定义没有 selector 的 `Service` : +### 没有 selector 的 Service + +服务最常见的是抽象化对 Kubernetes Pod 的访问,但是它们也可以抽象化其他种类的后端。 +实例: + + * 希望在生产环境中使用外部的数据库集群,但测试环境使用自己的数据库。 + * 希望服务指向另一个 {{< glossary_tooltip term_id="namespace" >}} 中或其它集群中的服务。 + * 您正在将工作负载迁移到 Kubernetes。 在评估该方法时,您仅在 Kubernetes 中运行一部分后端。 + +在任何这些场景中,都能够定义没有 selector 的 `Service`。 +实例: ```yaml -kind: Service apiVersion: v1 +kind: Service metadata: name: my-service spec: @@ -105,187 +236,406 @@ spec: targetPort: 9376 ``` + -由于这个 `Service` 没有 selector,就不会创建相关的 `Endpoints` 对象。可以手动将 `Service` 映射到指定的 `Endpoints`: +由于此服务没有选择器,因此 *不会* 自动创建相应的 Endpoint 对象。 您可以通过手动添加 Endpoint 对象,将服务手动映射到运行该服务的网络地址和端口: ```yaml -kind: Endpoints apiVersion: v1 +kind: Endpoints metadata: name: my-service subsets: - addresses: - - ip: 1.2.3.4 + - ip: 192.0.2.42 ports: - port: 9376 ``` +{{< note >}} + + + +端点 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 Services 的群集 IP,因为 {{}} 不支持将虚拟 IP 作为目标。 +{{< /note >}} + + + +访问没有 selector 的 `Service`,与有 selector 的 `Service` 的原理相同。 +请求将被路由到用户定义的 Endpoint, YAML中为: `192.0.2.42:9376` (TCP)。 + + + +ExternalName `Service` 是 `Service` 的特例,它没有 selector,也没有使用 DNS 名称代替。 +有关更多信息,请参阅本文档后面的[`ExternalName`](#externalname)。 + + +### Endpoint 切片 +{{< feature-state for_k8s_version="v1.16" state="alpha" >}} + + +Endpoint 切片是一种 API 资源,可以为 Endpoint 提供更可扩展的替代方案。 +尽管从概念上讲与 Endpoint 非常相似,但 Endpoint 切片允许跨多个资源分布网络端点。 +默认情况下,一旦到达100个 Endpoint,该 Endpoint 切片将被视为“已满”,届时将创建其他 Endpoint 切片来存储任何其他 Endpoint。 + +Endpoint 切片提供了附加的属性和功能,这些属性和功能在 [Endpoint 切片](/docs/concepts/services-networking/endpoint-slices/)中进行了详细描述。 + + +## VIP 和 Service 代理 -注意:Endpoint IP 地址不能是 loopback(127.0.0.0/8)、 link-local(169.254.0.0/16)、或者 link-local 多播(224.0.0.0/24)。 +在 Kubernetes 集群中,每个 Node 运行一个 `kube-proxy` 进程。`kube-proxy` 负责为 `Service` 实现了一种 VIP(虚拟 IP)的形式,而不是 [`ExternalName`](#externalname) 的形式。 + +### 为什么不使用 DNS 轮询? -ExternalName `Service` 是 `Service` 的特例,它没有 selector,也没有定义任何的端口和 Endpoint。 -相反地,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。 +时不时会有人问道,就是为什么 Kubernetes 依赖代理将入站流量转发到后端。 那其他方法呢? +例如,是否可以配置具有多个A值(或IPv6为AAAA)的DNS记录,并依靠轮询名称解析? -```yaml -kind: Service -apiVersion: v1 -metadata: - name: my-service - namespace: prod -spec: - type: ExternalName - externalName: my.database.example.com -``` +使用服务代理有以下几个原因: +  * DNS 实现的历史由来已久,它不遵守记录 TTL,并且在名称查找结果到期后对其进行缓存。 +  * 有些应用程序仅执行一次 DNS 查找,并无限期地缓存结果。 +  * 即使应用和库进行了适当的重新解析,DNS 记录上的 TTL 值低或为零也可能会给 DNS 带来高负载,从而使管理变得困难。 + +###版本兼容性 +从Kubernetes v1.0开始,您已经可以使用 [用户空间代理模式](#proxy-mode-userspace)。 +Kubernetes v1.1添加了 iptables 模式代理,在 Kubernetes v1.2 中,kube-proxy 的 iptables 模式成为默认设置。 +Kubernetes v1.8添加了 ipvs 代理模式。 -## VIP 和 Service 代理 + +### userspace 代理模式 {#proxy-mode-userspace} -在 Kubernetes v1.0 版本,`Service` 是 “4层”(TCP/UDP over IP)概念。 -在 Kubernetes v1.1 版本,新增了 `Ingress` API(beta 版),用来表示 “7层”(HTTP)服务。 +这种模式,kube-proxy 会监视 Kubernetes master 对 `Service` 对象和 `Endpoints` 对象的添加和移除。 +对每个 `Service`,它会在本地 Node 上打开一个端口(随机选择)。 +任何连接到“代理端口”的请求,都会被代理到 `Service` 的backend `Pods` 中的某个上面(如 `Endpoints` 所报告的一样)。 +使用哪个 backend `Pod`,是 kube-proxy 基于 `SessionAffinity` 来确定的。 +最后,它安装 iptables 规则,捕获到达该 `Service` 的 `clusterIP`(是虚拟 IP)和 `Port` 的请求,并重定向到代理端口,代理端口再代理请求到 backend `Pod`。 +默认情况下,用户空间模式下的kube-proxy通过循环算法选择后端。 -### userspace 代理模式 +默认的策略是,通过 round-robin 算法来选择 backend `Pod`。 +![userspace代理模式下Service概览图](/images/docs/services-userspace-overview.svg) + +### iptables 代理模式 {#proxy-mode-iptables} -默认的策略是,通过 round-robin 算法来选择 backend `Pod`。 -实现基于客户端 IP 的会话亲和性,可以通过设置 `service.spec.sessionAffinity` 的值为 `"ClientIP"` (默认值为 `"None"`)。 +这种模式,kube-proxy 会监视 Kubernetes 控制节点对 `Service` 对象和 `Endpoints` 对象的添加和移除。 +对每个 `Service`,它会安装 iptables 规则,从而捕获到达该 `Service` 的 `clusterIP` 和端口的请求,进而将请求重定向到 `Service` 的一组 backend 中的某个上面。 +对于每个 `Endpoints` 对象,它也会安装 iptables 规则,这个规则会选择一个 backend 组合。 +默认的策略是,kube-proxy 在 iptables 模式下随机选择一个 backend。 +使用 iptables 处理流量具有较低的系统开销,因为流量由 Linux netfilter 处理,而无需在用户空间和内核空间之间切换。 这种方法也可能更可靠。 -![userspace代理模式下Service概览图](/images/docs/services-userspace-overview.svg) +如果 kube-proxy 在 iptable s模式下运行,并且所选的第一个 Pod 没有响应,则连接失败。 这与用户空间模式不同:在这种情况下,kube-proxy 将检测到与第一个 Pod 的连接已失败,并会自动使用其他后端 Pod 重试。 +您可以使用 Pod [ readiness 探测器](/docs/concepts/workloads/pods/pod-lifecycle/#container-probes) +验证后端 Pod 可以正常工作,以便 iptables 模式下的 kube-proxy 仅看到测试正常的后端。 这样做意味着您避免将流量通过 kube-proxy 发送到已知已失败的Pod。 +![iptables代理模式下Service概览图](/images/docs/services-iptables-overview.svg) -### iptables 代理模式 + +### IPVS 代理模式 {#proxy-mode-ipvs} +{{< feature-state for_k8s_version="v1.11" state="stable" >}} + +在 `ipvs` 模式下,kube-proxy监视Kubernetes服务和端点,调用 `netlink` 接口相应地创建 IPVS 规则, +并定期将 IPVS 规则与 Kubernetes 服务和端点同步。 该控制循环可确保 IPVS 状态与所需状态匹配。 访问服务时,IPVS 将流量定向到后端Pod之一。 -默认的策略是,随机选择一个 backend。 -实现基于客户端 IP 的会话亲和性,可以将 `service.spec.sessionAffinity` 的值设置为 `"ClientIP"` (默认值为 `"None"`)。 +IPVS代理模式基于类似于 iptables 模式的 netfilter 挂钩函数,但是使用哈希表作为基础数据结构,并且在内核空间中工作。 +这意味着,与 iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通信的延迟要短,并且在同步代理规则时具有更好的性能。与其他代理模式相比,IPVS 模式还支持更高的网络流量吞吐量。 +IPVS提供了更多选项来平衡后端Pod的流量。 这些是: +- `rr`: round-robin +- `lc`: least connection (smallest number of open connections) +- `dh`: destination hashing +- `sh`: source hashing +- `sed`: shortest expected delay +- `nq`: never queue -和 userspace 代理类似,网络返回的结果是,任何到达 `Service` 的 IP:Port 的请求,都会被代理到一个合适的 backend,不需要客户端知道关于 Kubernetes、`Service`、或 `Pod` 的任何信息。 -这应该比 userspace 代理更快、更可靠。然而,不像 userspace 代理,如果初始选择的 `Pod` 没有响应,iptables 代理能够自动地重试另一个 `Pod`,所以它需要依赖 [readiness probes](/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#defining-readiness-probes)。 +{{< note >}} + -![iptables代理模式下Service概览图](/images/docs/services-iptables-overview.svg) +要在 IPVS 模式下运行 kube-proxy,必须在启动 kube-proxy 之前使 IPVS Linux 在节点上可用。 +当 kube-proxy 以 IPVS 代理模式启动时,它将验证 IPVS 内核模块是否可用。 +如果未检测到 IPVS 内核模块,则 kube-proxy 将退回到以 iptables 代理模式运行。 +{{< /note >}} -## 多端口 Service + +![IPVS代理的 Services 概述图](/images/docs/services-ipvs-overview.svg) +在这些代理模型中,绑定到服务IP的流量:在客户端不了解Kubernetes或服务或Pod的任何信息的情况下,将Port代理到适当的后端。 +如果要确保每次都将来自特定客户端的连接传递到同一Pod,则可以通过将 `service.spec.sessionAffinity` 设置为 "ClientIP" (默认值是 "None"),来基于客户端的IP地址选择会话关联。 -很多 `Service` 需要暴露多个端口。对于这种情况,Kubernetes 支持在 `Service` 对象中定义多个端口。 -当使用多个端口时,必须给出所有的端口的名称,这样 Endpoint 就不会产生歧义,例如: +您还可以通过适当设置 `service.spec.sessionAffinityConfig.clientIP.timeoutSeconds` 来设置最大会话停留时间。 (默认值为 10800 秒,即 3 小时)。 + + + +## 多端口 Service + +对于某些服务,您需要公开多个端口。 +Kubernetes允许您在Service对象上配置多个端口定义。 +为服务使用多个端口时,必须提供所有端口名称,以使它们无歧义。 +例如: ```yaml -kind: 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 + selector: + app: MyApp + ports: + - name: http + protocol: TCP + port: 80 + targetPort: 9376 + - name: https + protocol: TCP + port: 443 + targetPort: 9377 ``` +{{< note >}} + +与一般的Kubernetes名称一样,端口名称只能包含 小写字母数字字符 和 `-`。 端口名称还必须以字母数字字符开头和结尾。 +例如,名称 `123_abc` 和 `web` 有效,但是 `123_abc` 和 `-web` 无效。 +{{< /note >}} -### 为何不使用 round-robin DNS? + -一个不时出现的问题是,为什么我们都使用 VIP 的方式,而不使用标准的 round-robin DNS,有如下几个原因: +## 选择自己的 IP 地址 -* 长久以来,DNS 库都没能认真对待 DNS TTL、缓存域名查询结果 -* 很多应用只查询一次 DNS 并缓存了结果 - * 就算应用和库能够正确查询解析,每个客户端反复重解析造成的负载也是非常难以管理的 +在 `Service` 创建的请求中,可以通过设置 `spec.clusterIP` 字段来指定自己的集群 IP 地址。 +比如,希望替换一个已经已存在的 DNS 条目,或者遗留系统已经配置了一个固定的 IP 且很难重新配置。 -我们尽力阻止用户做那些对他们没有好处的事情,如果很多人都来问这个问题,我们可能会选择实现它。 +用户选择的 IP 地址必须合法,并且这个 IP 地址在 `service-cluster-ip-range` CIDR 范围内,这对 API Server 来说是通过一个标识来指定的。 +如果 IP 地址不合法,API Server 会返回 HTTP 状态码 422,表示值不合法。 + ## 服务发现 - - 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` 的名称需大写,横线被转换成下划线。 - - 举个例子,一个名称为 `"redis-master"` 的 Service 暴露了 TCP 端口 6379,同时给它分配了 Cluster IP 地址 10.0.0.11,这个 Service 生成了如下环境变量: ```shell @@ -298,122 +648,251 @@ REDIS_MASTER_PORT_6379_TCP_PORT=6379 REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11 ``` +{{< note >}} -*这意味着需要有顺序的要求* —— `Pod` 想要访问的任何 `Service` 必须在 `Pod` 自己之前被创建,否则这些环境变量就不会被赋值。DNS 并没有这个限制。 + +当您具有需要访问服务的Pod时,并且您正在使用环境变量方法将端口和群集IP发布到客户端Pod时,必须在客户端Pod出现 *之前* 创建服务。 +否则,这些客户端Pod将不会设定其环境变量。 +如果仅使用DNS查找服务的群集IP,则无需担心此设定问题。 -一个可选(尽管强烈推荐)[集群插件](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/README.md) 是 DNS 服务器。 -DNS 服务器监视着创建新 `Service` 的 Kubernetes API,从而为每一个 `Service` 创建一组 DNS 记录。 -如果整个集群的 DNS 一直被启用,那么所有的 `Pod` 应该能够自动对 `Service` 进行名称解析。 +{{< /note >}} +### DNS + +您可以(几乎总是应该)使用[附加组件](/docs/concepts/cluster-administration/addons/)为Kubernetes集群设置DNS服务。 -Kubernetes DNS 服务器是唯一的一种能够访问 `ExternalName` 类型的 Service 的方式。 -更多信息可以查看[DNS Pod 和 Service](/docs/concepts/services-networking/dns-pod-service/)。 +支持群集的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。 -## Headless Service +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](/docs/concepts/services-networking/dns-pod-service/)。 +## Headless Services -有时不需要或不想要负载均衡,以及单独的 Service IP。 -遇到这种情况,可以通过指定 Cluster IP(`spec.clusterIP`)的值为 `"None"` 来创建 `Headless` Service。 + +有时不需要或不想要负载均衡,以及单独的 Service IP。 +遇到这种情况,可以通过指定 Cluster IP(`spec.clusterIP`)的值为 `"None"` 来创建 `Headless` Service。 +您可以使用 headless Service 与其他服务发现机制进行接口,而不必与 Kubernetes 的实现捆绑在一起。 -对这类 `Service` 并不会分配 Cluster IP,kube-proxy 不会处理它们,而且平台也不会为它们进行负载均衡和路由。 +对这 headless `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 记录 + * `ExternalName` 类型 Service 的 CNAME 记录 * 记录:与 Service 共享一个名称的任何 `Endpoints`,以及所有其它类型 + +## 发布服务 —— 服务类型 {#publishing-services-service-types} + +对一些应用(如 Frontend)的某些部分,可能希望通过外部Kubernetes 集群外部IP 地址暴露 Service。 Kubernetes `ServiceTypes` 允许指定一个需要的类型的 Service,默认是 `ClusterIP` 类型。 `Type` 的取值以及行为如下: + * `ClusterIP`:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的 `ServiceType`。 + * [`NodePort`](#nodeport):通过每个 Node 上的 IP 和静态端口(`NodePort`)暴露服务。`NodePort` 服务会路由到 `ClusterIP` 服务,这个 `ClusterIP` 服务会自动创建。通过请求 `:`,可以从集群的外部访问一个 `NodePort` 服务。 + * [`LoadBalancer`](#loadbalancer):使用云提供商的负载局衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 `NodePort` 服务和 `ClusterIP` 服务。 + * [`ExternalName`](#externalname):通过返回 `CNAME` 和它的值,可以将服务映射到 `externalName` 字段的内容(例如, `foo.bar.example.com`)。 + 没有任何类型代理被创建。 + {{< note >}} + 您需要 CoreDNS 1.7 或更高版本才能使用 `ExternalName` 类型。 + {{< /note >}} -* `ClusterIP`:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的 `ServiceType`。 -* `NodePort`:通过每个 Node 上的 IP 和静态端口(`NodePort`)暴露服务。`NodePort` 服务会路由到 `ClusterIP` 服务,这个 `ClusterIP` 服务会自动创建。通过请求 `:`,可以从集群的外部访问一个 `NodePort` 服务。 -* `LoadBalancer`:使用云提供商的负载局衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 `NodePort` 服务和 `ClusterIP` 服务。 -* `ExternalName`:通过返回 `CNAME` 和它的值,可以将服务映射到 `externalName` 字段的内容(例如, `foo.bar.example.com`)。 - 没有任何类型代理被创建,这只有 Kubernetes 1.7 或更高版本的 `kube-dns` 才支持。 - +您也可以使用 [Ingress](/docs/concepts/services-networking/ingress/) 来暴露自己的服务。 +Ingress 不是服务类型,但它充当集群的入口点。 它可以将路由规则整合到一个资源中,因为它可以在同一IP地址下公开多个服务。 + +### NodePort 类型 -这可以让开发人员自由地安装他们自己的负载均衡器,并配置 Kubernetes 不能完全支持的环境参数,或者直接暴露一个或多个 Node 的 IP 地址。 +如果将 `type` 字段设置为 `NodePort`,则 Kubernetes 控制平面将在 `--service-node-port-range` 标志指定的范围内分配端口(默认值:30000-32767)。 +每个节点将那个端口(每个节点上的相同端口号)代理到您的服务中。 +您的服务在其 `.spec.ports[*].nodePort` 字段中要求分配的端口。 +如果您想指定特定的IP代理端口,则可以将 kube-proxy 中的 `--nodeport-addresses` 标志设置为特定的IP块。从Kubernetes v1.10开始支持此功能。 +该标志采用逗号分隔的IP块列表(例如10.0.0.0/8、192.0.2.0/25)来指定 kube-proxy 应该认为是此节点本地的IP地址范围。 -需要注意的是,Service 将能够通过 `:spec.ports[*].nodePort` 和 `spec.clusterIp:spec.ports[*].port` 而对外可见。 +例如,如果您使用 `--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。 -### LoadBalancer 类型 +需要注意的是,Service 能够通过 `:spec.ports[*].nodePort` 和 `spec.clusterIp:spec.ports[*].port` 而对外可见。 + +### LoadBalancer 类型 使用支持外部负载均衡器的云提供商的服务,设置 `type` 的值为 `"LoadBalancer"`,将为 `Service` 提供负载均衡器。 负载均衡器是异步创建的,关于被提供的负载均衡器的信息将会通过 `Service` 的 `status.loadBalancer` 字段被发布出去。 +实例: ```yaml -kind: Service apiVersion: v1 +kind: Service metadata: name: my-service spec: @@ -423,7 +902,6 @@ spec: - protocol: TCP port: 80 targetPort: 9376 - nodePort: 30061 clusterIP: 10.0.171.239 loadBalancerIP: 78.11.24.19 type: LoadBalancer @@ -433,64 +911,559 @@ status: - ip: 146.148.47.155 ``` + 来自外部负载均衡器的流量将直接打到 backend `Pod` 上,不过实际它们是如何工作的,这要依赖于云提供商。 + 在这些情况下,将根据用户设置的 `loadBalancerIP` 来创建负载均衡器。 某些云提供商允许设置 `loadBalancerIP`。如果没有设置 `loadBalancerIP`,将会给负载均衡器指派一个临时 IP。 如果设置了 `loadBalancerIP`,但云提供商并不支持这种特性,那么设置的 `loadBalancerIP` 值将会被忽略掉。 - - -### AWS 内部负载均衡器 -在混合云环境中,有时从虚拟私有云(VPC)环境中的服务路由流量是非常有必要的。 -可以通过在 `Service` 中增加 `annotation` 来实现,如下所示: - +{{< note >}} + + +如果您使用的是 SCTP,请参阅下面有关 `LoadBalancer` 服务类型的 [caveat](#caveat-sctp-loadbalancer-service-type)。 +{{< /note >}} + +{{< note >}} + +在 **Azure** 上,如果要使用用户指定的公共类型 `loadBalancerIP` ,则首先需要创建静态类型的公共IP地址资源。 +此公共IP地址资源应与群集中其他自动创建的资源位于同一资源组中。 例如,`MC_myResourceGroup_myAKSCluster_eastus`。 + +将分配的IP地址指定为loadBalancerIP。 确保您已更新云提供程序配置文件中的securityGroupName。 +有关对 `CreatingLoadBalancerFailed` 权限问题进行故障排除的信息, +请参阅 [与Azure Kubernetes服务(AKS)负载平衡器一起使用静态IP地址](https://docs.microsoft.com/en-us/azure/aks/static-ip)或[通过高级网络在AKS群集上创建LoadBalancerFailed](https://github.com/Azure/AKS/issues/357)。 +{{< /note >}} + +<-- +#### Internal load balancer +In a mixed environment it is sometimes necessary to route traffic from Services inside the same +(virtual) network address block. + +In a split-horizon DNS environment you would need two Services to be able to route both external and internal traffic to your endpoints. + +You can achieve this by adding one the following annotations to a Service. +The annotation to add depends on the cloud Service provider you're using. +--> + +#### 内部负载均衡器 + +在混合环境中,有时有必要在同一(虚拟)网络地址块内路由来自服务的流量。 + +在水平分割 DNS 环境中,您需要两个服务才能将内部和外部流量都路由到您的 endpoints。 +您可以通过向服务添加以下注释之一来实现此目的。 +要添加的注释取决于您使用的云服务提供商。 + +{{< tabs name="service_tabs" >}} +{{% tab name="Default" %}} + +选择一个标签 +{{% /tab %}} +{{% tab name="GCP" %}} +```yaml +[...] +metadata: + name: my-service + annotations: + cloud.google.com/load-balancer-type: "Internal" +[...] +``` + +将 `cloud.google.com/load-balancer-type: "internal"` 节点用于版本1.7.0至1.7.3的主服务器。 +有关更多信息,请参见 [文档](https://cloud.google.com/kubernetes-engine/docs/internal-load-balancing). +{{% /tab %}} +{{% tab name="AWS" %}} ```yaml [...] -metadata: +metadata: name: my-service - annotations: - service.beta.kubernetes.io/aws-load-balancer-internal: 0.0.0.0/0 + annotations: + service.beta.kubernetes.io/aws-load-balancer-internal: "true" [...] ``` +{{% /tab %}} +{{% tab name="Azure" %}} +```yaml +[...] +metadata: + name: my-service + annotations: + service.beta.kubernetes.io/azure-load-balancer-internal: "true" +[...] +``` +{{% /tab %}} +{{% tab name="OpenStack" %}} +```yaml +[...] +metadata: + name: my-service + annotations: + service.beta.kubernetes.io/openstack-internal-load-balancer: "true" +[...] +``` +{{% /tab %}} +{{% tab name="Baidu Cloud" %}} +```yaml +[...] +metadata: + name: my-service + annotations: + service.beta.kubernetes.io/cce-load-balancer-internal-vpc: "true" +[...] +``` +{{% /tab %}} +{{< /tabs >}} + +### AWS TLS 支持 {#ssl-support-on-aws} +为了对在AWS上运行的集群提供部分TLS / SSL支持,您可以向 `LoadBalancer` 服务添加三个注释: +```yaml +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 +``` + + -### AWS SSL 支持 -对运行在 AWS 上部分支持 SSL 的集群,从 1.3 版本开始,可以为 `LoadBalancer` 类型的 `Service` 增加两个 annotation: +第一个指定要使用的证书的ARN。 它可以是已上载到 IAM 的第三方颁发者的证书,也可以是在 AWS Certificate Manager 中创建的证书。 +```yaml +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 转发流量而不修改报头。 + +在某些端口处于安全状态而其他端口未加密的混合使用环境中,可以使用以下注释: + +```yaml 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 + service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http + service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443,8443" ``` + +从Kubernetes v1.9起可以使用 [预定义的 AWS SSL 策略](http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-policy-table.html) 为您的服务使用HTTPS或SSL侦听器。 +要查看可以使用哪些策略,可以使用 `aws` 命令行工具: +```bash +aws elb describe-load-balancer-policies --query 'PolicyDescriptions[].PolicyName' +``` -第一个 annotation 指定了使用的证书。它可以是第三方发行商发行的证书,这个证书或者被上传到 IAM,或者由 AWS 的证书管理器创建。 + + +然后,您可以使用 +"`service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy`" +注解; 例如: ```yaml metadata: name: my-service annotations: - service.beta.kubernetes.io/aws-load-balancer-backend-protocol: (https|http|ssl|tcp) + service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy: "ELBSecurityPolicy-TLS-1-2-2017-01" ``` + +#### AWS上的PROXY协议支持 +为了支持在AWS上运行的集群,启用 [PROXY协议](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt), +您可以使用以下服务注释: -HTTP 和 HTTPS 将选择7层代理:ELB 将中断与用户的连接,当转发请求时,会解析 Header 信息并添加上用户的 IP 地址(`Pod` 将只能在连接的另一端看到该 IP 地址)。 +```yaml + metadata: + name: my-service + annotations: + service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*" +``` -TCP 和 SSL 将选择4层代理:ELB 将转发流量,并不修改 Header 信息。 + + +从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存储桶创建的逻辑层次结构。 + +```yaml + metadata: + name: my-service + annotations: + service.beta.kubernetes.io/aws-load-balancer-access-log-enabled: "true" + # Specifies whether access logs are enabled for the load balancer + service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval: "60" + # The interval for publishing the access logs. You can specify an interval of either 5 or 60 (minutes). + service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name: "my-bucket" + # The name of the Amazon S3 bucket where the access logs are stored + service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix: "my-bucket-prefix/prod" + # The logical hierarchy you created for your Amazon S3 bucket, for example `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` 也可以用于设置最大时间(以秒为单位),以保持现有连接在注销实例之前保持打开状态。 + +```yaml + 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注释 + +还有其他一些注释,用于管理经典弹性负载均衡器,如下所述。 +```yaml + metadata: + name: my-service + annotations: + service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "60" + # The time, in seconds, that the connection is allowed to be idle (no data has been sent over the connection) before it is closed by the load balancer + + service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true" + # Specifies whether cross-zone load balancing is enabled for the load balancer + + service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags: "environment=prod,owner=devops" + # A comma-separated list of key-value pairs which will be recorded as + # additional tags in the ELB. + + service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold: "" + # The number of successive successful health checks required for a backend to + # be considered healthy for traffic. Defaults to 2, must be between 2 and 10 + + service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold: "3" + # The number of unsuccessful health checks required for a backend to be + # considered unhealthy for traffic. Defaults to 6, must be between 2 and 10 + + service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval: "20" + # The approximate interval, in seconds, between health checks of an + # individual instance. Defaults to 10, must be between 5 and 300 + service.beta.kubernetes.io/aws-load-balancer-healthcheck-timeout: "5" + # The amount of time, in seconds, during which no response means a failed + # health check. This value must be less than the service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval + # value. Defaults to 5, must be between 2 and 60 + + service.beta.kubernetes.io/aws-load-balancer-extra-security-groups: "sg-53fae93f,sg-42efd82e" + # A list of additional security groups to be added to the ELB +``` + + + +{{< feature-state for_k8s_version="v1.15" state="beta" >}} + + + +```yaml + metadata: + name: my-service + annotations: + service.beta.kubernetes.io/aws-load-balancer-type: "nlb" +``` + +{{< note >}} + + + +NLB 仅适用于某些实例类。 有关受支持的实例类型的列表,请参见 Elastic Load Balancing 上的 [AWS文档](http://docs.aws.amazon.com/elasticloadbalancing/latest/network/target-group-register-targets.html#register-deregister-targets)。 +{{< /note >}} + + + +与经典弹性负载平衡器不同,网络负载平衡器(NLB)将客户端的 IP 地址转发到该节点。 如果服务的 `.spec.externalTrafficPolicy` 设置为 `Cluster` ,则客户端的IP地址不会传达到终端 Pod。 + +通过将 `.spec.externalTrafficPolicy` 设置为 `Local`,客户端IP地址将传播到终端 Pod,但这可能导致流量分配不均。 +没有针对特定 LoadBalancer 服务的任何 Pod 的节点将无法通过自动分配的 `.spec.healthCheckNodePort` 进行 NLB 目标组的运行状况检查,并且不会收到任何流量。 + +为了获得平均流量,请使用DaemonSet或指定 [pod anti-affinity](/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity)使其不在同一节点上。 + +您还可以将NLB服务与 [内部负载平衡器](/docs/concepts/services-networking/service/#internal-load-balancer)批注一起使用。 + +为了使客户端流量能够到达 NLB 后面的实例,使用以下 IP 规则修改了节点安全组: + +| Rule | Protocol | Port(s) | IpRange(s) | IpRange Description | +|------|----------|---------|------------|---------------------| +| Health Check | TCP | NodePort(s) (`.spec.healthCheckNodePort` for `.spec.externalTrafficPolicy = Local`) | VPC 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`。 + +```yaml +spec: + loadBalancerSourceRanges: + - "143.231.0.0/16" +``` + +{{< note >}} + + + +如果未设置 `.spec.loadBalancerSourceRanges` ,则 Kubernetes 允许从 `0.0.0.0/0` 到节点安全组的流量。 +如果节点具有公共 IP 地址,请注意,非 NLB 流量也可以到达那些修改后的安全组中的所有实例。 +{{< /note >}} + + + +### 类型ExternalName {#externalname} + +类型为 ExternalName 的服务将服务映射到 DNS 名称,而不是典型的选择器,例如 `my-service` 或者 `cassandra`。 +您可以使用 `spec.externalName` 参数指定这些服务。 + +例如,以下 Service 定义将 `prod` 名称空间中的 `my-service` 服务映射到 `my.database.example.com`: + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: my-service + namespace: prod +spec: + type: ExternalName + externalName: my.database.example.com +``` +{{< note >}} + + + +ExternalName 接受 IPv4 地址字符串,但作为包含数字的 DNS 名称,而不是 IP 地址。 类似于 IPv4 地址的外部名称不能由 CoreDNS 或 ingress-nginx 解析,因为外部名称旨在指定规范的 DNS 名称。 +要对 IP 地址进行硬编码,请考虑使用 [headless Services](#headless-services)。 +{{< /note >}} + + + +当查找主机 `my-service.prod.svc.cluster.local` 时,群集DNS服务返回 `CNAME` 记录,其值为 `my.database.example.com`。 +访问 `my-service` 的方式与其他服务的方式相同,但主要区别在于重定向发生在 DNS 级别,而不是通过代理或转发。 +如果以后您决定将数据库移到群集中,则可以启动其 Pod,添加适当的选择器或端点以及更改服务的`类型`。 + +{{< note >}} + +本部分感谢 [Alen Komljen](https://akomljen.com/)的 [Kubernetes Tips - Part1](https://akomljen.com/kubernetes-tips-part-1/) 博客文章。 +{{< /note >}} + + ### 外部 IP @@ -499,11 +1472,11 @@ TCP 和 SSL 将选择4层代理:ELB 将转发流量,并不修改 Header 信 `externalIPs` 不会被 Kubernetes 管理,它属于集群管理员的职责范畴。 根据 `Service` 的规定,`externalIPs` 可以同任意的 `ServiceType` 来一起指定。 -在上面的例子中,`my-service` 可以在 80.11.12.10:80(外部 IP:端口)上被客户端访问。 +在上面的例子中,`my-service` 可以在 "`80.11.12.10:80`"(`externalIP:port`) 上被客户端访问。 ```yaml -kind: Service apiVersion: v1 +kind: Service metadata: name: my-service spec: @@ -514,49 +1487,83 @@ spec: protocol: TCP port: 80 targetPort: 9376 - externalIPs: + 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 是强制要求的。 + -我们打算为 L7(HTTP)`Service` 改进我们对它的支持。 +## 虚拟IP实施 {#the-gory-details-of-virtual-ips} -我们打算为 `Service` 实现更加灵活的请求进入模式,这些 `Service` 包含当前 `ClusterIP`、`NodePort` 和 `LoadBalancer` 模式,或者更多。 +对很多想使用 `Service` 的人来说,前面的信息应该足够了。 +然而,有很多内部原理性的内容,还是值去理解的。 + ### 避免冲突 @@ -564,30 +1571,57 @@ Kubernetes 最主要的哲学之一,是用户不应该暴露那些能够导致 这种场景下,让我们来看一下网络端口 —— 用户不应该必须选择一个端口号,而且该端口还有可能与其他用户的冲突。 这就是说,在彼此隔离状态下仍然会出现失败。 - - 为了使用户能够为他们的 `Service` 选择一个端口号,我们必须确保不能有2个 `Service` 发生冲突。 我们可以通过为每个 `Service` 分配它们自己的 IP 地址来实现。 - - 为了保证每个 `Service` 被分配到一个唯一的 IP,需要一个内部的分配器能够原子地更新 etcd 中的一个全局分配映射表,这个更新操作要先于创建每一个 `Service`。 为了使 `Service` 能够获取到 IP,这个映射表对象必须在注册中心存在,否则创建 `Service` 将会失败,指示一个 IP 不能被分配。 一个后台 Controller 的职责是创建映射表(从 Kubernetes 的旧版本迁移过来,旧版本中是通过在内存中加锁的方式实现),并检查由于管理员干预和清除任意 IP 造成的不合理分配,这些 IP 被分配了但当前没有 `Service` 使用它们。 + + +### Service IP 地址 {#ips-and-vips} 不像 `Pod` 的 IP 地址,它实际路由到一个固定的目的地,`Service` 的 IP 实际上不能通过单个主机来进行应答。 相反,我们使用 `iptables`(Linux 中的数据包处理逻辑)来定义一个虚拟IP地址(VIP),它可以根据需要透明地进行重定向。 当客户端连接到 VIP 时,它们的流量会自动地传输到一个合适的 Endpoint。 环境变量和 DNS,实际上会根据 `Service` 的 VIP 和端口来进行填充。 - +kube-proxy支持三种代理模式: 用户空间,iptables和IPVS;它们各自的操作略有不同。 #### Userspace + + 作为一个例子,考虑前面提到的图片处理应用程序。 当创建 backend `Service` 时,Kubernetes master 会给它指派一个虚拟 IP 地址,比如 10.0.0.1。 假设 `Service` 的端口是 1234,该 `Service` 会被集群中所有的 `kube-proxy` 实例观察到。 @@ -602,29 +1636,237 @@ Kubernetes 最主要的哲学之一,是用户不应该暴露那些能够导致 客户端可以简单地连接到一个 IP 和端口,而不需要知道实际访问了哪些 `Pod`。 +#### iptables -#### Iptables + 再次考虑前面提到的图片处理应用程序。 -当创建 backend `Service` 时,Kubernetes master 会给它指派一个虚拟 IP 地址,比如 10.0.0.1。 +当创建 backend `Service` 时,Kubernetes 控制面板会给它指派一个虚拟 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 是可以更改的。 +#### IPVS + + + +在大规模集群(例如10,000个服务)中,iptables 操作会显着降低速度。 IPVS 专为负载平衡而设计,并基于内核内哈希表。 +因此,您可以通过基于 IPVS 的 kube-proxy 在大量服务中实现性能一致性。 +同时,基于 IPVS 的 kube-proxy 具有更复杂的负载平衡算法(最小连接,局部性,加权,持久性)。 + +## API Object + + +Service 是Kubernetes REST API中的顶级资源。 您可以在以下位置找到有关API对象的更多详细信息: +[Service 对象 API](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#service-v1-core). + +## Supported protocols {#protocol-support} + +### TCP + +{{< feature-state for_k8s_version="v1.0" state="stable" >}} + + +您可以将TCP用于任何类型的服务,这是默认的网络协议。 + +### UDP + +{{< feature-state for_k8s_version="v1.0" state="stable" >}} + + +您可以将UDP用于大多数服务。 对于 type=LoadBalancer 服务,对 UDP 的支持取决于提供此功能的云提供商。 + +### HTTP + +{{< feature-state for_k8s_version="v1.1" state="stable" >}} + + +如果您的云提供商支持它,则可以在 LoadBalancer 模式下使用服务来设置外部 HTTP/HTTPS 反向代理,并将其转发到该服务的 Endpoints。 + +{{< note >}} + + +您还可以使用 {{< glossary_tooltip term_id="ingress" >}} 代替 Service 来公开HTTP / HTTPS服务。 +{{< /note >}} + + +### PROXY 协议 + +{{< feature-state for_k8s_version="v1.1" state="stable" >}} + + + +如果您的云提供商支持它(例如, [AWS](/docs/concepts/cluster-administration/cloud-providers/#aws)), +则可以在 LoadBalancer 模式下使用 Service 在 Kubernetes 本身之外配置负载均衡器,该负载均衡器将转发前缀为 [PROXY协议][PROXY protocol](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 +``` + + +接下来是来自客户端的数据。 + +### SCTP + +{{< feature-state for_k8s_version="v1.12" state="alpha" >}} + + + +Kubernetes 支持 SCTP 作为 Service,Endpoint,NetworkPolicy 和 Pod 定义中的 `协议` 值作为alpha功能。 +要启用此功能,集群管理员需要在apiserver上启用 `SCTPSupport` 功能门,例如 `--feature-gates = SCTPSupport = true,…`。 + +启用功能门后,您可以将服务,端点,NetworkPolicy或Pod的 `protocol` 字段设置为 `SCTP`。 +Kubernetes相应地为 SCTP 关联设置网络,就像为 TCP 连接一样。 + + + +#### 警告 {#caveat-sctp-overview} + +##### 支持多宿主SCTP关联 {#caveat-sctp-multihomed} + +{{< warning >}} + + +对多宿主 SCTP 关联的支持要求CNI插件可以支持将多个接口和 IP 地址分配给 Pod。 +用于多宿主 SCTP 关联的 NAT 在相应的内核模块中需要特殊的逻辑。 +{{< /warning >}} + + + +##### Service 类型为 LoadBalancer 的服务 {#caveat-sctp-loadbalancer-service-type} +{{< warning >}} + + +如果云提供商的负载平衡器实现支持将 SCTP 作为协议,则只能使用 `类型` LoadBalancer 加上 `协议` SCTP 创建服务。 否则,服务创建请求将被拒绝。 当前的云负载平衡器提供商(Azure,AWS,CloudStack,GCE,OpenStack)都缺乏对 SCTP 的支持。 +{{< /warning >}} + +##### Windows {#caveat-sctp-windows-os} + +{{< warning >}} + + +基于Windows的节点不支持SCTP。 +{{< /warning >}} + +##### Userspace kube-proxy {#caveat-sctp-kube-proxy-userspace} + +{{< warning >}} + + +当 kube-proxy 处于用户空间模式时,它不支持 SCTP 关联的管理。 +{{< /warning >}} + + +## 未来工作 + +未来我们能预见到,代理策略可能会变得比简单的 round-robin 均衡策略有更多细微的差别,比如 master 选举或分片。 +我们也能想到,某些 `Service` 将具有 “真正” 的负载均衡器,这种情况下 VIP 将简化数据包的传输。 + +Kubernetes 项目打算为 L7(HTTP)`Service` 改进我们对它的支持。 +Kubernetes 项目打算为 `Service` 实现更加灵活的请求进入模式,这些 `Service` 包含当前 `ClusterIP`、`NodePort` 和 `LoadBalancer` 模式,或者更多。 -## API 对象 -在 Kubernetes REST API 中,Service 是 top-level 资源。关于 API 对象的更多细节可以查看:[Service API 对象](/docs/api-reference/{{< param "version" >}}/#service-v1-core)。 +{{% /capture %}} +{{% capture whatsnext %}} + -## 更多信息 +* 阅读 [Connecting Applications with Services](/docs/concepts/services-networking/connect-applications-service/) +* 阅读 [Ingress](/docs/concepts/services-networking/ingress/) +* 阅读 [Endpoint Slices](/docs/concepts/services-networking/endpoint-slices/) -阅读 [使用 Service 连接 Frontend 到 Backend](/docs/tutorials/connecting-apps/connecting-frontend-backend/)。 +{{% /capture %}} diff --git a/content/zh/docs/reference/glossary/ingress.md b/content/zh/docs/reference/glossary/ingress.md new file mode 100755 index 0000000000000..1f5beff1218a3 --- /dev/null +++ b/content/zh/docs/reference/glossary/ingress.md @@ -0,0 +1,24 @@ +--- +title: Ingress +id: ingress +date: 2018-04-12 +full_link: /docs/concepts/services-networking/ingress/ +short_description: > + An API object that manages external access to the services in a cluster, typically HTTP. + +aka: +tags: +- networking +- architecture +- extension +--- + +一个 API 对象,用于管理对集群中服务的外部访问,通常是 HTTP。 + + + +Ingress 可以提供负载平衡,SSL 终端和基于名称的虚拟主机。 diff --git a/content/zh/docs/reference/glossary/service.md b/content/zh/docs/reference/glossary/service.md new file mode 100755 index 0000000000000..657db3aa06975 --- /dev/null +++ b/content/zh/docs/reference/glossary/service.md @@ -0,0 +1,25 @@ +--- +title: Service +id: service +date: 2018-04-12 +full_link: /docs/concepts/services-networking/service/ +short_description: > + A way to expose an application running on a set of Pods as a network service. + +aka: +tags: +- fundamental +- core-object +--- + + +将运行在一组 {{< glossary_tooltip text="Pods" term_id="pod" >}} 上的应用程序公开为网络服务的抽象方法。 + + + + +服务所针对的Pod集(通常)由 {{< glossary_tooltip text="selector" term_id="selector" >}} 确定。 如果添加或删除了更多Pod,则与选择器匹配的Pod集将发生变化。 该服务确保可以将网络流量定向到该工作负载的当前Pod集。 \ No newline at end of file diff --git a/content/zh/examples/service/access/Dockerfile b/content/zh/examples/service/access/Dockerfile new file mode 100644 index 0000000000000..b7b09d492a2be --- /dev/null +++ b/content/zh/examples/service/access/Dockerfile @@ -0,0 +1,4 @@ +FROM nginx:1.17.3 + +RUN rm /etc/nginx/conf.d/default.conf +COPY frontend.conf /etc/nginx/conf.d diff --git a/content/zh/examples/service/access/frontend.conf b/content/zh/examples/service/access/frontend.conf new file mode 100644 index 0000000000000..9a1f5a0ed63a8 --- /dev/null +++ b/content/zh/examples/service/access/frontend.conf @@ -0,0 +1,11 @@ +upstream hello { + server hello; +} + +server { + listen 80; + + location / { + proxy_pass http://hello; + } +} diff --git a/content/zh/examples/service/access/frontend.yaml b/content/zh/examples/service/access/frontend.yaml new file mode 100644 index 0000000000000..9f5b6b757fe8c --- /dev/null +++ b/content/zh/examples/service/access/frontend.yaml @@ -0,0 +1,39 @@ +apiVersion: v1 +kind: Service +metadata: + name: frontend +spec: + selector: + app: hello + tier: frontend + ports: + - protocol: "TCP" + port: 80 + targetPort: 80 + type: LoadBalancer +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: frontend +spec: + selector: + matchLabels: + app: hello + tier: frontend + track: stable + replicas: 1 + template: + metadata: + labels: + app: hello + tier: frontend + track: stable + spec: + containers: + - name: nginx + image: "gcr.io/google-samples/hello-frontend:1.0" + lifecycle: + preStop: + exec: + command: ["/usr/sbin/nginx","-s","quit"] diff --git a/content/zh/examples/service/access/hello-application.yaml b/content/zh/examples/service/access/hello-application.yaml new file mode 100644 index 0000000000000..1cf41313c5dde --- /dev/null +++ b/content/zh/examples/service/access/hello-application.yaml @@ -0,0 +1,20 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: hello-world +spec: + selector: + matchLabels: + run: load-balancer-example + replicas: 2 + template: + metadata: + labels: + run: load-balancer-example + spec: + containers: + - name: hello-world + image: gcr.io/google-samples/node-hello:1.0 + ports: + - containerPort: 8080 + protocol: TCP diff --git a/content/zh/examples/service/access/hello-service.yaml b/content/zh/examples/service/access/hello-service.yaml new file mode 100644 index 0000000000000..71344ecb8be13 --- /dev/null +++ b/content/zh/examples/service/access/hello-service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: hello +spec: + selector: + app: hello + tier: backend + ports: + - protocol: TCP + port: 80 + targetPort: http diff --git a/content/zh/examples/service/access/hello.yaml b/content/zh/examples/service/access/hello.yaml new file mode 100644 index 0000000000000..85dff18ee1d80 --- /dev/null +++ b/content/zh/examples/service/access/hello.yaml @@ -0,0 +1,24 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: hello +spec: + selector: + matchLabels: + app: hello + tier: backend + track: stable + replicas: 7 + template: + metadata: + labels: + app: hello + tier: backend + track: stable + spec: + containers: + - name: hello + image: "gcr.io/google-samples/hello-go-gke:1.0" + ports: + - name: http + containerPort: 80 diff --git a/content/zh/examples/service/load-balancer-example.yaml b/content/zh/examples/service/load-balancer-example.yaml new file mode 100644 index 0000000000000..ea88fd154868c --- /dev/null +++ b/content/zh/examples/service/load-balancer-example.yaml @@ -0,0 +1,21 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/name: load-balancer-example + name: hello-world +spec: + replicas: 5 + selector: + matchLabels: + app.kubernetes.io/name: load-balancer-example + template: + metadata: + labels: + app.kubernetes.io/name: load-balancer-example + spec: + containers: + - image: gcr.io/google-samples/node-hello:1.0 + name: hello-world + ports: + - containerPort: 8080 diff --git a/content/zh/docs/concepts/services-networking/curlpod.yaml b/content/zh/examples/service/networking/curlpod.yaml similarity index 87% rename from content/zh/docs/concepts/services-networking/curlpod.yaml rename to content/zh/examples/service/networking/curlpod.yaml index 0741a58e7f563..c15133641f541 100644 --- a/content/zh/docs/concepts/services-networking/curlpod.yaml +++ b/content/zh/examples/service/networking/curlpod.yaml @@ -1,8 +1,11 @@ -apiVersion: apps/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: curl-deployment spec: + selector: + matchLabels: + app: curlpod replicas: 1 template: metadata: diff --git a/content/zh/examples/service/networking/custom-dns.yaml b/content/zh/examples/service/networking/custom-dns.yaml new file mode 100644 index 0000000000000..02f77a9efe09d --- /dev/null +++ b/content/zh/examples/service/networking/custom-dns.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Pod +metadata: + namespace: default + name: dns-example +spec: + containers: + - name: test + image: nginx + dnsPolicy: "None" + dnsConfig: + nameservers: + - 1.2.3.4 + searches: + - ns1.svc.cluster-domain.example + - my.dns.search.suffix + options: + - name: ndots + value: "2" + - name: edns0 diff --git a/content/zh/examples/service/networking/dual-stack-default-svc.yaml b/content/zh/examples/service/networking/dual-stack-default-svc.yaml new file mode 100644 index 0000000000000..00ed87ba196be --- /dev/null +++ b/content/zh/examples/service/networking/dual-stack-default-svc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: my-service +spec: + selector: + app: MyApp + ports: + - protocol: TCP + port: 80 + targetPort: 9376 \ No newline at end of file diff --git a/content/zh/examples/service/networking/dual-stack-ipv4-svc.yaml b/content/zh/examples/service/networking/dual-stack-ipv4-svc.yaml new file mode 100644 index 0000000000000..a875f44d6d060 --- /dev/null +++ b/content/zh/examples/service/networking/dual-stack-ipv4-svc.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: my-service +spec: + ipFamily: IPv4 + selector: + app: MyApp + ports: + - protocol: TCP + port: 80 + targetPort: 9376 \ No newline at end of file diff --git a/content/zh/examples/service/networking/dual-stack-ipv6-lb-svc.yaml b/content/zh/examples/service/networking/dual-stack-ipv6-lb-svc.yaml new file mode 100644 index 0000000000000..2586ec9b39a44 --- /dev/null +++ b/content/zh/examples/service/networking/dual-stack-ipv6-lb-svc.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: my-service + labels: + app: MyApp +spec: + ipFamily: IPv6 + type: LoadBalancer + selector: + app: MyApp + ports: + - protocol: TCP + port: 80 + targetPort: 9376 \ No newline at end of file diff --git a/content/zh/examples/service/networking/dual-stack-ipv6-svc.yaml b/content/zh/examples/service/networking/dual-stack-ipv6-svc.yaml new file mode 100644 index 0000000000000..2aa0725059bbc --- /dev/null +++ b/content/zh/examples/service/networking/dual-stack-ipv6-svc.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: my-service +spec: + ipFamily: IPv6 + selector: + app: MyApp + ports: + - protocol: TCP + port: 80 + targetPort: 9376 \ No newline at end of file diff --git a/content/zh/docs/concepts/services-networking/hostaliases-pod.yaml b/content/zh/examples/service/networking/hostaliases-pod.yaml similarity index 93% rename from content/zh/docs/concepts/services-networking/hostaliases-pod.yaml rename to content/zh/examples/service/networking/hostaliases-pod.yaml index aa57b9a9e5562..643813b34a13d 100644 --- a/content/zh/docs/concepts/services-networking/hostaliases-pod.yaml +++ b/content/zh/examples/service/networking/hostaliases-pod.yaml @@ -3,6 +3,7 @@ kind: Pod metadata: name: hostaliases-pod spec: + restartPolicy: Never hostAliases: - ip: "127.0.0.1" hostnames: diff --git a/content/zh/docs/concepts/services-networking/ingress.yaml b/content/zh/examples/service/networking/ingress.yaml similarity index 100% rename from content/zh/docs/concepts/services-networking/ingress.yaml rename to content/zh/examples/service/networking/ingress.yaml diff --git a/content/zh/docs/concepts/services-networking/nginx-secure-app.yaml b/content/zh/examples/service/networking/nginx-secure-app.yaml similarity index 100% rename from content/zh/docs/concepts/services-networking/nginx-secure-app.yaml rename to content/zh/examples/service/networking/nginx-secure-app.yaml diff --git a/content/zh/docs/concepts/services-networking/nginx-svc.yaml b/content/zh/examples/service/networking/nginx-svc.yaml similarity index 100% rename from content/zh/docs/concepts/services-networking/nginx-svc.yaml rename to content/zh/examples/service/networking/nginx-svc.yaml diff --git a/content/zh/docs/concepts/services-networking/run-my-nginx.yaml b/content/zh/examples/service/networking/run-my-nginx.yaml similarity index 100% rename from content/zh/docs/concepts/services-networking/run-my-nginx.yaml rename to content/zh/examples/service/networking/run-my-nginx.yaml diff --git a/content/zh/examples/service/nginx-service.yaml b/content/zh/examples/service/nginx-service.yaml new file mode 100644 index 0000000000000..810f0ec7d8633 --- /dev/null +++ b/content/zh/examples/service/nginx-service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: nginx-service +spec: + ports: + - port: 8000 # the port that this service should serve on + # the container on each pod to connect to, can be a name + # (e.g. 'www') or a number (e.g. 80) + targetPort: 80 + protocol: TCP + # just like the selector in the deployment, + # but this time it identifies the set of pods to load balance + # traffic to. + selector: + app: nginx