当前位置: 首页 > 知识库问答 >
问题:

使用入口作为API网关的Kubernetes集群中两个服务之间的通信

燕英逸
2023-03-14

我在尝试在kubernetes集群中的两个服务之间进行通信时遇到问题。我们使用kong ingress对象作为“api网关”,从简单的角度前端重新路由http调用,以将其发送到。NET Core 3.1 API控制器接口后端。

在这两个ClusterIP服务前面有一个入口控制器,用于从kubernetes集群获取外部http调用,以启动前端服务。此处显示了该入口:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-nginx
  namespace: kong
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - host: app.***.*******.com     <<  Obfuscated
      http:
        paths:
            - path: /
              backend:
                serviceName: frontend-service
                servicePort: 80

第一个服务称为“前端服务”,这是一个简单的有角度的9前端,允许我键入http字符串并将这些字符串提交到后端
下面显示了用于此的清单yaml文件。请注意,图像名称由于各种原因而变得模糊。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
  namespace: kong
  labels:
    app: frontend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      imagePullSecrets:
      - name: regcred
      containers:
      - name: frontend
        image: ***********/*******************:****  << Obfuscated
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  namespace: kong
  name: frontend-service
spec:
  type: ClusterIP  
  selector:
    app: frontend
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP

第二个服务是一个简单的。NET Core 3.1 API接口,当到达控制器时打印回一些文本。后端服务称为“dataapi”,其中有一个简单的控制器,称为ValuesController。

下面显示了用于此的清单yaml文件。

  replicas: 1
  selector:
    matchLabels:
      app: dataapi
  template:
    metadata:
      labels:
        app: dataapi
    spec:
      imagePullSecrets:
      - name: regcred
      containers:
      - name: dataapi
        image: ***********/*******************:****  << Obfuscated
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: dataapi
  namespace: kong
  labels:
    app: dataapi
spec:
  ports:
  - port: 80
    name: http
    targetPort: 80
  selector:
    app: dataapi

我们使用Kong入口作为代理将传入的超文本传输协议调用重定向到dataapi服务。此清单文件如下所示:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: kong-gateway
  namespace: kong
spec:
  ingressClassName: kong
  rules:
  - http:
      paths:
      - path: /dataapi
        pathType: Prefix
        backend:
          service:
            name: dataapi
            port:
              number: 80

执行“kubectl get all”会产生以下输出:

kubectl get all

NAME                                READY   STATUS    RESTARTS   AGE
pod/dataapi-dbc8bbb69-mzmdc         1/1     Running   0          2d2h
pod/frontend-5d5ffcdfb7-kqxq9       1/1     Running   0          65m
pod/ingress-kong-56f8f44fd5-rwr9j   2/2     Running   0          6d

NAME                              TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)                      AGE
service/dataapi                   ClusterIP      10.128.72.137    <none>         80/TCP,443/TCP               2d2h
service/frontend-service          ClusterIP      10.128.44.109    <none>         80/TCP                       2d
service/kong-proxy                LoadBalancer   10.128.246.165   XX.XX.XX.XX    80:31289/TCP,443:31202/TCP   6d
service/kong-validation-webhook   ClusterIP      10.128.138.44    <none>         443/TCP                      6d

NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/dataapi        1/1     1            1           2d2h
deployment.apps/frontend       1/1     1            1           2d
deployment.apps/ingress-kong   1/1     1            1           6d

NAME                                      DESIRED   CURRENT   READY   AGE
replicaset.apps/dataapi-dbc8bbb69         1         1         1       2d2h
replicaset.apps/frontend-59bf9c75dc       0         0         0       25h
replicaset.apps/ingress-kong-56f8f44fd5   1         1         1       6d

和'kubectl获取入口'给出:

NAME                    CLASS    HOSTS  (Obfuscated)
ingress-nginx           <none>   ***.******.com,**.********.com,**.****.com,**.******.com  + 1 more...        xx.xx.xxx.xx   80      6d                                                                             ADDRESS        PORTS   AGE
kong-gateway            kong     *                                                                            xx.xx.xxx.xx   80      2d2h

从前端,期望构建超文本传输协议字符串:

http://kong-proxy/dataapi/api/values

将在后端输入“values”控制器,并从该控制器返回文本字符串。

这两个服务都在同一个kubernetes集群上运行,这里使用Linode。我们的想法是,它是两个类型为ClusterIP的服务之间的“集群内”通信。

Chrome控制台中报告的错误为:

zone-evergreen.js:2828 GET http://kong-proxy/dataapi/api/values net::ERR_NAME_NOT_RESOLVED

请注意,我们发现了一个与我们类似的StackOverflow问题,结果中的建议是将“default.svc.cluster.local”添加到超文本传输协议字符串中,如下所示:

http://kong-proxy.default.svc.cluster.local/dataapi/api/values

这不起作用。我们还将kong(服务的名称空间)替换为默认值,如下所示:

http://kong-proxy.kong.svc.cluster.local/dataapi/api/values

产生与上述相同的错误。

我是否遗漏了一个关键步骤?非常感谢您的任何建议!

***************Eric Gagnon回应更新**************

再次感谢Eric的回应。以下是我和我的同事根据您的建议尝试的内容

  1. pod dns配置错误:检查pod的第一个名称服务器是否等于'库贝-dns'svc ip,以及搜索是否从kong.svc.cluster.local开始:
kubectl exec -i -t -n kong frontend-simple-deployment-7b8b9cfb44-f2shk -- cat /etc/resolv.conf

nameserver 10.128.0.10
search kong.svc.cluster.local svc.cluster.local cluster.local members.linode.com
html" target="_blank">options ndots:5

kubectl get -n kube-system svc 

NAME       TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                  AGE
kube-dns   ClusterIP   10.128.0.10   <none>        53/UDP,53/TCP,9153/TCP   55d

kubectl describe -n kube-system svc kube-dns

Name:              kube-dns
Namespace:         kube-system
Labels:            k8s-app=kube-dns
                   kubernetes.io/cluster-service=true
                   kubernetes.io/name=KubeDNS
Annotations:       lke.linode.com/caplke-version: v1.19.9-001
                   prometheus.io/port: 9153
                   prometheus.io/scrape: true
Selector:          k8s-app=kube-dns
Type:              ClusterIP
IP:                10.128.0.10
Port:              dns  53/UDP
TargetPort:        53/UDP
Endpoints:         10.2.4.10:53,10.2.4.14:53
Port:              dns-tcp  53/TCP
TargetPort:        53/TCP
Endpoints:         10.2.4.10:53,10.2.4.14:53
Port:              metrics  9153/TCP
TargetPort:        9153/TCP
Endpoints:         10.2.4.10:9153,10.2.4.14:9153
Session Affinity:  None
Events:            <none>    
I do not understand where and how to do this.  We tried to add DNS directly inside our Angular frontend app, but we found out it is not possible to add this.

我们在这里尝试了两次测试。首先,我们的kong代理服务可以从入口控制器访问。请注意,这不是我们简单的前端应用程序。它只不过是一个将http字符串传递给我们设置的公共网关的代理而已。这确实有效。我们通过以下方式揭示了这一点:

http://gateway.cwg.stratbore.com/test/api/test

["Successfully pinged Test controller!!"]

kubectl logs -n kong ingress-kong-56f8f44fd5-rwr9j | grep test 

10.2.4.11 - - [16/Apr/2021:16:03:42 +0000] "GET /test/api/test HTTP/1.1" 200 52 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36"

So this works.

但是,当我们尝试从与后端运行在同一集群中的简单前端界面执行此操作时:

它不适用于文本框中显示的文本。此命令不添加任何新内容:

kubectl logs -n kong ingress-kong-56f8f44fd5-rwr9j | grep test 

前端返回一个错误。

但如果我们添加此http文本:

金刚入口吊舱被击中:

kubectl logs -n kong ingress-kong-56f8f44fd5-rwr9j | grep test 

10.2.4.11 - - [16/Apr/2021:16:03:42 +0000] "GET /test/api/test HTTP/1.1" 200 52 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36"
10.2.4.11 - - [17/Apr/2021:16:55:50 +0000] "GET /test/api/test HTTP/1.1" 200 52 "http://app-basic.cwg.stratbore.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36"

但是前端返回了一个错误。

所以在这一点上,我们已经尝试了很多方法来让我们的前端应用程序成功地向我们的后端发送超文本传输协议并获得响应,但我们没有成功。我还尝试了我们的前端应用程序打包的nginx.conf文件的各种配置,但也没有成功。

我将把所有这些打包在一个github项目中。谢谢。

共有2个答案

法镜
2023-03-14

在Eric G的大力帮助下(谢谢!)在这一点上,阅读前面的StackOverflow,我最终解决了这个问题。正如此链接中的答案所示,我们的前端pod是在一个对Kubernetes集群一无所知的web浏览器中提供我们的应用程序。

如链接所示,我们在nginx入口中添加了另一条规则,以成功将超文本传输协议请求路由到适当的服务

    - host: gateway.*******.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: gateway-service
                port:
                  number: 80

然后从我们的Angular前端,我们发送了如下HTTP请求:

...
http.get<string>("http://gateway.*******.com/api/name_of_contoller');
...

我们最终能够以我们想要的方式与后端服务进行通信。前端和后端都位于同一Kubernetes群集中。

皇甫飞跃
2023-03-14

克里斯,

我没有使用linode或Kong,也不知道您的前端实际上是做什么的,所以我只会指出我所能看到的:

>

  • http://[dataapi的pod ip]:80来自主机节点

nginx入口控制器上的默认路径匹配是path Prefix,因此带有path:/和nginx.ingress.kubernetes.io/rewrite-target:/的nginx入口实际上匹配所有内容并重写为 /.如果您正确指定所有入口以使它们优先于“/”,这可能不是问题。

您说过“使用kong入口作为代理重定向传入”,只是想确保您正在代理(而不是重定向客户端)。

chrome只是从前端服务中继其上游错误吗?外部客户端应该无法解析集群的URL(除非您已将本地计算机加入集群的网络或执行了其他一些花哨的操作)。默认情况下,dns仅在集群内工作。

群集dns通常遵循[服务名称]。[命名空间名称]。svc.cluster.local.如果dns群集dns正常工作,则使用来自群集中pod的curl、ping、wget等并将其指向svc将其发送到群集svc ip,而不是外部ip。

您的dataapi服务是配置为响应/dataapi/api/values,还是不关心uri是什么?

如果您没有任何限制命名空间内流量的网络策略,您应该能够在同一命名空间中创建一个测试pod,并直接卷曲服务dns和pod ip:

apiVersion: v1
kind: Pod
metadata:
  name: curl-test
  namespace: kong
spec:
  containers:
  - name: curl-test
    image: buildpack-deps
    imagePullPolicy: Always
    command:
    - "curl"
    - "-v"
    - "http://dataapi:80/dataapi/api/values"
  #nodeSelector:
  #  kubernetes.io/hostname: [a more different node's hostname]

pod应尝试从群集进行dns解析。因此,它应该找到dataapi的svc ip和curl端口80路径/dataapi/api/值。服务IP是虚拟的,因此实际上无法“访问”。相反,iptables将它们路由到pod-ip,该pod-ip具有实际的网络endpoint并可寻址。

一旦完成,只需检查日志:kubectl logs curl test,然后删除它。

如果失败,日志中失败的性质应该会告诉您这是dns还是链接问题。如果它有效,那么您可能没有集群dns问题。但您可能有节点间通信问题。要测试这一点,您可以运行与上述相同的清单,但取消注释节点选择器字段以强制它在与您的Kong代理pod不同的节点上运行。这是一种手动方法,但它可以快速排除故障。只需根据需要冲洗并重复其他节点。

当然,它可能不是这些,但希望这有助于故障排除。

 类似资料:
  • 我试图在两个 kubernetes 集群中的两个应用程序之间获取 mTLS,而没有 Istio 的方式(使用其入口网关),我想知道以下内容是否有效(对于 Istio,对于 Likerd,对于 Consul...)。 假设我们有一个带有应用程序A. A的k8s集群A和一个带有应用程序B. B的集群B。我希望它们与mTLS通信。 集群A为nginx入口控制器提供了letsEncrypt证书,并为其应用

  • 我正在Kubernetes集群中运行2个服务。 价格SVC 服务以“ClusterIP”类型部署,入口(netcalar)位于服务前面。 调度运行良好,我可以从库伯内特斯集群外部访问调度。 现在,尝试从pricesvc访问计划vc。我可以使用ClusterIP服务endpoint或入口。由于我计划在多个数据中心运行库伯内特斯集群,因此我将在DC的Active/Active中运行我的应用程序,因此我

  • 我是Kubernetes的初学者,我的情况如下:我有两个不同的吊舱:吊舱和吊舱。首先,我想向外界公开PodA,所以我为PodA创建了一个服务(类型NodePort或LoadBalancer),这对我来说并不难理解。 然后我想让PodA与PodB通信,在谷歌搜索了几个小时后,我发现答案是我还需要为PodB创建一个服务(如果我想让PodB只在集群内可见,请键入ClusterIP),如果我这样做,我可以

  • 我正在尝试访问部署在远程机器中的现有kubernetes集群中的服务。我已将集群配置为可以从本地mac通过kubectl访问。 我要连接的服务的入口配置为: 我的/etc/hosts文件如下所示: 我应该使用什么URL从本地浏览器访问此服务?我应该进行更多配置吗?

  • 我有一个运行在minikube(已启用加载项)中的nginx ingress,它有几个吊舱和服务,ingress具有以下配置: 当我在集群之外时,以下各项工作正常: 但是,当我在集群内时,我希望容器能够使用我的入口模板中列出的主机名相互通信。例如,我希望以下方法可以工作,但事实并非如此: 相反,它返回实际api的结果。信息网站,我没有隶属关系。首先,有人能确认这是可行的吗? 非常感谢。

  • 我有一个复合服务S.c,它使用两个原子服务S.a和S.b,其中所有三个服务都在Kubernetes集群中运行。更好的模式是什么 1)将Sa、Sb创建为无头服务,并让Sc通过NGINX等外部负载均衡器与它们集成(使用DNS解析器来维护更新的后端pod) 2) 使用clusterIP创建Sa、Sb,并让Sc通过群集DNS(skyDNS加载项)访问/解析它们。这将在内部利用基于IP表的负载平衡来实现PO