diff --git a/content/zh/docs/tutorials/services/source-ip.md b/content/zh/docs/tutorials/services/source-ip.md index 2bc7a5c4f9a2f..f4369268ce065 100644 --- a/content/zh/docs/tutorials/services/source-ip.md +++ b/content/zh/docs/tutorials/services/source-ip.md @@ -7,7 +7,7 @@ content_template: templates/tutorial {{% capture overview %}} -Kubernetes 集群中运行的应用通过抽象的 Service 查找彼此,相互通信和连接外部世界。本文揭示了发送到不同类型 Services 的数据包源 IP 的内幕,你可以根据需求改变这个行为。 +Kubernetes 集群中运行的应用通过 Service 抽象来互相查找、通信和与外部世界沟通。本文介绍被发送到不同类型 Services 的数据包源 IP 的变化过程,你可以根据你的需求改变这些行为。 {{% /capture %}} @@ -31,11 +31,14 @@ Kubernetes 集群中运行的应用通过抽象的 Service 查找彼此,相互 ## 准备工作 -你必须拥有一个正常工作的 Kubernetes 1.5 集群,用来运行本文中的示例。该示例使用一个简单的 nginx webserver 回送它接收到的请求的 HTTP 头中的源 IP 地址。你可以像下面这样创建它: +你必须拥有一个正常工作的 Kubernetes 1.5 集群来运行此文档中的示例。该示例使用一个简单的 nginx webserver,通过一个HTTP消息头返回它接收到请求的源IP。你可以像下面这样创建它: ```console -$ kubectl run source-ip-app --image=k8s.gcr.io/echoserver:1.4 -deployment "source-ip-app" created +kubectl run source-ip-app --image=k8s.gcr.io/echoserver:1.4 +``` +输出结果为 +``` +deployment.apps/source-ip-app created ``` {{% /capture %}} @@ -45,7 +48,7 @@ deployment "source-ip-app" created * 通过多种类型的 Services 暴露一个简单应用 * 理解每种 Service 类型如何处理源 IP NAT -* 理解保留源 IP 的折中 +* 理解保留源IP所涉及的折中 {{% /capture %}} @@ -59,33 +62,50 @@ deployment "source-ip-app" created 如果你的 kube-proxy 运行在 [iptables 模式](/docs/user-guide/services/#proxy-mode-iptables)下,从集群内部发送到 ClusterIP 的包永远不会进行源地址 NAT,这从 Kubernetes 1.2 开始是默认选项。Kube-proxy 通过一个 `proxyMode` endpoint 暴露它的模式。 ```console -$ kubectl get nodes -NAME STATUS AGE VERSION -kubernetes-minion-group-6jst Ready 2h v1.6.0+fff5156 -kubernetes-minion-group-cx31 Ready 2h v1.6.0+fff5156 -kubernetes-minion-group-jj1t Ready 2h v1.6.0+fff5156 - -kubernetes-minion-group-6jst $ curl localhost:10249/proxyMode +kubectl get nodes +``` +输出结果与以下结果类似: +``` +NAME STATUS ROLES AGE VERSION +kubernetes-node-6jst Ready 2h v1.13.0 +kubernetes-node-cx31 Ready 2h v1.13.0 +kubernetes-node-jj1t Ready 2h v1.13.0 +``` +从其中一个节点中得到代理模式 +```console +kubernetes-node-6jst $ curl localhost:10249/proxyMode +``` +输出结果为: +``` iptables ``` - -你可以通过在 source IP 应用上创建一个服务来测试源 IP 保留。 +你可以通过在source IP应用上创建一个Service来测试源IP保留。 ```console -$ kubectl expose deployment source-ip-app --name=clusterip --port=80 --target-port=8080 -service "clusterip" exposed - -$ kubectl get svc clusterip -NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE -clusterip 10.0.170.92 80/TCP 51s +kubectl expose deployment source-ip-app --name=clusterip --port=80 --target-port=8080 +``` +输出结果为: +``` +service/clusterip exposed +``` +```console +kubectl get svc clusterip +``` +输出结果与以下结果类似: +``` +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +clusterip ClusterIP 10.0.170.92 80/TCP 51s ``` 从相同集群中的一个 pod 访问这个 `ClusterIP`: ```console -$ kubectl run busybox -it --image=busybox --restart=Never --rm +kubectl run busybox -it --image=busybox --restart=Never --rm +``` +输出结果与以下结果类似: +``` Waiting for pod default/busybox to be running, status is Pending, pod ready: false If you don't see a command prompt, try pressing enter. @@ -116,21 +136,29 @@ command=GET ## Type=NodePort 类型 Services 的 Source IP -对于 Kubernetes 1.5,发送给类型为 [Type=NodePort](/docs/user-guide/services/#type-nodeport) Services 的数据包默认进行源地址 NAT。你可以创建一个 `NodePort` Service 来进行测试: +从 Kubernetes 1.5 开始,发送给类型为 [Type=NodePort](/docs/user-guide/services/#type-nodeport) Services 的数据包默认进行源地址 NAT。你可以通过创建一个 `NodePort` Service 来进行测试: ```console -$ kubectl expose deployment source-ip-app --name=nodeport --port=80 --target-port=8080 --type=NodePort -service "nodeport" exposed +kubectl expose deployment source-ip-app --name=nodeport --port=80 --target-port=8080 --type=NodePort +``` +输出结果为: +``` +service/nodeport exposed +``` -$ NODEPORT=$(kubectl get -o jsonpath="{.spec.ports[0].nodePort}" services nodeport) -$ NODES=$(kubectl get nodes -o jsonpath='{ $.items[*].status.addresses[?(@.type=="ExternalIP")].address }') +```console +NODEPORT=$(kubectl get -o jsonpath="{.spec.ports[0].nodePort}" services nodeport) +NODES=$(kubectl get nodes -o jsonpath='{ $.items[*].status.addresses[?(@.type=="ExternalIP")].address }') ``` 如果你的集群运行在一个云服务上,你可能需要为上面报告的 `nodes:nodeport` 开启一条防火墙规则。 现在,你可以通过上面分配的节点端口从外部访问这个 Service。 ```console -$ for node in $NODES; do curl -s $node:$NODEPORT | grep -i client_address; done +for node in $NODES; do curl -s $node:$NODEPORT | grep -i client_address; done +``` +输出结果与以下结果类似: +``` client_address=10.180.1.1 client_address=10.240.0.5 client_address=10.240.0.3 @@ -146,7 +174,7 @@ client_address=10.240.0.3 * Pod 的回复被发送回给客户端 -形象的: +用图表示: ``` client @@ -167,15 +195,21 @@ client_address=10.240.0.3 设置 `service.spec.externalTrafficPolicy` 字段如下: ```console -$ kubectl patch svc nodeport -p '{"spec":{"externalTrafficPolicy":"Local"}}' -service "nodeport" patched +kubectl patch svc nodeport -p '{"spec":{"externalTrafficPolicy":"Local"}}' +``` +输出结果为: +``` +service/nodeport patched ``` 现在,重新运行测试: ```console -$ for node in $NODES; do curl --connect-timeout 1 -s $node:$NODEPORT | grep -i client_address; done +for node in $NODES; do curl --connect-timeout 1 -s $node:$NODEPORT | grep -i client_address; done +``` +输出结果为: +``` client_address=104.132.1.79 ``` @@ -191,7 +225,7 @@ client_address=104.132.1.79 * node1 使用正确的源 IP 地址将数据包路由到 endpoint -形象的: +用图表示: ``` client @@ -210,20 +244,34 @@ client_address=104.132.1.79 ## Type=LoadBalancer 类型 Services 的 Source IP -对于 Kubernetes 1.5,发送给类型为 [Type=LoadBalancer](/docs/user-guide/services/#type-nodeport) Services 的数据包默认进行源地址 NAT,这是由于所有处于 `Ready` 状态的 Kubernetes 节点对于负载均衡的流量都是符合条件的。所以如果数据包到达一个没有 endpoint 的节点,系统将把这个包代理到*有* endpoint 的节点,并替换数据包的源 IP 为节点的 IP(如前面章节所述)。 +从Kubernetes1.5开始,发送给类型为 [Type=LoadBalancer](/docs/user-guide/services/#type-nodeport) Services 的数据包默认进行源地址 NAT,这是因为所有处于 `Ready` 状态的可调度 Kubernetes 节点对于负载均衡的流量都是符合条件的。所以如果数据包到达一个没有 endpoint 的节点,系统将把这个包代理到*有* endpoint 的节点,并替换数据包的源 IP 为节点的 IP(如前面章节所述)。 你可以通过在一个 loadbalancer 上暴露这个 source-ip-app 来进行测试。 ```console -$ kubectl expose deployment source-ip-app --name=loadbalancer --port=80 --target-port=8080 --type=LoadBalancer -service "loadbalancer" exposed +kubectl expose deployment source-ip-app --name=loadbalancer --port=80 --target-port=8080 --type=LoadBalancer +``` +输出结果为: +``` +service/loadbalancer exposed +``` -$ kubectl get svc loadbalancer -NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE -loadbalancer 10.0.65.118 104.198.149.140 80/TCP 5m +打印Service的IPs: +```console +kubectl get svc loadbalancer +``` +输出结果与以下结果类似: +``` +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +loadbalancer LoadBalancer 10.0.65.118 104.198.149.140 80/TCP 5m +``` -$ curl 104.198.149.140 +```console +curl 104.198.149.140 +``` +输出结果与以下结果类似: +``` CLIENT VALUES: client_address=10.240.0.5 ... @@ -233,7 +281,7 @@ client_address=10.240.0.5 然而,如果你的集群运行在 Google Kubernetes Engine/GCE 上,设置 `service.spec.externalTrafficPolicy` 字段值为 `Local` 可以强制使*没有* endpoints 的节点把他们自己从负载均衡流量的可选节点名单中删除。这是通过故意使它们健康检查失败达到的。 -形象的: +用图表示: ``` client @@ -251,29 +299,44 @@ health check ---> node 1 node 2 <--- health check 你可以设置 annotation 来进行测试: ```console -$ kubectl patch svc loadbalancer -p '{"spec":{"externalTrafficPolicy":"Local"}}' +kubectl patch svc loadbalancer -p '{"spec":{"externalTrafficPolicy":"Local"}}' ``` 你应该能够立即看到 Kubernetes 分配的 `service.spec.healthCheckNodePort` 字段: ```console -$ kubectl get svc loadbalancer -o yaml | grep -i healthCheckNodePort +kubectl get svc loadbalancer -o yaml | grep -i healthCheckNodePort +``` +输出结果与以下结果类似: +``` healthCheckNodePort: 32122 ``` `service.spec.healthCheckNodePort` 字段指向每个节点在 `/healthz` 路径上提供的用于健康检查的端口。你可以这样测试: +```console +kubectl get pod -o wide -l run=source-ip-app +``` +输出结果与以下结果类似: ``` -$ kubectl get pod -o wide -l run=source-ip-app NAME READY STATUS RESTARTS AGE IP NODE -source-ip-app-826191075-qehz4 1/1 Running 0 20h 10.180.1.136 kubernetes-minion-group-6jst - -kubernetes-minion-group-6jst $ curl localhost:32122/healthz +source-ip-app-826191075-qehz4 1/1 Running 0 20h 10.180.1.136 kubernetes-node-6jst +``` +使用 curl 命令发送请求到每个节点的 `/healthz` 路径。 +```console +kubernetes-node-6jst $ curl localhost:32122/healthz +``` +输出结果与以下结果类似: +``` 1 Service Endpoints found - -kubernetes-minion-group-jj1t $ curl localhost:32122/healthz +``` +```console +kubernetes-node-jj1t $ curl localhost:32122/healthz +``` +输出结果与以下结果类似: +``` No Service Endpoints Found ``` @@ -281,7 +344,10 @@ No Service Endpoints Found 主节点运行的 service 控制器负责分配 cloud loadbalancer。在这样做的同时,它也会分配指向每个节点的 HTTP 健康检查的 port/path。等待大约 10 秒钟之后,没有 endpoints 的两个节点的健康检查会失败,然后 curl 负载均衡器的 ip: ```console -$ curl 104.198.149.140 +curl 104.198.149.140 +``` +输出结果与以下结果类似: +``` CLIENT VALUES: client_address=104.132.1.79 ... @@ -291,7 +357,7 @@ client_address=104.132.1.79 __跨平台支持__ -由于 Kubernetes 1.5 在类型为 Type=LoadBalancer 的 Services 中支持源 IP 保存的特性仅在 cloudproviders 的子集中实现(GCP and Azure)。你的集群运行的 cloudprovider 可能以某些不同的方式满足 loadbalancer 的要求: +从 Kubernetes 1.5 开始,通过类型为 Type=LoadBalancer 的 Services 进行源 IP 保存的支持仅在一部分 cloudproviders 中实现(GCP and Azure)。你的集群运行的 cloudprovider 可能以某些不同的方式满足 loadbalancer 的要求: 1. 使用一个代理终止客户端连接并打开一个到你的 nodes/endpoints 的新连接。在这种情况下,源 IP 地址将永远是云负载均衡器的地址而不是客户端的。 @@ -327,5 +393,3 @@ $ kubectl delete deployment source-ip-app * 学习更多关于 [通过 services 连接应用](/docs/concepts/services-networking/connect-applications-service/) * 学习更多关于 [负载均衡](/docs/user-guide/load-balancer) {{% /capture %}} - -