【问题标题】:k8s Ingress affects LoadBalancer on different domaink8s Ingress 影响不同域上的 LoadBalancer
【发布时间】:2017-11-23 10:05:40
【问题描述】:

TL;DR: 每约 5 次请求,nginx-ingress-controller 会影响不同域上的另一个 LoadBalancer 服务。

我在 GCE 上使用 Kubernetes 时遇到了一个奇怪的情况,我被卡住了。我不知道我是否有配置,或者是否偶然发现了 k8s 中的一个(非常严重的)错误。

我有两个 LoadBalancer 服务,每个都有自己的静态 IP 和指向它们的 DNS 记录。

一个 LoadBalancer (通过它的选择器)直接指向一个运行我的 API 网络服务器的部署,这是api.domain.com。由于复杂的客户端证书身份验证方案,此 API 不能位于入口控制器后面,而 nginx 入口(目前)还不可能。

另一个 LoadBalancer 服务指向 NGINX 入口控制器。在site.domain.com 为我的网站提供服务。我使用标准的 nginx-default-backend 从入口控制器提供 404。

问题在于,当我在浏览器中加载 API(api.domain.com)时,每 3 或 4 次刷新一次,就会从 nginx-default-backend 提供 404。

因此,每隔 5 次左右,来自完全不同域(site.domain.com234.234.234.234)的页面就会在我的 API 域(api.domain.com123.123.123.123)上提供服务。我不明白这怎么会发生。

删除nginx-ingress-controller 后,API 再次正常运行。我真的很困惑。

对于 API:

apiVersion: v1
kind: Service
metadata:
  name: api
spec:
  type: LoadBalancer
  loadBalancerIP: 123.123.123.123
  selector:
    app: api
  ports:
  - port: 443

对于网站:

apiVersion: v1
kind: Service
metadata:
  name: nginx-ingress-lb
  labels:
    app: nginx-ingress-lb
spec:
  type: LoadBalancer
  loadBalancerIP: 234.234.234.234
  ports:
  - port: 443
    name: https
  selector:
    # Selects nginx-ingress-controller pods
    app: nginx-ingress-controller
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-ingress-controller
  labels:
    app: nginx-ingress-controller
spec:
  replicas: 1
  template:
    metadata:
      name: nginx-ingress-controller
      labels:
        app: nginx-ingress-controller
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.9.0-beta.17
        name: nginx-ingress-controller
        readinessProbe:
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
        livenessProbe:
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10
          timeoutSeconds: 1
        ports:
        - containerPort: 443
          hostPort: 443
        env:
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: POD_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
        args:
        - /nginx-ingress-controller
        - --default-backend-service=$(POD_NAMESPACE)/nginx-default-backend
        - --publish-service=$(POD_NAMESPACE)/nginx-ingress-lb
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress
  namespace: development
spec:
  tls:
  - hosts:
    - site.domain.com
    secretName: "site.domain.com-tls"
  rules:
  - host: "site.domain.com"
    http:
      paths:
      - backend:
          serviceName: website
          servicePort: http

到目前为止我检查过的内容:

我已经使用host -a 检查了我的 DNS 记录,它们都是正确的。我使用kubectl get po -l app=website 检查了选择器中的名称冲突,没有冲突。我检查了绑定的IP地址:

> kubectl get svc
NAME                    TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)
api                     LoadBalancer   10.3.240.197   123.123.123.123  443:32126/TCP
nginx-default-backend   ClusterIP      10.3.253.16    <none>           80/TCP
nginx-ingress-lb        LoadBalancer   10.3.245.191   234.234.234.234  443:31051/TCP
website                 ClusterIP      10.3.254.180   <none>           80/TCP

> kubectl get ingress
NAME          HOSTS             ADDRESS           PORTS
ingress       site.domain.com   234.234.234.234   80, 443

> host api.domain.com
api.domain.com has address 123.123.123.123
> host site.domain.com
site.domain.com has address 234.234.234.234

我觉得一切都很好。

我做错了什么还是 k8s 或 nginx-ingress 有什么严重问题?

【问题讨论】:

    标签: kubernetes


    【解决方案1】:

    这是一个有趣的。
    我花了一些时间绘制图表并假设错误发生的原因,但最好的答案来自GLBC README

    不要在单个集群中启动 2 个控制器实例,它们 会互相争斗

    编辑

    我相信这种行为是由于 GCE 负载均衡器转发规则的工作方式与 nginx-ingress-controller 冲突(反之亦然 :))

    据我所知,GCE 负载均衡器转发规则接受转发到集群主机的同一端口号上的流量,即您的示例中的 :443

    nginx-ingress-controller 定义中:

    ports:
            - containerPort: 443
              hostPort: 443
    

    我们看到 nginx-ingress pod 正在侦听位于 :443 的主机。
    但 GCE 负载均衡器也转发到:443 的主机。

    把它们放在一起

    假设您的 API pod 部署在集群节点的某个子集上,例如 3/4。
    然后 3/4 倍的 GCE 负载均衡器将流量定向到具有侦听 API pod 的主机 - 成功!

    但是第四个请求路由到端口443 上的节点,没有运行 API pod。但是,nginx-ingress-controller pod 正在侦听,因此使用 404 响应请求。

    因此,问题并不是真正的 DNS 解析问题,因为它可能看起来。


    参考文献

    来自 k8s 服务 shortcomings 的以下引用似乎支持我的理论,因为 NodePort 值未使用,因此端口转发发生在同一端口上。

    并非所有云提供商(例如 Google Compute Engine 无需分配 NodePort 即可 LoadBalancer 可以工作,但 AWS 可以)

    GCE转发规则创建
    https://github.com/kubernetes/kubernetes/blob/master/pkg/cloudprovider/providers/gce/gce_loadbalancer_external.go

    【讨论】:

    • 我正在运行NGINX ingress,而不是 GCE 入口。另外,我只有一个入口控制器在运行。根据nginx ingress的文档,可以同时运行一个GCE和NGINX ingress,只要定义类:Note: Deploying multiple ingress controller and not specifying the annotation will result in both controllers fighting to satisfy the Ingress.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-14
    • 2021-04-22
    • 2021-12-14
    • 2021-12-20
    • 2019-09-10
    • 2019-10-22
    相关资源
    最近更新 更多