前言

当我们在Kubernetes部署的服务需要暴露给外部用户使用时,有三种选择:LoadBalancer,NodePort, Ingress。

LoadBalancer类型得结合各个Cloud Provider提供的LB来使用,如果需要暴露的service很多,需要很多LB以及公网IP,比较浪费cost。

NodePort 方式一个端口只能一个服务使用,根据端口划分服务,可用端口范围:30000~32767, 同样如果在暴露的servicie很多的情况下会导致节点要开的端口越来越多,不好管理,平时测试可以用用。

Ingress是自kubernetes1.1版本后引入的资源类型,在这个资源中我们可以去配置我们的服务路由规则,但是要真正去实现识别这个 Ingress 并提供代理路由功能,还需要安装一个对应的控制器Ingress controller才能实现。Ingress nginx controller 本质上就是kubernetes 部署的pod 里面有一个 Nginx container,只不过它能根据 Ingress 资源的定义动态生成 Nginx 的配置文件,然后动态 Reload。可以理解成 Ingress controller是由Kubernetes管理的负载均衡器。

Ingress controller是以一种插件的形式提供,有多种实现,有基于 Nginx 的,也有基于 HAProxy的,还有现在很流行的Envoy,详见:https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/, 我后面文章也会介绍基于 Envoy的 Ingress controller。

本文使用Kubernetes 社区推出的 Ingress Controller: Ingress-nginx (github.com/kubernetes/ingress-nginx) 它是基于Nginx 的扩展版 OpenResty 及诸多第三方模块构建的,其基于 OpenResty 的 Lua 嵌入式编程能力,扩展了 Nginx 的功能,并基于 balancer_by_lua 模块实现了 Pod 变化的动态变更功能。

要注意区分另外一个名字相近由Nginx公司推出的Nginx ingress controller (github.com/nginxinc/kubernetes-ingress)。Nginx 官方版本提供其基于Go语言开发的 Ingress 控制器,并与 Nginx 集成分为 Nginx 开源版和 Nginx Plus 版,开源版仅基于 Nginx 的原始功能,不支持 Pod 变化的动态变更。Nginx Plus 版则提供了诸多完善的商业功能,其支持 Nginx 原生配置指令、JWT 验证、Pod 变化的动态配置及主动健康检查等功能。

 

关键词:Ingress nginx入门,Ingress nginx安装,同一集群多Ingress Nginx安装,Ingress nginx使用

 

安装

测试环境

  • Kubernetes 1.22(GKE)
  • Ingress Nginx 1.3.0
  • Kustomize 3.10.0 

安装及使用

安装方式有多种,我这里介绍使用Kustomize 安装

k8s manifests 参考 my repo

根据需要修改自己所需,这里的例子是为 atlantis namespace 下面的 atlantis serivce 配置一个Ingress

由于Ingress controller 和 Ingress 均安装在dmz namespace, 和 atlantis 不在同一个namespace下面,我们需要为atlantis serivce 加了一个 ExternalName 类型的service 相当于别名。

这样dmz namespace 下面 Ingress 就指向 -> ExternalName 类型的service -> 指向 atlantis ns 下面  atlantis svc。

(Optional)Ingress 和 atlantis 放在同一个namespace 下面,就不需要多一个 ExernalName service了。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: sre-ingress-resource
  annotations:
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "300"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
    nginx.ingress.kubernetes.io/proxy-body-size: 100m
    nginx.ingress.kubernetes.io/proxy-buffer-size: 512k
    nginx.ingress.kubernetes.io/client-body-buffer-size: 512k
    ingress.kubernetes.io/ssl-redirect: "true"
    ingress.kubernetes.io/force-ssl-redirect: "true"

spec:
  ingressClassName: nginx
  rules:
  - host: atlantis-demo.wadexu.cloud
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: atlantis-demo-ext-svc
            port:
              number: 8080
  tls:
  - hosts:
    - atlantis-demo.wadexu.cloud
    secretName: wade-tls-secret
---
apiVersion: v1
kind: Service
metadata:
  name:  atlantis-demo-ext-svc
spec:
  type: ExternalName
  externalName: atlantis.atlantis.svc.cluster.local
  ports:
  - name: http
    port: 8080
    targetPort: 4141
    protocol: TCP

build and apply

kustomize build ingress-nginx-public/sre-mgmt-dev/ > ~/deploy.yaml

kubectl apply -f ~/deploy.yaml

 因为用了 https ,所以需要加一个tls-secret

kubectl create secret -n dmz tls wade-tls-secret \
  --key ./xxx.key \
  --cert ./xxx.pem

 

多个 Ingress Nginx Controller 部署

同一个cluster 如果要安装另一个ingress nginx controller,比如作为内部API网关,该怎么实现呢?

为了避免多个ingress controller 以一种困惑的方式同时争抢更新 ingress status字段,需要使用IngressClasses 官方文档

另外还要注意资源重名的情况,需要改name,否则后部署的Ingress controller 会覆盖前者, 比如 ClusterRoleBinding

参考 my manifests 部署在app namespace的internal Ingress nginx 针对以上资源的修改。

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: nginx
spec:
  controller: k8s.io/internal-ingress-nginx
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: app
commonLabels:
  app.kubernetes.io/name: internal-ingress-nginx
  app.kubernetes.io/instance: internal-ingress-nginx
resources:
- ../../base
patchesStrategicMerge:
- ingress-class-patch.yaml
patches:
  - target:
      kind: IngressClass
      name: nginx
    patch: |-
      - op: replace
        path: /metadata/name
        value: internal-nginx
  - target:
      kind: Deployment
      name: ingress-nginx-controller
    patch: |-
      - op: replace
        path: /metadata/name
        value: internal-ingress-nginx-controller
      - op: replace
        path: /spec/template/spec/containers/0/args/3
        value: "--controller-class=k8s.io/internal-ingress-nginx"
      - op: replace
        path: /spec/template/spec/containers/0/args/4
        value: "--ingress-class=internal-nginx"
  - target:
      kind: ClusterRoleBinding
      name: ingress-nginx
    patch: |-
      - op: replace
        path: /metadata/name
        value: internal-ingress-nginx
  - target:
      kind: ClusterRoleBinding
      name: ingress-nginx-admission
    patch: |-
      - op: replace
        path: /metadata/name
        value: internal-ingress-nginx-admission
  - target:
      kind: ValidatingWebhookConfiguration
      name: ingress-nginx-admission
    patch: |-
      - op: replace
        path: /metadata/name
        value: internal-ingress-nginx-admission

 

总结

一般来说,Ingress nginx 足以应付大部分场景了,除非你想用到一些高阶功能,比如流量管理,熔断等等。那么我会推荐 后起之秀基于Enovy的那些Ingress controller,比如Ambassador 现在叫Emissary, CNCF的incubating 项目。

 


Learning by Doing