请求外部IP与转发规则k8s服务目标不匹配

请求外部IP与转发规则k8s服务目标不匹配

我们正在运行两个独立的子域,每个子域位于单独的外部 IP 地址上,并且每个子域都与其自己的 kubernetes nginx 服务匹配。配置如下所示:

#--------------------
# config for administrative nginx ssl termination deployment and associated service


apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: admin-nginx
labels:
  name: admin-nginx
spec:
replicas: 1
template:
  metadata:
    name: admin-nginx
    labels:
      name: admin-nginx
  spec:
    nodeSelector:
      cloud.google.com/gke-nodepool: currentNodePool
    containers:
    - name: admin-nginx
      image: path/to/nginx-ssl-image:1
      ports:
        - name: admin-http
          containerPort: 80
        - name: admin-https
          containerPort: 443

apiVersion: v1
kind: Service
metadata: 
name: admin-nginx
spec: 
ports: 
  - name: https
    port: 443
    targetPort: admin-https
    protocol: TCP
  - name: http
    port: 80
    targetPort: admin-http
    protocol: TCP
selector: 
  name: admin-nginx
type: LoadBalancer


#--------------------
# config for our api's nginx ssl termination deployment and associated service


apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: public-nginx
labels:
  name: public-nginx
spec:
replicas: 2
strategy:
  rollingUpdate:
    maxUnavailable: 0
template:
  metadata:
    labels:
      name: public-nginx
  spec:
    nodeSelector:
      cloud.google.com/gke-nodepool: currentNodePool
    containers:
    - name: public-nginx
      image: path/to/nginx-ssl-image:1
      ports:
        - name: public-http
          containerPort: 80
        - name: public-https
          containerPort: 443


apiVersion: v1
kind: Service
metadata: 
name: public-nginx
spec: 
ports: 
  - name: https
    port: 443
    targetPort: public-https
    protocol: TCP
  - name: http
    port: 80
    targetPort: public-http
    protocol: TCP
selector: 
  name: public-nginx
type: LoadBalancer


#--------------------

在我们的 kubernetes 集群中,我们与每个 nginx 部署关联了一个内部使用的自定义 API 路由器/网关。这些路由器各自都有一个 /health 端点,用于健康检查。这一点稍后会变得很重要。

上面的一些细节已被省略;还有一些配置可以使 nginx 知道目标服务的地址和端口。

上述配置创建了 2 个负载均衡器。我猜,从技术上讲,它会创建两个转发规则,每个规则都有一个关联的外部 IP,以及一个由我们的 k8s 集群中的所有实例组成的目标池。一般来说,这应该可以正常工作。每个 k8s 生成的转发规则在其描述字段中都有一个注释,如下所示:

{"kubernetes.io/service-name":"default/admin-nginx"}

还会创建相关的防火墙条目,其描述字段中有类似的注释:

{"kubernetes.io/service-name":"default/admin-nginx", "kubernetes.io/service-ip":"external.ip.goes.here"}

然后,外部 IP 通过 CloudFlare 的 DNS 服务连接到我们的一个子域。

理想情况下,这一切的运作方式以及过去的运作方式应如下。

对 admin.ourdomain.com/health 的传入请求将返回由 API 路由器部署(好吧,无论如何,指向实现该部署的 pod 的服务)处理的所有管理事务的运行状况页面。它通过 nginx pod 来实现这一点,由 nginx 服务指向,由转发规则上的描述注释指向,由 GCE 外部 IP 地址管理器和防火墙指向,尽管我不太清楚最后一部分的顺序。

像这样:

server          status  lookupMicros
https://adminservice0:PORT/health    Ok  910
https://adminservice1:PORT/health    Ok  100
https://adminservice2:PORT/health    Ok  200
https://adminservice3:PORT/health    Ok  876

等等。

同时,对 public.ourdomain.com/health 的请求应该返回几乎相同的内容,除了公共服务之外。

像这样:

server          status  lookupMicros
https://service0:PORT/health    Ok  910
https://service1:PORT/health    Ok  100
https://service2:PORT/health    Ok  200
https://service3:PORT/health    Ok  876

ETC。

很合理,对吧?

据我所知,整个过程的关键在于确保对管理子域的请求(通过链接到管理员注释转发规则的外部地址)最终通过 GCE 的网络设备进入 Kubernetes 集群的某个地方。它首先到达集群中的哪个位置并不重要,因为所有节点都知道存在哪些服务以及它们在哪里。

只是……我现在看到的不是这个。相反,我看到的是:每刷新几次 admin.ourdomain.com/health,它肯定与公共子域位于不同的 IP 地址上,就会返回公共子域的健康页面。这很糟糕。

好的一面是,由于某种原因,我没有看到发往公共子域 /health 的请求最终从管理端返回结果,但无论如何,这非常令人不安。

无论发生了什么,值得注意的是,在错误端发出的请求(如 admin.ourdomain.com/publicendpoint)被正确处理为 404。我想那只是因为 /health 是唯一固有属于 API 路由器的端点,而且这支持了这样一种情况:无论发生什么,似乎都是因为从 GCE 转发规则到正确的 kubernetes 服务的路径存在问题。

现在,我想我们终于到了我提问的部分了。问题如下:

为什么通过与针对特定 kubernetes 服务的转发规则关联的外部 IP 的请求会被间歇性地发送到错误的 kubernetes 服务?

对于此问题的任何帮助或信息都将不胜感激。

相关内容