k8s实现nginx-ingress通过统一IP访问服务无缝对接生产上游Nginx

7,343 阅读5分钟

前言

在Kubernetes中,服务和Pod的IP地址仅可以在集群网络内部使用,对于集群外的应用是不可见的。为了使外部的应用能够访问集群内的服务,在Kubernetes 目前 提供了以下几种方案:

  • NodePort
  • LoadBalancer
  • Ingress

这三种方案中,考虑到NodePort是直接开放外部端口,这样需要管理所有服务开放的端口,跟我们原本使用k8s的初衷略有违背,我们初衷是希望对外是服务访问,对内可以不针对每个服务所在的服务器以及端口进行管理,在降低运维压力同时,实现负载均衡,因此一般不选择这种方案实现对外暴露服务,而LoadBalancer需要云端服务支持,就是一般是需要付费,考虑成本也是不在参考范围里面的,因此最后的Ingress这根稻草,在安全与成本的方向的考虑,满足了大部分人的需求,基础部署参考:helm3.0部署nginx-ingress.

Ingress 简介

在kubernetes集群中,我们知道service和pod的ip仅在集群内部访问。如果外部应用要访问集群内的服务,集群外部的请求需要通过负载均衡转发到service在Node上暴露的NodePort上,然后再由kube-proxy组件将其转发给相关的pod。 而Ingress就是为进入集群的请求提供路由规则的集合,通俗点就是提供外部访问集群的入口,将外部的HTTP或者HTTPS请求转发到集群内部service上。

Ingress访问原理

Ingress代理的并不是pod的service,而是pod,之所以在配置的时候是配置的service,是为了通过service来获取所有pod的信息。 

访问原理如下:

在这里插入图片描述

Ingress实现生产环境服务暴露方案

Ingress通常使用http://domain/path的方式暴露服务,对于生产环境,是已经配置了一层Nginx代理,通过80/443端口对外开放应用入口

具体访问原理如下:

在这里插入图片描述
当服务部署到k8s之后,能不能用原本的方案呢?

方案一:使用Nginx-Ingress实现反向代理,替换原来的Nginx

具体实现逻辑如下:

在这里插入图片描述
这个需要一个前提条件是由于是生产环境,域名是必须能够公网IP进行DNS解析,也就是Nginx-Ingress所在的服务器必须进行DNS解析才可以实现直接对外暴露服务,但是nginx-ingress是通过k8s部署,在正常情况下,我们都不会指定节点去部署,因为指定节点部署就可能会出现单点故障问题,且不能基于k8s进行动态分配服务器,也就是DNS解析这个除非全解析,不然不靠谱,鉴于时间问题以及风险问题,这种模式不考虑。

方案二:使用Nginx-Ingress实现反向代理,上游对接原有的Nginx服务

具体实现逻辑如下:

在这里插入图片描述
从图上面可以看到,相当于加了一层代理,只需要改变原有生成环境的反向代理服务地址就能把服务访问迁移到k8s的服务上面。这是一个相对比较合理跟成本较低的方案,在Nginx-Ingress这一层还是基于Ingress的规则统一开放k8s上面的应用服务,Nginx这一层反向代理Nginx-Ingress即可。

具体实现

开放nginx-ingress 80/443端口

按照我们正常使用,nginx-ingress所在服务器集群式不开通外网,但是为了方便使用,我们通过externalIPs将服务使用固定IP的方式对内网开放,其他服务/应用可以通过http/https://externalIPs/xxx的方式即可访问nginx-ingress.

具体配置如下:

spec:
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 80
      nodePort: 31314
    - name: https
      protocol: TCP
      port: 443
      targetPort: 443
      nodePort: 30491
  selector:
    app: nginx-ingress
    component: controller
    release: nginx-ingress
  clusterIP: 10.100.221.205
  type: LoadBalancer
  externalIPs:
    - 192.168.1.123
  sessionAffinity: None
  externalTrafficPolicy: Cluster

Ingress规则编写

编写一个Ingress规则,将服务通过ingress开放出去 注意这里跟普通的ingress规则差异的点在于spec.rules.host这个选项,一般我们这个选项会填写我们的域名如www.test.com,但是这里我们采用方案二,因此不需要填写这个选项,按照以下的配置,访问test服务的时候,只需要通过我们上一步填写的IP即可访问,具体路径:http://192.168.1.123/test,这样写就可以访问test服务,实现nginx-ingress通过统一IP访问服务。我们把上述的服务地址配置到上游的nginx代理即可。

spec:
  rules:
    - http:
        paths:
          - path: /test
            backend:
              serviceName: test
              servicePort: 8080

解决ingress 308问题

如果只有上面的操作,访问http://domain/path的时候,页面会跳转不信任链接,,报错308原因是当我们的ingress规则不填写host的时候,ingress-nginx默认要求https,所以这时会遇到访问总是308跳转的问题。

针对这个问题,只需要修改nginx-ingress的参数如下: 打卡nginx-ingress的configmap:nginx-ingress-controller 设置 ssl-redirect: 'false'

data:
  compute-full-forwarded-for: 'true'
  enable-vts-status: 'false'
  forwarded-for-header: X-Forwarded-For
  ssl-redirect: 'false'
  use-forwarded-headers: 'true'

然后就可以完成无缝对接生产上游~~~

在这里插入图片描述