1. 介绍

基于Nginx的Ingress controller有多种,比如 kong、kubernetes/ingress nginxnginxinc/kubernetes-ingress。比较容易混淆的是后两者。

  • nginxinc/kubernetes-ingress是F5 nginx官方推出的控制器,支持开源版本和商业版版本的nginx。
  • kubernetes/ingress nginx 是由kubernetes社区基于nginx社区版实现的ingess控制器,由Kubernetes社区维护,F5 Nginx承诺帮助管理这个项目。

当前这篇博客的内容全部基于 F5 nginx 推出的 nginxinc/kubernetes-ingress 开源版本。需要注意的是:这篇文档是以官方文档为准,并结合自己的理解和案例进行挑重点内容进行梳理,学习过程中推荐和官方文档相互印证。
当前文档剔除了官方文档中商业版Nginx功能,并且主要针对原生**ingress**资源为核心进行学习,个人认为CRD的学习必要性不高,需要用的时候查官方文档就可以了。

1.1. 原理

Ingress Controller 以下简称IC,本章节从集群中Nginx Ingress Controller流量转发到控制器内部实现方式都做了介绍,更多更具体的描述可参考官方文档

1.1.1. IC 流量转发

05-3-1-nginx - 图1

  • 管理员(admin)在集群中部署 Nginx IC ,通常会有多个副本,图中只显示了一个
  • 用户A配置a.example.comIngress资源,转发流量到Pod A中;用户B配置b.example.comIngress资源,转发流量到Pod 中
  • IC Pod中IC进程监听 Ingress 资源变化,生成 Nginx 配置文件,并重载 nginx 进程
  • 管理员(Admin)将域名解析到集群外部的LB上(Public Endpoint)
  • 客户端通过域名访问到 Public Endpoint,Public Endpoint将流量转发到IC Pod中Nginx监听的套接字,Nginx再根据配置文件转发流量到 Pod A 和 Pod B

    1.1.2. IC Pod 内部逻辑

    通常使用Deployment或者Daemonset部署多个Pod,每个Pod 内部有三类进程:

  • IC :根据集群中Ingress或者其它CRD资源生成nginx配置

  • Nginx Master:Nginx 的 Master 进程,用来控制Nginx Worker进程
  • Nginx Worker:Nginx 的 Worker 进程,处理用户请求流量的进程

05-3-1-nginx - 图2
上述架构图中每个阶段的详细描述如下:

  1. (HTTP) IC 可以通过HTTP接口暴露自身和Nginx指标,Prometheus通过接口采集相关信息并展示。默认情况下接口为:9113/metrics,这个功能可以关闭
  2. (HTTPS) IC 通过Kubernetes API 获取资源(Ingress, nginx CRD)的更新,处理后并更新资源状态
  3. (HTTP) Kubelet 通过 IC 的 Readiness 接口判断 IC Pod 是否就绪
  4. (File I/O) IC 进程启动时,会读取来自文件系统的配置生成所需的配置模板。这些模板位于容器的 /目录中,并具有.tmpl扩展名
  5. (File I/O) IC将日志写入标准输出和标准错误,由容器运行时收集
  6. (File I/O) IC根据 Kubernetes资源生成配置文件,并写入 /etc/nginx 目录下,以 .conf结尾
  7. (File I/O) IC根据 Ingress 或者其它资源 获取的TLS 证书和私钥写入 文件中
  8. (HTTP) IC通过unix:/var/lib/nginx/nginx-status.sock 获取Nginx指标,并以Promethues格式暴露出去
  9. (HTTP) 为了确保配置文件加载成功,IC 会通过unix:/var/lib/nginx/nginx-config-version.sock确保至少有一个worker进程使用了最新的配置
  10. (N/A) IC 启动Nginx Master进程
  11. (Signal) IC 通过nginx -s reload重载Nignx 配置文件
  12. (Signal) IC 通过nginx -s quit停止Nginx进程
  13. (File I/O) master 将日志写入标准输出和标准错误,由容器运行时收集
  14. (File I/O) master 在启动和reload时从文件读取 TLS 证书和私钥
  15. (File I/O) master 在启动和reload时从文件读取 配置
  16. (Signal) master 控制worker进程的生命周期
  17. (File I/O) worker 将日志写入标准输出和标准错误,由容器运行时收集
  18. (UDP) worker 将upstream端点的响应延迟日志通过unix:/var/lib/nginx/nginx-syslog.sock发送给IC,由IC通过Metrics暴露
  19. (HTTP,HTTPS,TCP,UDP) worker 承接来自客户端的请求
  20. (HTTP,HTTPS,TCP,UDP) worker 将请求转发到后端的Pod上
  21. (HTTP) admin 通过 woker 的8080端口访问nginx的状态页,默认仅 localhost能访问

    1.1.3. IC 进程内部逻辑

    05-3-1-nginx - 图3
    IC 进程处理Kubernetes资源(ingress和CRD)的流程如下:

  22. 用户创建Ingress或CRD资源

  23. IC 进程会缓存关注的资源(Ingress和其它CRD资源),通过watch Kuberntes API保持缓存的同步
  24. 当资源发生变化,会通知 Control Loop
  25. Control Loop 从缓存中获取更新的资源,比如 TLS 证书、Ingress等
  26. Control Loop 生成TLS证书和私钥文件
  27. Control Loop 生成nginx配置文件
  28. Control Loop 执行 nginx reload,并等待nginx完成配置文件的加载:

7.1. nginx 重载并读取 TLS 证书
7.2. nginx 重载并读取配置文件

  1. Control Loop 推送event并更新资源状态

IC 关注的Kuberntes资源有以下这些:

  1. 七层负责均衡:Ingress、VirtualServers (CR)、VirtualServerRoutes (CR)
  2. 七层策略:Policies (CR)
  3. 四层负载均衡:TransportServers (CR)
  4. 服务发现:Service、Endpoints、Pods
  5. 密钥配置:Secrets
  6. 全局配置:ConfigMap、GlobalConfiguration (CR)
  7. 其它自定义资源(默认不启用):APPolicies, APLogConfs, APUserSigs、IngressLink

2. 部署

2.1. 版本说明

在部署或升级之前,需要参考官方提供的版本支持说明。一般而言尽量使用最新版本,官方明确说明所有版本是生产可用的,并且可实现稳定升级,不会存在版本回退的兼容性问题。
image.png
在镜像选择方面,支持基于Alpine、Debian、Redhat-Ubi 三种基础进行构建的镜像。并且还提供 OpenTracing 链路跟踪模块的版本,具体如下:

Name Base image Third-party modules DockerHub image Architectures
Alpine-based image nginx:1.21.6-alpine, which is based on alpine:3.15
nginx/nginx-ingress:2.2.0-alpine arm/v7, arm64, amd64, ppc64le, s390x
Alpine-based image with OpenTracing nginx:1.21.6-alpine, which is based on alpine:3.15 NGINX OpenTracing module, OpenTracing library, OpenTracing tracers for Jaeger, Zipkin and Datadog nginx/nginx-ingress:2.2.0-alpine-ot arm/v7, arm64, amd64, ppc64le, s390x
Debian-based image nginx:1.21.6, which is based on debian:bullseye-slim
nginx/nginx-ingress:2.2.0 arm/v7, arm64, amd64, ppc64le, s390x
Debian-based image with OpenTracing nginx:1.21.6, which is based on debian:bullseye-slim NGINX OpenTracing module, OpenTracing library, OpenTracing tracers for Jaeger, Zipkin and Datadog nginx/nginx-ingress:2.2.0-ot arm/v7, arm64, amd64, ppc64le, s390x
Ubi-based image redhat/ubi8
nginx/nginx-ingress:2.2.0-ubi arm64, amd64, s390x

Nginx官方提供三种部署方式:

  • 清单文件部署:虽然繁琐,但是自定义更加方便。由于Nginx部署方便,我更倾向于直接使用清单文件部署。
  • Chart 部署:方便后续的管理
  • Operator 部署:目前 starts 少,不推荐使用

    2.2. 使用清单文件部署

    这里给出所有部署的步骤和发生修改的清单文档,但是可能和官方文档版本会有出入,部署时可以相互印证

    1. [root@duduniao ~]# git clone https://github.com/nginxinc/kubernetes-ingress.git --branch v2.2.0
    2. [root@duduniao ~]# cd kubernetes-ingress/deployments
    3. # 将部署所有的基础设施部署清单都加到git仓库进行版本管理
    4. [root@duduniao deployments]# cp -r common daemon-set rbac service /data/projects/gitlab/kubernetes-manifest/local-01/deploy-infra/nginxinc-ingress
    5. [root@duduniao deployments]# cd /data/projects/gitlab/kubernetes-manifest/local-01/deploy-infra/nginxinc-ingress

    2.2.1. 配置RBAC

    [root@duduniao nginxinc-ingress]# kubectl apply -f common/ns-and-sa.yaml
    [root@duduniao nginxinc-ingress]# kubectl apply -f rbac/rbac.yaml
    

    2.2.2. 创建CRD

    # 创建默认的Nginx Server证书,该证书用于针对404页面响应和默认TLS证书。nginx默认提供了自签名证书 common/default-server-secret.yaml, 但是更加推荐使用自己的公司证书。
    [root@duduniao nginxinc-ingress]# kubectl create secret -n nginx-ingress tls default-server-secret --cert=certs/server.crt --key=certs/server.key
    
    [root@duduniao nginxinc-ingress]# kubectl apply -f common/nginx-config.yaml
    [root@duduniao nginxinc-ingress]# kubectl apply -f common/ingress-class.yaml
    
    # nginx 的自定义配置项,默认data为空
    kind: ConfigMap
    apiVersion: v1
    metadata:
    name: nginx-config
    namespace: nginx-ingress
    data:
    client-max-body-size: 10m
    error-log-level: error
    keepalive: "8"
    server-tokens: "false"
    ssl-protocols: TLSv1.2
    worker-connections: "10240"
    worker-processes: "2"
    # 当前环境的ingress controller下游是使用Nginx L4负载均衡的,为了获取到源地址,使用了 proxy protocol协议
    # 因此打开了 proxy-protocol,并且日志中也指定了proxy_protocol_addr
    # 如果下游LB可以透传地址到当前控制器,可以取消 proxy_protocol配置
    proxy-protocol: "true"
    log-format: '$time_local|$remote_addr|$proxy_protocol_addr|$http_x_real_ip|$http_x_forwarded_for|$resource_name|$resource_type|$resource_namespace|$service|$request_method|$server_protocol|$host|$request_uri|$http_referer|$http_user_agent|$body_bytes_sent|$status|$grpc_status'
    
    apiVersion: networking.k8s.io/v1
    kind: IngressClass
    metadata:
    name: nginx
    # 设置为默认的ingress class,如果注释annotations,表示不会设置为默认的ingress controller
    annotations:
      ingressclass.kubernetes.io/is-default-class: "true"
    spec:
    controller: nginx.org/ingress-controller
    
    [root@duduniao nginxinc-ingress]# kubectl apply -f common/crds/k8s.nginx.org_virtualservers.yaml
    [root@duduniao nginxinc-ingress]# kubectl apply -f common/crds/k8s.nginx.org_virtualserverroutes.yaml
    [root@duduniao nginxinc-ingress]# kubectl apply -f common/crds/k8s.nginx.org_transportservers.yaml
    [root@duduniao nginxinc-ingress]# kubectl apply -f common/crds/k8s.nginx.org_policies.yaml
    [root@duduniao nginxinc-ingress]# kubectl apply -f common/crds/k8s.nginx.org_globalconfigurations.yaml
    

    2.2.3. 部署控制器

    部署控制器的方式有两种:

  • 使用deployment + service(NodePort/LoadBalancer)

  • 使用daemonset

一般情况,在私有云环境中,更加推荐使用daemonset,在公有云可以使用 deployment。这里以daemon为例:

[root@duduniao nginxinc-ingress]# kubectl label nodes ubuntu-2004-104 ingress-controller/nginx=yes
[root@duduniao nginxinc-ingress]# kubectl label nodes ubuntu-2004-105 ingress-controller/nginx=yes
[root@duduniao nginxinc-ingress]# kubectl label nodes ubuntu-2004-106 ingress-controller/nginx=yes
[root@duduniao nginxinc-ingress]# kubectl apply -f daemon-set/nginx-ingress.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nginx-ingress
  namespace: nginx-ingress
spec:
  selector:
    matchLabels:
      app: nginx-ingress
  template:
    metadata:
      labels:
        app: nginx-ingress
     #annotations:                        # 如果prometheus是通过注释采集日志,则需要打开
       #prometheus.io/scrape: "true"
       #prometheus.io/port: "9113"
       #prometheus.io/scheme: http
    spec:
      serviceAccountName: nginx-ingress
      containers:
      - image: nginx/nginx-ingress:2.2.0  # 不带链路追踪的镜像,链路跟踪后续演示
        imagePullPolicy: IfNotPresent
        name: nginx-ingress
        ports:
        - name: http
          containerPort: 80
          hostPort: 80
        - name: https
          containerPort: 443
          hostPort: 443
        - name: readiness-port
          containerPort: 8081
        - name: prometheus
          containerPort: 9113
        readinessProbe:
         httpGet:
           path: /nginx-ready
           port: readiness-port
         periodSeconds: 1
        securityContext:
          allowPrivilegeEscalation: true
          runAsUser: 101 #nginx
          capabilities:
            drop:
            - ALL
            add:
            - NET_BIND_SERVICE
        env:
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: TZ                      # 指定时区,方便查看日志
          value: Asia/Shanghai
        args:
          - -nginx-configmaps=$(POD_NAMESPACE)/nginx-config
          - -default-server-tls-secret=$(POD_NAMESPACE)/default-server-secret
          - -wildcard-tls-secret=$(POD_NAMESPACE)/default-server-secret        # 指定默认证书,当ingress中声明TLS却没有指定secretName时使用该证书
          - -enable-prometheus-metrics  # 启用prometheus指标
          - -enable-snippets            # 支持通过注释插入代码片段
          - -health-status              # 开启健康状态检查接口,方便前端LB对它健康检查
          - -enable-latency-metrics     # 开启延迟指标监控
      nodeSelector:
        ingress-controller/nginx: "yes" # 选择部署的节点,即使是daemonset也不是所有worker节点都部署

2.2.4. LB配置

实验环境下,ingress controller 下游的LB使用的是nginx,配置如下:

upstream ingress-443 {
  server 10.4.7.106:443 max_fails=1 fail_timeout=30s ;
  server 10.4.7.105:443 max_fails=1 fail_timeout=30s ;
  server 10.4.7.104:443 max_fails=1 fail_timeout=30s ;
}

upstream ingress-80 {
  server 10.4.7.106:80 max_fails=1 fail_timeout=30s ;
  server 10.4.7.105:80 max_fails=1 fail_timeout=30s ;
  server 10.4.7.104:80 max_fails=1 fail_timeout=30s ;
}

server {
  listen 0.0.0.0:443 ;
  proxy_protocol on ;
  proxy_connect_timeout 2s;
  proxy_next_upstream on;
  proxy_next_upstream_timeout 5;
  proxy_next_upstream_tries 1;
  proxy_pass ingress-443;
  access_log /var/log/nginx/kube-ingress.log proxy;
}

server {
  listen 0.0.0.0:80 ;
  proxy_protocol on ;
  proxy_connect_timeout 2s;
  proxy_next_upstream on;
  proxy_next_upstream_timeout 5;
  proxy_next_upstream_tries 1;
  proxy_pass ingress-80;
  access_log /var/log/nginx/kube-ingress.log proxy;
}

2.2.5. 验证

2.2.5.1. 默认404页面

直接通过LB进行访问,测试443和80是否正常,并且验证443端口是否使用了默认的证书

[root@duduniao nginxinc-ingress]# curl -I http://10.4.7.100
HTTP/1.1 404 Not Found
Server: nginx
Date: Wed, 04 May 2022 08:31:59 GMT
Content-Type: text/html
Content-Length: 146
Connection: keep-alive

[root@duduniao nginxinc-ingress]# curl -I https://10.4.7.100 -k
HTTP/1.1 404 Not Found
Server: nginx
Date: Wed, 04 May 2022 08:32:16 GMT
Content-Type: text/html
Content-Length: 146
Connection: keep-alive
# 因为是本地vmware搭建的环境,使用 hosts 配置域名解析,解析域名到 LB
[root@duduniao nginxinc-ingress]# curl https://test.huanle.com  # 证书验证通过,表明默认证书配置正确
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
# 上述测试中,原客户端IP 10.4.7.1 已经被成功记录到日志中
04/May/2022:16:39:49 +0800|10.4.7.100|10.4.7.1|-|-|||||HEAD|HTTP/1.1|10.4.7.100|/|-|curl/7.68.0|0|404|
04/May/2022:16:39:56 +0800|10.4.7.100|10.4.7.1|-|-|||||GET|HTTP/1.1|test.huanle.com|/|-|curl/7.68.0|146|404|

# 如果带上X-Real-IP和X-Forwarded-For验证,模拟下游其它L7负载均衡器
[root@duduniao nginxinc-ingress]# curl -H "X-Real-IP: 192.168.99.251" -H "X-Forwarded-For: 192.168.99.251, 10.4.7.1" https://test.huanle.com
04/May/2022:16:44:33 +0800|10.4.7.100|10.4.7.1|192.168.99.251|192.168.99.251, 10.4.7.1|||||GET|HTTP/1.1|test.huanle.com|/|-|curl/7.68.0|146|404|

2.2.5.2. ingress http 验证

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ingress-demo-01
spec:
  replicas: 2
  selector:
    matchLabels:
      app: ingress-demo-01
      release: stable
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: ingress-demo-01
        release: stable
    spec:
      containers:
      - name: nginx-pod
        image: linuxduduniao/nginx:v1.0.5
---
apiVersion: v1
kind: Service
metadata:
  name: ingress-demo-01
spec:
  selector:
    app: ingress-demo-01
    release: stable
  ports:
  - name: http
    port: 80
    targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-demo-01
spec:
  ingressClassName: nginx
  rules:
  - host: ingress-demo-01.huanle.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: ingress-demo-01
            port:
              name: http
[root@duduniao ~]# curl ingress-demo-01.huanle.com/info
2022-05-04T08:49:22+00:00|v1.0.3|ingress-demo-01-698bb5556b-4rq5j|ok
[root@duduniao ~]# curl ingress-demo-01.huanle.com/info
2022-05-04T08:49:23+00:00|v1.0.3|ingress-demo-01-698bb5556b-vbwmz|ok
04/May/2022:16:48:39 +0800|10.4.7.100|10.4.7.1|-|-|ingress-demo-01|ingress|default|ingress-demo-01|GET|HTTP/1.1|ingress-demo-01.huanle.com|/info|-|curl/7.68.0|59|200|
04/May/2022:16:49:22 +0800|10.4.7.100|10.4.7.1|-|-|ingress-demo-01|ingress|default|ingress-demo-01|GET|HTTP/1.1|ingress-demo-01.huanle.com|/info|-|curl/7.68.0|70|200|

2.2.5.3. ingress https 验证

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ingress-demo-02
spec:
  replicas: 2
  selector:
    matchLabels:
      app: ingress-demo-02
      release: stable
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: ingress-demo-02
        release: stable
    spec:
      containers:
      - name: nginx-pod
        image: linuxduduniao/nginx:v1.0.4
---
apiVersion: v1
kind: Service
metadata:
  name: ingress-demo-02
spec:
  selector:
    app: ingress-demo-02
    release: stable
  ports:
  - name: http
    port: 80
    targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-demo-02
spec:
  ingressClassName: nginx
  rules:
  - host: ingress-demo-02.huanle.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: ingress-demo-02
            port:
              name: http
  tls:
  - hosts:
    - ingress-demo-02.huanle.com
    secretName: huanle.com
[root@duduniao nginxinc-ingress]# curl https://ingress-demo-02.huanle.com/info
2022-05-04T10:02:13+00:00|v1.0.4|ingress-demo-02-749fd84dc-kmtf5|ok
[root@duduniao nginxinc-ingress]# curl https://ingress-demo-02.huanle.com/info
2022-05-04T10:02:13+00:00|v1.0.4|ingress-demo-02-749fd84dc-j6xz5|ok
04/May/2022:18:02:10 +0800|10.4.7.100|10.4.7.1|-|-|ingress-demo-02|ingress|default|ingress-demo-02|GET|HTTP/1.1|ingress-demo-02.huanle.com|/info|-|curl/7.68.0|69|200|
04/May/2022:18:03:02 +0800|10.4.7.100|10.4.7.1|-|-|ingress-demo-02|ingress|default|ingress-demo-02|GET|HTTP/1.1|ingress-demo-02.huanle.com|/info|-|curl/7.68.0|69|200|

3. 配置

3.1. Nginx全局配置

3.1.1. 命令行参数

在Ingress Pod启动的Yaml文件中,可以指定启动参数,nginx涉及的启动参数较多,此处挑重点描述,其它请参考官方文档

  1. -enable-snippets:是否在ingress和nginx CRD资源中启用配置段功能,默认false。需要对nginx配置项有比较深的了解才能更好的使用它,否则很容易导致配置文件加载出错。通常仅在实现复杂的功能的情况下才会考虑开启。
  2. -default-server-tls-secret:指定默认的server端TLS证书和私钥,用于返回404页面使用。格式:namespace/secret
  3. -wildcard-tls-secret:用来指定默认的server端TLS证书和私钥,当ingress指定了TLS方式访问,但是没有指定secretName时使用该通配符证书
  4. -enable-custom-resources:是否启用自定义资源,默认为true
  5. -health-status:指定该参数将添加/nginx-healthlocation,用来给下游LB检查nginx是否正常
  6. -global-configuration:指定启动时读取通过CRD定义的全局配置,格式:namespace/name
  7. -ingress-template-path:指定nginx配置文件的渲染模板,默认nginx.ingress.tmpl
  8. -main-template-path:指定nginx主配置文件渲染模板,默认nginx.ingress.tmpl
  9. -nginx-configmaps:从configmap读取nginx配置,格式namespace/name
  10. -transportserver-template-path:指定TransportServer资源的配置文件渲染模板,默认值nginx.transportserver.tmpl
  11. -virtualserver-template-path:指定VirtualServer资源的配置文件渲染模板,默认值nginx.ingress.tmpl
  12. nginx-debug:指定nginx启用debug模式,需要在configmap中指定error-log-level: debug
  13. -nginx-status:启用nginx状态页,默认true
  14. -nginx-status-allow-cidrs:配置允许访问状态页的IP或CIDR,默认仅locahost
  15. -enable-prometheus-metrics:开启Prometheus指标导出功能
  16. -prometheus-metrics-listen-port:指定Prometheus指标导出接口的监听端口,默认9113
  17. -prometheus-tls-secret:指定Prometheus指标导出接口的监听端口的TLS证书和私钥,格式namespace/name,默认不加密

    3.1.2. ConfigMap

    使用ConfigMap配置nginx的全局配置参数,在定义ingress或者其它nginx CRD资源时,可以覆盖全局配置。同样ConfigMap涉及到的参数很多,此处仅挑重点的进行标红,其它请参考官方文档

    3.1.2.1. 常规自定义配置

    | ConfigMap Key | Description | Default | Example | | —- | —- | —- | —- | | proxy-connect-timeout | Sets the value of the proxy_connect_timeout and grpc_connect_timeout directive. | 60s |
    | | proxy-read-timeout | Sets the value of the proxy_read_timeout and grpc_read_timeout directive. | 60s |
    | | proxy-send-timeout | Sets the value of the proxy_send_timeout and grpc_send_timeout directive. | 60s |
    | | client-max-body-size | Sets the value of the client_max_body_size directive. | 1m |
    | | proxy-buffering | Enables or disables buffering of responses from the proxied server. | True |
    | | proxy-buffers | Sets the value of the proxy_buffers directive. | Depends on the platform. |
    | | proxy-buffer-size | Sets the value of the proxy_buffer_size and grpc_buffer_size directives. | Depends on the platform. |
    | | proxy-max-temp-file-size | Sets the value of the proxy_max_temp_file_size directive. | 1024m |
    | | set-real-ip-from | Sets the value of the set_real_ip_from directive. | N/A |
    | | real-ip-header | Sets the value of the real_ip_header directive. | X-Real-IP |
    | | real-ip-recursive | Enables or disables the real_ip_recursive directive. | False |
    | | default-server-return | Configures the return directive in the default server, which handles a client request if none of the hosts of Ingress or VirtualServer resources match. The default value configures NGINX to return a 404 error page. You can configure a fixed response or a redirect. For example, default-server-return: 302 https://nginx.org will redirect a client to https://nginx.org. | 404 |
    | | server-tokens | Enables or disables the server_tokens directive. Additionally, with the NGINX Plus, you can specify a custom string value, including the empty string value, which disables the emission of the“Server” field. | True |
    | | worker-processes | Sets the value of the worker_processes directive. | auto |
    | | worker-rlimit-nofile | Sets the value of the worker_rlimit_nofile directive. | N/A |
    | | worker-connections | Sets the value of the worker_connections directive. | 1024 |
    | | worker-cpu-affinity | Sets the value of the worker_cpu_affinity directive. | N/A |
    | | worker-shutdown-timeout | Sets the value of the worker_shutdown_timeout directive. | N/A |
    | | server-names-hash-bucket-size | Sets the value of the server_names_hash_bucket_size directive. | 256 |
    | | server-names-hash-max-size | Sets the value of the server_names_hash_max_size directive. | 1024 |
    | | resolver-addresses | Sets the value of the resolver addresses. Note: If you use a DNS name (for example, kube-dns.kube-system.svc.cluster.local ) as a resolver address, NGINX Plus will resolve it using the system resolver during the start and on every configuration reload. If the name cannot be resolved or the DNS server doesn’t respond, NGINX Plus will fail to start or reload. To avoid this, we recommend using IP addresses as resolver addresses instead of DNS names. Supported in NGINX Plus only. | N/A | Support for Type ExternalName Services
    . | | resolver-ipv6 | Enables IPv6 resolution in the resolver. Supported in NGINX Plus only. | True | Support for Type ExternalName Services | | resolver-valid | Sets the time NGINX caches the resolved DNS records. Supported in NGINX Plus only. | TTL value of a DNS record | Support for Type ExternalName Services | | resolver-timeout | Sets the resolver_timeout for name resolution. Supported in NGINX Plus only. | 30s | Support for Type ExternalName Services | | keepalive-timeout | Sets the value of the keepalive_timeout directive. | 65s |
    | | keepalive-requests | Sets the value of the keepalive_requests directive. | 100 |
    | | variables-hash-bucket-size | Sets the value of the variables_hash_bucket_size directive. | 256 |
    | | variables-hash-max-size | Sets the value of the variables-hash-max-size directive. | 1024 |
    |

3.1.2.2. 日志配置

ConfigMap Key Description Default Example
error-log-level Sets the global error log level for NGINX. notice
access-log-off Disables the access log False
default-server-access-log-off Disables the access log for the default server. If access log is disabled globally (access-log-off: “True”), then the default server access log is always disabled. False
log-format Sets the custom log format for HTTP and HTTPS traffic. For convenience, it is possible to define the log format across multiple lines (each line separated by \n). In that case, the Ingress Controller will replace every \n character with a space character. All ‘ characters must be escaped. See the template file for the access log. Custom Log Format
.
log-format-escaping Sets the characters escaping for the variables of the log format. Supported values: json (JSON escaping), default (the default escaping) none (disables escaping). default
stream-log-format Sets the custom log format for TCP, UDP, and TLS Passthrough traffic. For convenience, it is possible to define the log format across multiple lines (each line separated by \n). In that case, the Ingress Controller will replace every \n character with a space character. All ‘ characters must be escaped. See the template file
.

stream-log-format-escaping Sets the characters escaping for the variables of the stream log format. Supported values: json (JSON escaping), default (the default escaping) none (disables escaping). default

3.1.2.3. SSL/TLS 配置

ConfigMap Key Description Default
redirect-to-https Sets the 301 redirect rule based on the value of the http_x_forwarded_proto header on the server block to force incoming traffic to be over HTTPS. Useful when terminating SSL in a load balancer in front of the Ingress Controller — see 115 False
ssl-redirect Sets an unconditional 301 redirect rule for all incoming HTTP traffic to force incoming traffic over HTTPS. True
hsts Enables HTTP Strict Transport Security (HSTS) : the HSTS header is added to the responses from backends. The preload directive is included in the header. False
hsts-max-age Sets the value of the max-age directive of the HSTS header. 2592000 (1 month)
hsts-include-subdomains Adds the includeSubDomains directive to the HSTS header. False
hsts-behind-proxy Enables HSTS based on the value of the http_x_forwarded_proto request header. Should only be used when TLS termination is configured in a load balancer (proxy) in front of the Ingress Controller. Note: to control redirection from HTTP to HTTPS configure the nginx.org/redirect-to-https annotation. False
ssl-protocols Sets the value of the ssl_protocols directive. TLSv1 TLSv1.1 TLSv1.2
ssl-prefer-server-ciphers Enables or disables the ssl_prefer_server_ciphers directive. False
ssl-ciphers Sets the value of the ssl_ciphers directive. HIGH:!aNULL:!MD5
ssl-dhparam-file Sets the content of the dhparam file. The controller will create the file and set the value of the ssl_dhparam directive with the path of the file. N/A

3.1.2.4. Listeners配置

ConfigMap Key Description Default Example
http2 Enables HTTP/2 in servers with SSL enabled. False
proxy-protocol Enables PROXY Protocol for incoming connections. False Proxy Protocol

3.1.2.5. Backend配置

ConfigMap Key Description Default
lb-method Sets the load balancing method. To use the round-robin method, specify “round_robin”. “random two least_conn”
max-fails Sets the value of the max_fails parameter of the server directive. 1
upstream-zone-size Sets the size of the shared memory zone for upstreams. For NGINX, the special value 0 disables the shared memory zones. For NGINX Plus, shared memory zones are required and cannot be disabled. The special value 0 will be ignored. 256k for NGINX, 512k for NGINX Plus
fail-timeout Sets the value of the fail_timeout parameter of the server directive. 10s
keepalive Sets the value of the keepalive directive. Note that proxy_set_header Connection “”; is added to the generated configuration when the value > 0. 0

3.1.2.6. Snippets & Custom 模板

ConfigMap Key Description Default Example
main-snippets Sets a custom snippet in main context. N/A
http-snippets Sets a custom snippet in http context. N/A
location-snippets Sets a custom snippet in location context. N/A
server-snippets Sets a custom snippet in server context. N/A
stream-snippets Sets a custom snippet in stream context. N/A Support for TCP/UDP Load Balancing
main-template Sets the main NGINX configuration template. By default the template is read from the file in the container. Custom Templates
ingress-template Sets the NGINX configuration template for an Ingress resource. By default the template is read from the file on the container. Custom Templates
virtualserver-template Sets the NGINX configuration template for an VirtualServer resource. By default the template is read from the file on the container. Custom Templates

3.1.2.7. 链路追踪

ConfigMap Key Description Default
opentracing Enables OpenTracing globally (for all Ingress, VirtualServer and VirtualServerRoute resources). Note: requires the Ingress Controller image with OpenTracing module and a tracer. See the docs for more information. False
opentracing-tracer Sets the path to the vendor tracer binary plugin. N/A
opentracing-tracer-config Sets the tracer configuration in JSON format. N/A

3.2. Ingress资源配置

Kubernetes原生的ingress支持的字段很少,只有域名、路径、协议、上游服务器等配置项,在实践中往往需要更加复杂的配置,比如请求头配置、长链接配置、rewrite配置等。通常情况下,使用annotations进行配置。

3.2.1. annotations

在创建Ingress时,IC会检查所有annotations中nginx相关的注解,并且对其进行校验,如果校验失败,则不会被创建nginx配置文件,也就无法完成流量转发,此时可以通过kubectl describe ingress xxx进行查看报错原因。但是IC并不会对所有的注解进行校验,以下是不校验的注解:

  • nginx.org/server-tokens
  • nginx.org/proxy-hide-headers
  • nginx.org/proxy-pass-headers
  • nginx.org/rewrites

    3.2.1.2. Listeners

    | Annotation | ConfigMap Key | Description | Default | Example | | —- | —- | —- | —- | —- | | nginx.org/listen-ports | N/A | Configures HTTP ports that NGINX will listen on. | [80] |
    | | nginx.org/listen-ports-ssl | N/A | Configures HTTPS ports that NGINX will listen on. | [443] |
    |

3.2.1.3. General

Annotation ConfigMap Key Description Default Example
nginx.org/proxy-connect-timeout proxy-connect-timeout Sets the value of the proxy_connect_timeout and grpc_connect_timeout directive. 60s
nginx.org/proxy-read-timeout proxy-read-timeout Sets the value of the proxy_read_timeout and grpc_read_timeout directive. 60s
nginx.org/proxy-send-timeout proxy-send-timeout Sets the value of the proxy_send_timeout and grpc_send_timeout directive. 60s
nginx.org/client-max-body-size client-max-body-size Sets the value of the client_max_body_size directive. 1m
nginx.org/proxy-buffering proxy-buffering Enables or disables buffering of responses from the proxied server. True
nginx.org/proxy-buffers proxy-buffers Sets the value of the proxy_buffers directive. Depends on the platform.
nginx.org/proxy-buffer-size proxy-buffer-size Sets the value of the proxy_buffer_size and grpc_buffer_size directives. Depends on the platform.
nginx.org/proxy-max-temp-file-size proxy-max-temp-file-size Sets the value of the proxy_max_temp_file_size directive. 1024m
nginx.org/server-tokens server-tokens Enables or disables the server_tokens directive. Additionally, with the NGINX Plus, you can specify a custom string value, including the empty string value, which disables the emission of the “Server” field. True

3.2.1.4. URI/Header

Annotation ConfigMap Key Description Default Example
nginx.org/proxy-hide-headers proxy-hide-headers Sets the value of one or more proxy_hide_header directives. Example: “nginx.org/proxy-hide-headers”: “header-a,header-b” N/A
nginx.org/proxy-pass-headers proxy-pass-headers Sets the value of one or more proxy_pass_header directives. Example: “nginx.org/proxy-pass-headers”: “header-a,header-b” N/A
nginx.org/rewrites N/A Configures URI rewriting. N/A Rewrites Support

3.2.1.5. Auth / TLS

Annotation ConfigMap Key Description Default
nginx.org/redirect-to-https redirect-to-https Sets the 301 redirect rule based on the value of the http_x_forwarded_proto header on the server block to force incoming traffic to be over HTTPS. Useful when terminating SSL in a load balancer in front of the Ingress Controller — see 115 False
ingress.kubernetes.io/ssl-redirect ssl-redirect Sets an unconditional 301 redirect rule for all incoming HTTP traffic to force incoming traffic over HTTPS. True
nginx.org/hsts hsts Enables HTTP Strict Transport Security (HSTS) \ : the HSTS header is added to the responses from backends. The preload directive is included in the header. False
nginx.org/hsts-max-age hsts-max-age Sets the value of the max-age directive of the HSTS header. 2592000 (1 month)
nginx.org/hsts-include-subdomains hsts-include-subdomains Adds the includeSubDomains directive to the HSTS header. False
nginx.org/hsts-behind-proxy hsts-behind-proxy Enables HSTS based on the value of the http_x_forwarded_proto request header. Should only be used when TLS termination is configured in a load balancer (proxy) in front of the Ingress Controller. Note: to control redirection from HTTP to HTTPS configure the nginx.org/redirect-to-https annotation. False

3.2.1.6. upstream

Annotation ConfigMap Key Description Default Example
nginx.org/lb-method lb-method Sets the load balancing method. To use the round-robin method, specify “round_robin”. “random two least_conn”
nginx.org/ssl-services N/A Enables HTTPS or gRPC over SSL when connecting to the endpoints of services. N/A SSL Services Support
nginx.org/grpc-services N/A Enables gRPC for services. Note: requires HTTP/2 (see http2 ConfigMap key); only works for Ingresses with TLS termination enabled. N/A GRPC Services Support
nginx.org/websocket-services N/A Enables WebSocket for services. N/A WebSocket support
nginx.org/max-fails max-fails Sets the value of the max_fails parameter of the server directive. 1
nginx.org/max-conns N\A Sets the value of the max_conns parameter of the server directive. 0
nginx.org/upstream-zone-size upstream-zone-size Sets the size of the shared memory zone for upstreams. For NGINX, the special value 0 disables the shared memory zones. For NGINX Plus, shared memory zones are required and cannot be disabled. The special value 0 will be ignored. 256K
nginx.org/fail-timeout fail-timeout Sets the value of the fail_timeout parameter of the server directive. 10s
nginx.org/keepalive keepalive Sets the value of the keepalive directive. Note that proxy_set_header Connection “”; is added to the generated configuration when the value > 0. 0

3.2.1.7. sinppets

Annotation ConfigMap Key Description Default
nginx.org/location-snippets location-snippets Sets a custom snippet in location context. N/A
nginx.org/server-snippets server-snippets Sets a custom snippet in server context. N/A

3.2.3. 案例

3.2.3.1. 简单demo

  • http 服务:参考 2.2.5.2
  • https 服务:参考2.2.5.3

    3.2.3.2. kubernetes dashboard

  1. 部署dashboard:参考官方文档
  2. 通常需要使用kubectl proxy才能访问,为了方便使用ingress暴露dashboard服务 ```yaml

kind: Service apiVersion: v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard spec: ports:

- name: https
  port: 8443
  targetPort: 8443

selector: k8s-app: kubernetes-dashboard


apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: dashboard namespace: kubernetes-dashboard annotations:

# 从nginx访问后端的svc,采用 https 协议
nginx.org/ssl-services: kubernetes-dashboard

spec: ingressClassName: nginx rules:

  • host: dashboard.huanle.com http: paths:
    • path: / pathType: Prefix backend: service:
      name: kubernetes-dashboard
      port:
        name: https
      

      没指定 secretName时使用默认泛域名证书,通过IC命令行参数 -wildcard-tls-secret 指定

      指定 tls 后,http协议会被重定向为https: return 301 https://$host:443$request_uri;

      tls:
  • hosts:
    • dashboard.huanle.com ```

      3.2.3.3. jenkins

      Jenkins 部署完毕后,如果用户需要访问jenkins dashboard,那么通常建议配置 ingress ,这样比 NodePort 更方便,至少不用携带端口。但是不合理的代理配置会导致jenkins提示反向代理错误。 ```yaml apiVersion: v1 kind: Namespace metadata: name: devops

apiVersion: v1 kind: PersistentVolumeClaim metadata: name: jenkins-default namespace: devops spec: storageClassName: managed-nfs-storage accessModes:

- ReadWriteMany

resources: requests:

  storage: 5Gi

apiVersion: apps/v1 kind: Deployment metadata: name: jenkins-default namespace: devops spec: replicas: 1 selector: matchLabels: app: jenkins instance: default template: metadata: labels: app: jenkins instance: default spec: containers:

  - name: jenkins-server
    image: jenkins/jenkins:2.344
    ports:
    - name: http-port
      containerPort: 8080
    - name: jnlp-port
      containerPort: 50000
    volumeMounts:
    - name: jenkins-home
      mountPath: /var/jenkins_home
    resources:
      limits:
        cpu: 2048m
        memory: 2048Mi
      requests:
        cpu: 100m
        memory: 512Mi
  volumes:
  - name: jenkins-home
    persistentVolumeClaim:
      claimName: jenkins-default

apiVersion: v1 kind: Service metadata: name: jenkins-default-web namespace: devops spec: type: ClusterIP selector: app: jenkins instance: default ports:

  • port: 8080 targetPort: http-port

apiVersion: v1 kind: Service metadata: name: jenkins-default-jnlp namespace: devops spec: type: ClusterIP selector: app: jenkins instance: default ports:

  • port: 50000 targetPort: jnlp-port

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: jenkins-default namespace: devops annotations: nginx.org/client-max-body-size: 64m nginx.org/keepalive: “4” spec: ingressClassName: nginx rules:

  • host: jenkins-default.huanle.com http: paths:
    • path: / pathType: Prefix backend: service:
      name: jenkins-default-web
      port:
        number: 8080
      
      tls:
  • hosts:
    • jenkins-default.huanle.com ```

      3.2.3.4. 更多案例

      官方提供了很多配置示例,重点关注 Rewrite,Websocket,GRPC的示例。

      3.3. CRD配置

      3.3.1. TransportServer

      TransportServer 是用来定义TCP/UDP层的转发规则,一般情况也用不上。如果是给集群内部的服务使用,那么为啥直接走SVC?
      如果暴露给集群外部,那么我们为啥不用NodePort?
      如果必须要走IC,那么我们为了更好的暴露端口,那么是不是使用两台专用节点部署IC,并直接使用宿主机的网络名称空间?
      如果需要学习,可以参考官方文档

      3.3.2. VirtualServer & VirtualServerRoute

      同样,我个人人为意义不大,与其学习更复杂的定义格式,不如直接使用 ingress + sinppets

4. 运维

4.1. 日志

nginx 的访问日志对部分服务而言很重要,甚至可以考虑接入到日志中心,在接入前需要考虑以下事项:

  1. 日志格式如何定义?可以参考 2.2.2 中 common/nginx-config.yaml 配置
  2. 访问日志如何区分?默认标准容器日志中混杂了error日志,access日志,IC日志,采集端需要更加定义的日志格式进行区分
  3. 访问日志如何落盘?默认错误日志写到sdterr,访问日志写到stdout。如果要落盘就得挂盘,并写入日志
  4. 如何透传客户端IP?如果IC前端有LB,那么如何获取客户端真实IP?2.2.2 中 common/nginx-config.yaml 中proxy-protocol是一种解决方案。

    4.2. 状态页

    默认情况下,IC是开启状态页的,如果临时通过状态页查看当前nginx状态,可以将 nginx pod 的8080端口映射出来:

    [root@duduniao jenkins]# kubectl port-forward -n nginx-ingress nginx-ingress-v99fw 8080:8080
    [root@duduniao deploy-cluster]# curl 127.0.0.1:8080/stub_status
    Active connections: 1
    server accepts handled requests
    28 28 630
    Reading: 0 Writing: 1 Waiting: 0
    

    4.3. 监控

    IC使用-enable-prometheus-metrics暴露prometheus格式的指标,默认metrics 接口为http://<pod_ip>:9113/metrics,具体可以参考readme中指标含义描述。
    Grafana 示例可以参考官方的 dashboard.json 文件
    通常情况下,prometheus采集pod指标有两种自动发现方案:

  5. promethues通过注解自动添加pod到监控列表。在pod的annotations中定义,比如 2.2.3. 的 daemon-set/nginx-ingress.yaml 中注解部分

  6. prometheus通过ServiceMonitor添加pod到监控列表。自定义资源ServiceMonitor关联到service完成自动发现Endpoint中Pod列表