如何简化Kubernetes入站和出站流量管理

NGINX | 2021年6月28日

在以下情况下,服务网格实际上可能会增加Kubernetes环境的管理复杂性:必须将其与Ingress控制器分开配置。分开配置不只是耗时,还会增加配置错误的概率。这些错误可能导致流量无法正确路由,甚至引发安全漏洞(例如,恶意行为者获得受限应用的访问权限)和不良体验(例如,客户无法访问其有权使用的应用)。除了分开配置所需的时间外,还需要花费更多时间排查错误。

通过将基于NGINX Plus的NGINX Ingress Controller与NGINX Service Mesh集成,以控制入站和出站mTLS流量,可以避免这些问题并节省时间。本视频演示将介绍完整步骤。

以下章节引用了支持文档:

先决条件(0:18)

在开始实际演示之前,我们完成了以下准备工作:

  1. 在Kubernetes集群中安装了NGINX Server Mesh control plane,并为服务网格设置了mTLS和strict策略。
  2. 在Kubernetes集群中将基于NGINX Plus的NGINX Ingress Controller安装为Deployment(而非DaemonSet),并启用出站流量,然后将其公开为以下类型的服务:LoadBalancer。注意:此演示不适用于基于NGINX Open Source的NGINX Ingress Controller。为便于阅读,本文后续将基于NGINX Plus的NGINX Ingress Controller简称为“NGINX Ingress Controller”。
  3. 按照我们的说明下载示例bookinfo应用,注入NGINX Service Mesh边车,并部署该应用。

由于在步骤 1 中创建了strict策略,来自网格外部客户端、发往bookinfo应用的请求会被 sidecar 拒绝。在演示中,我们首先运行以下命令设置端口转发,以说明这一点:

> kubectl port-forward svc/product-page 9080Forwarding from 127.0.0.1:9080 -> 9080
Forwarding from [::1]:9080 -> 9080
Handling connection for 9080

尝试访问该应用时,会收到状态码 503,因为本地计算机不属于服务网格:

> curl localhost:9080503

使用 NGINX Service Mesh 部署 NGINX Ingress Controller(1:50)

公开应用流程的第一步是部署一个NGINX Ingress Controller实例。相关说明请参阅教程《使用NGINX Plus Ingress Controller for Kubernetes进行部署》。

为此,NGINX同时提供Deployment和DaemonSet清单。在本演示中,我们使用Deployment清单nginx-plus-ingress.yaml。该清单包含相关注解,用于通过同一个NGINX Ingress Controller实例路由入站和出站流量:

正在加载代码示例…

该清单支持NGINX Ingress Controller与NGINX Service Mesh的证书颁发机构(CA)Spire直接集成,无需将NGINX Service Mesh边车注入NGINX Ingress Controller。NGINX Ingress Controller会直接从Spire CA获取证书和密钥,用于与网格中的Pod进行mTLS通信。该清单指定了Spire代理地址:

正在加载代码示例…

并将Spire代理的UNIX套接字挂载到NGINX Ingress Controller Pod:

正在加载代码示例…

关于该清单,最后需要注意的是-enable-internal-routes CLI参数。该参数支持将流量路由到出口服务:

正在加载代码示例…

开始演示前,我们运行了kubectl apply -f nginx-plus-ingress.yaml命令来安装NGINX Ingress Controller。现在,我们检查nginx-ingress命名空间中的部署。如下方输出的READY列所示,NGINX Ingress Controller Pod中只有一个容器,因为我们尚未向其中注入NGINX Service Mesh边车。

我们还部署了一个类型为LoadBalancer的服务,以便从集群外部访问NGINX Ingress Controller的外部IP地址(此处为35.233.133.188)。我们将通过该IP地址访问示例bookinfo应用。

> kubectl get pods --namespace=nginx-ingressNAME                                 READY   STATUS    RESTARTS   AGE
pod/nginx-ingress-867f954b8f0fzdrm   1/1     Running   0          3d3h

NAME                    TYPE           CLUSTER-IP      EXTERNAL-IP      ...
service-nginx-ingress   LoadBalancer   10.31.245.207   35.233.133.188   ...

      ... PORT(S)                      AGE
      ... 80:31469/TCP,443:32481/TCP   4d2h
...

使用标准Kubernetes Ingress资源公开应用(3:55)

现在,我们使用bookinfo-ingress.yaml中定义的标准Kubernetes Ingress资源,将网格中的bookinfo应用公开。相关说明请参阅教程《使用NGINX Plus Ingress Controller公开应用》。

正在加载代码示例…

该资源在第10行引用了用于bookinfo应用的Kubernetes Secret,并包含一条路由规则,指定将对bookinfo.example.com的请求发送到productpage服务(第11至18行)。该Secret在bookinfo-secret.yaml中定义:

正在加载代码示例…

运行此命令以加载密钥和证书;演示中使用的是自签名证书:

> kubectl apply -f bookinfo-secret.yamlsecret/bookinfo-secret unchanged

激活Ingress资源:

> kubectl apply -f bookinfo-ingress.yamlingress.networking.k8s.io/bookinfo-ingress deleted

并验证Ingress Controller是否已添加该资源中定义的路由,输出末尾的事件可确认这一点:

> kubectl describe ingress bookinfo-ingress...
Events:
  Type    Reason          Age   From                      Message
  ----    ------          ----  ----                      -------
  Normal  AddedOrUpdated  5s    nginx-ingress-controller  Configuration for ...
        ...default/bookinfo-ingress was added or updated

现在,在演示中,我们使用浏览器访问位于bookinfo的应用,地址为https://bookinfo.example.com/。(我们之前已在本地/etc/hosts文件中添加了Ingress Controller服务IP地址(如上所述,演示中为35.233.133.188)与bookinfo.example.com之间的映射。有关操作说明,请参阅文档。)随着请求在Book Reviews服务的3个版本之间轮转,页面中reviews部分的信息会定期变化。这3个版本在bookinfo.yaml中定义(下载)。

接下来,我们检查进入集群的入口流量。运行 generate-traffic.sh 脚本,通过 NGINX Ingress Controller 的公共 IP 地址向 productpage 服务发出请求,然后运行 nginx-meshctl top 命令来监控流量:

> nginxmesh-ctl top deploy/productpage-v1Deployment       Direction  Resource       Success Rate  P99    P90    P50   ...
productpage-v1  
                 To         details-v1     100.00%       3ms    3ms    2ms   
                 To         reviews-v2     100.00%       99ms   90ms   20ms
                 To         reviews-v3     100.00%       99ms   85ms   18ms
                 To         reviews-v1     100.00%       20ms   17ms   9ms
                 From       nginx-ingress  100.00%       192ms  120ms  38ms

      ... NumRequests 
      ... 14
      ... 5
      ... 5
      ... 12

使用NGINX VirtualServer资源公开应用(6:45)

接下来,我们将介绍另一种公开应用的方法,即使用NGINX VirtualServer资源。这是NGINX Ingress Controller的一种自定义资源,支持更复杂的流量处理,例如流量拆分和基于内容的路由。

首先,删除标准Ingress资源:

> kubectl delete -f bookinfo-ingress.yamlingress.networking.k8s.io "bookinfo-ingress" deleted

bookinfo-vs.yaml文件使用与bookinfo-ingress.yaml相同的Secret配置mTLS(第7–8行)。第9–12行将productpage服务定义为上游,第13–24行定义一条路由,将向bookinfo.example.com发出的所有GET请求转发到该上游。对于除GET以外的HTTP方法,将返回状态码405。

正在加载代码示例…

应用该资源:

> kubectl apply -f bookinfo-vs.yamlvirtualserver.kubernetes.nginx.org/bookinfo-vs created

然后执行与Ingress资源相同的步骤,即运行kubectl describe命令以确认部署正确,并在浏览器中访问该应用。该应用拒绝POST方法,这也表明应用运行正常:

> curl -k -X POST https://bookinfo.example.com/Method not allowed

使用NGINX Ingress Controller配置安全出口路由(8:44)

下面介绍如何通过NGINX Ingress Controller路由出站流量。教程《使用NGINX Plus Ingress Controller配置安全出站路由》使用不同的示例应用介绍了这一过程。

我们已在bash中定义了一个简单的bash.yaml Pod,并将其部署到用于发送请求的默认命名空间中。如下方输出的READY列所示,该Pod已注入NGINX Service Mesh边车。

> kubectl get allNAME                        READY  STATUS    RESTARTS   AGE
pod/bash-6ccb678958-zsgm7   2/2    Running   0          77s

NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.31.240.1   <none>        443/TCP   4d2h
...

在一些用例中,您可能需要允许从Pod内部向出口服务发出请求。出口服务是指不属于NGINX Service Mesh的任何实体,例如部署在以下位置的服务:

  • 集群外部
  • 在另一个集群上
  • 位于同一集群中,但未注入NGINX Service Mesh边车

在此演示中,我们将介绍最后一种用例。我们在legacy命名空间中部署了一个应用。该命名空间不受NGINX Service Mesh控制,并且已禁用NGINX Service Mesh边车的自动注入。此应用仅运行一个Pod。

> kubectl get all --namespaces=legacyNAME                          READY  STATUS    RESTARTS   AGE
pod/target-5f7bcb96c6-km9lz   1/1    Running   0          27m

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/target-svc   ClusterIP   10.31.245.213   <none>        80/TCP,443/TCP   27m
...

请注意,我们已为NGINX Service Mesh配置了strict mTLS策略;因此,无法直接从bash Pod向目标服务发送请求,因为二者无法相互进行身份验证。尝试发送请求时,会收到状态码503,如下所示:

> kubectl exec -it bash-6ccb678958-zsgm7 -c bash -- curl target-svc.legacycurl: (56) Recv failure: connection reset by peer
503command terminated with exit code 56

解决方法是让bash Pod通过NGINX Ingress Controller发送出站流量。取消注释bash.yaml第14至15行的注解:

正在加载代码示例…

然后应用新配置:

> kubectl apply -f bash.yamldeployment.apps/bash configured

并验证新的bash Pod已启动:

> kubectl get podsNAME                    READY  STATUS        RESTARTS   AGE
bash-678c8b4579-7sfml   2/2    Running       0          6s
bash-6ccb678958-zsgm7   2/2    Terminating   0          3m28s

现在,当我们像之前一样运行相同的kubectl exec命令,从bash Pod向目标服务发送请求时,收到的状态码是404,而不是503。这表明bash Pod已成功将请求发送到NGINX Ingress Controller,但由于未定义路由,NGINX Ingress Controller不知道应将请求转发到何处。

我们使用legacy-route.yaml中的以下Ingress资源定义创建所需路由。第7行的“internal-route”注解表示目标服务不会暴露到互联网,而仅对NGINX Service Mesh中的工作负载开放。

正在加载代码示例…

激活新资源,并确认NGINX Ingress Controller已添加该资源中定义的路由:

> kubectl apply -f legacy-route.yamlingress.networking.k8s.io/target-internal-route created
> kubectl describe ingress target-internal-route -n legacy
...
Events:
  Type    Reason          Age   From                      Message
  ----    ------          ----  ----                      -------
  Normal  AddedOrUpdated  6s    nginx-ingress-controller  Configuration for ...
        ...legacy/target-internal-route was added or updated

现在,运行kubectl exec命令后,即可访问目标服务:

{"req": {"method": "GET"                "url": "/",
                "host": "target-svc.legacy",
                "remoteAddr": "10.28.2.76:56086"}}

通过NGINX Ingress Controller路由出站流量的一项优势是,可以精确控制从集群内部能够访问哪些外部服务;只有已定义路由的服务才能被访问。

演示的最后一项内容是如何监控出站流量。我们运行kubectl exec命令发送多个请求,然后运行以下命令:

> nginxmesh-ctl top deploy/nginx-ingress -n nginx-ingressDeployment      Direction  Resource  Success Rate  P99  P90  P50  NumRequests
nginx-ingress  
                To         target    100.00%       1ms  1ms  1ms  9
                From       bash      100.00%       0ms  0ms  0ms  9

告别延迟:试用搭配NGINX Ingress Controller的NGINX Service Mesh

许多服务网格都提供入口和出口网关选项,但NGINX集成还带来一项额外优势:降低延迟。大多数服务网格都需要将边车注入Ingress控制器,导致流量在传输到应用的途中多经过一跳。分秒都很重要,这一额外跳转会拖慢数字体验,可能导致客户转向其他服务。NGINX Service Mesh不会向NGINX Ingress Controller注入边车,因此不会增加不必要的延迟。NGINX Ingress Controller通过直接与网格的证书颁发机构Spire集成,成为NGINX Service Mesh的一部分。NGINX Ingress Controller只需从Spire代理获取证书和密钥,即可与网格中的Pod进行mTLS证书交换。

NGINX Ingress Controller for Kubernetes有两个版本:NGINX Open Source和NGINX Plus。要按照本博客所述方式将NGINX Ingress Controller与NGINX Service Mesh结合部署,必须使用NGINX Plus版本。该版本提供30天免费试用。

NGINX Service Mesh可免费使用,并可立即下载,部署时间不到10分钟。要开始使用,请查看文档,并通过GitHub向我们反馈使用情况。


分享
标签: 2021, F5 NGINX, Tech

相关博客文章

NGINX Plus R26 正式发布
NGINX | 2022/02/15

NGINX Plus R26 正式发布

NGINX Plus R26通过缓存JSON Web密钥集加快JWT验证,并强化TLS握手,从而提升安全性。NGINX JavaScript的新功能包括增强对异步函数的支持,以及实现WebCrypto API。

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击
NGINX | 2022/02/10

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击

gRPC具备开发人员设计和部署现代应用所需的速度与灵活性,但其开放性也使其极易受到第7层DoS攻击。NGINX App Protect DoS可保护gRPC应用免受此类破坏性攻击。

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划
NGINX | 2021/09/13

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划

了解选择错误的Ingress控制器可能带来的风险,以及如何从关键方面着手,让您的选择更好地适应未来需求。

NGINX Plus R19 正式发布
NGINX | 2019/09/03

NGINX Plus R19 正式发布

NGINX Plus R19扩展了监控功能,不仅提供更多指标,还新增了指标分析方式;增加试运行模式,用于测试限速效果;增强键值存储,以支持IP地址范围;并使限速更加动态。

NGINX现已正式加入F5
NGINX | 2019/05/09

NGINX现已正式加入F5

NGINX现已正式成为F5的一部分。Gus Robertson现任F5 NGINX业务部门负责人。他阐述了两家公司在人才、文化和愿景方面融合的价值,以及双方将如何携手增强NGINX的开源产品和商业产品。

使用NGINX和NGINX Plus实现高性能缓存
NGINX | 2016/08/24

使用NGINX和NGINX Plus实现高性能缓存

我将介绍NGINX在内容缓存和性能方面的工作原理,并分享一些控制NGINX内容缓存方式的技巧。