011-Kubernetes Ingress-Nginx

  1. 一、负载均衡器
    1. 1. 基于 LVS 的 HTTPS 负载均衡
    2. 2. 基于 Nginx 的 HTTPS 负载均衡
  2. 二、Ingress简介
    1. 1. Ingress 介绍
    2. 2. Ingress 与 Service
  3. 三、 安装 Ingress 控制器
    1. 1. 下载 Ingress-nginx 安装包
    2. 2. 导入 Ingress-nginx 镜像
    3. 3. 安装 Ingress-nginx
      1. 3.1 解压 Ingress-nginx 压缩包
      2. 3.2 编辑 values.yaml
      3. 3.3 关于 dnsPolicy
      4. 3.4 安装 ingress-nginx
    4. 4. 测试 Ingress-nginx
      1. 4.1 创建 Service 和 Deployment
      2. 4.2 创建 Ingress
      3. 4.3 修改主机 host 文件
      4. 4.4 浏览器访问域名
  4. 四、Ingress Nginx 使用
    1. 1. Ingress-nginx HTTP 代理
    2. 2. Ingress-nginx HTTPS 代理
      1. 2.1 生成证书和私钥
      2. 2.2 创建资源清单
    3. 3. Ingress-nginx BasicAuth 代理
    4. 4. Ingress-nginx 域名重定向
    5. 5. Ingress-nginx Rewrite
      1. 5.1 案例
      2. 5.1 rewrite 和 redirect
    6. 6. Ingress-nginx 错误代码重定向
      1. 6.1 默认错误后端(全局)
        1. 6.1.1 修改 values.yaml
        2. 6.1.2 更新 Ingress Nginx
        3. 6.1.3 测试资源清单
      2. 6.2 单独声明错误后端
    7. 7. Ingress-nginx 匹配请求头
      1. 7.1 开启 Snippet
      2. 7.2 编辑资源清单
    8. 8. Ingress-nginx 配置黑白名单
      1. 8.1. 配置方案
      2. 8.2 黑白名单的区别
      3. 8.3 ConfigMap 添加黑名单
        1. 8.3.1 编辑 Ingress-Nginx ConfigMap
        2. 8.3.2 测试资源清单
      4. 8.4 Annotations 添加黑名单
      5. 8.5 ConfigMap 设置白名单
        1. 8.5.1 编辑 Ingress-Nginx ConfigMap
        2. 8.5.2 测试资源清单
      6. 8.6 Annotations 添加白名单
    9. 9. Ingress-nginx 速率限制
      1. 9.1 速率限制设置
      2. 9.2 测试案例:无速率限制
      3. 9.3 测试案例:使用 Ingress 限制请求速率
    10. 10. Ingress-nginx 灰度或者金丝雀发布
      1. 10.1 概述
      2. 10.2 创建 V1 版本的 Ingress
      3. 10.3 创建 V2 版本的 Ingress
    11. 11. Ingress-nginx 代理后端 https 协议
    12. 12. Ingress-nginx 四层代理
      1. 12.1TCP代理
      2. 12.2 UDP代理
    13. 13. Ingress-nginx 链路追踪
      1. 13.1 部署 Jaeger
      2. 13.2 ingress 设置

K8S集群服务器

IP Hostname
10.20.1.139 k8s-master01
10.20.1.140 k8s-node01
10.20.1.141 k8s-node02

一、负载均衡器

负载均衡器有两类,区别在于 四层网络七层网络 的支持,传输层在第四层,这层协议有 TCP/UDP/TCP SSL 等,而七层有 HTTP/HTTPS。

1. 基于 LVS 的 HTTPS 负载均衡

基于 LVS 的 HTTPS 负载均衡 是 典型的四层代理架构。客户端发出请求,经过LVS直接转发到服务器,然后服务器返回结果,从请求的发出到结果的响应,中间仅仅产生一次完整的TCP连接。

四层代理架构

2. 基于 Nginx 的 HTTPS 负载均衡

基于 Nginx 的 HTTPS 负载均衡是一种基于七层网络代理架构的实现。客户端发出 https 请求,请求到达nginx服务器,nginx 重新生成一个新的 http 请求发到真实的服务器,服务器计算结果后发往 nginx,nginx再将结果以 https 的方式返回给客户端。从请求的发出到结果的响应,中间产生了两次请求。

七层代理架构

二、Ingress简介

1. Ingress 介绍

Ingress 是从 Kubernetes 集群外部访问集群内部服务的入口,同时为集群内的 Service 提供七层负载均衡能力。它提供了 HTTP 和 HTTPS 路由功能,使外部流量能够访问集群内部的服务。通过定义 Ingress 资源,可以控制哪些外部请求能够访问集群中的哪些服务,以及如何路由这些请求。

具体架构图如下:

Ingress架构

我们做网站时,使用 Nginx 做 Web 服务器,会使用一个子域名绑定一个网站,a.xxx.com 绑定 A 网站,b.xxx.com 绑定 B 网站,这样在一个域名的不同子域名可以访问不同的站点,对于现在的大多数互联网网站,依然会使用这种方法划分。

在微服务架构中,多个模块部署在不同的服务器上,则但是我们希望都通过 xxx.com 这个域名直接访问,就好像所有模块都在一起,让用户感觉只有一个网站。则可能会使用目录路径对模块进行划分,例如如果我们要实现 xxx.com/a 访问 A 模块,xxx.com/b 访问 B 模块,但对用户来说,一直在访问 xxx.com 这个域名。

这种需求,我们可以使用 nginx 进行反向代理,而在 Kubernetes 中,这种需求也是一模一样的。

首先,我们可以为 A、B、C 等应用,创建多个 Service,每个 Service 访问一个应用,然后使用 Ingress 配置路由规则,决定 URL 可以访问哪个 Service。

Ingress代理请求

Ingress 公开了从集群外部到集群内服务的 HTTP 和 HTTPS 路由,Ingress 资源上定义的规则控制了路由。

Ingress 可以让集群中的多个 Service 能够从集群外访问,Ingress 还提供负载均衡、SSL/TLS 和基于名称的虚拟服务器等,Ingress 可以配置边缘路由器或其他前端工具来帮助处理网络流量,但是一般都是通自己的负载均衡器来实现。

Ingress 有两部分,一部分是 LoadBalancer ,提供统一入口,代理请求;另一部分是 Ingress 控制器,复制定义路由规则等。

如果不使用公有云平台的 LoadBalancer ,那么就自己搭建一个服务器,这台服务器加入到 Kubernetes 集群中,做流量入口,这台服务器网络接口必须够大,抗得住流量。

2. Ingress 与 Service

在前面,我们已经学习到了 Service,通过 Service 我们可以暴露一个端口到外网中,通过这个端口可以访问应用。

其中,有两种方法可以暴露 Service,可以让其被集群外部访问:

  • 使用 Service.Type=LoadBalancer
  • 使用 Service.Type=NodePort

Service 的访问方式是 IP,每次要将服务公开给外界时,都必须创建一个新的 LoadBalancer 并向云服务商获取一个公网 IP 地址。或者使用 NodePort,但是只能在一台服务器上被访问,而且 Service 只能为一种 Pod 服务,暴露一个或多个端口,那么 N 个服务,就需要创建 N 个 Service。Service 虽然能够公开端口到外部网络中,但是无法将这些服务合并到一个 example.com/{服务} 中访问,Service 需要通过不同的端口访问。

如果你有一个 example.com 域名,你部署了多个 Web 服务,其中有两个子模块分别为课程(course)、考试(exam) 两个微服务,这些模块构成了一个培训网站。此时我们希望访问 example.com/api/course 能够访问课程学习模块,访问 example.com/api/exam 能够访问考试模块。显然,Service 是无法做到的。

使用 Ingress ,可以轻松设置路由规则,而且无需创建一堆 LoadBalancers/Nodes 公开每个服务,并且 Ingress 本身具有很多功能。

Ingress 也需要 Service 。

三、 安装 Ingress 控制器

Ingress 控制器有多种实现,其中 Kubernetes 官方有一个名为 Ingress-nginx 的实现,其它实现还有 Kong Ingress、Traefik、HAProxy Ingress 等。这里演示 使用 Helm 安装 Ingress-nginx 。

官方文档:https://kubernetes.github.io/ingress-nginx/deploy/#using-helm

1. 下载 Ingress-nginx 安装包

需要首先安装helm管理工具:https://georgechan95.github.io/blog/d8e3c7b3.html

ingress-nginx 的仓库在国外,国内下载需要vpn支持,参考:https://georgechan95.github.io/blog/7f174b3e.html

# 添加 ingress-nginx仓库
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx

# 下载 ingress-nginx 安装包
helm pull ingress-nginx/ingress-nginx --version=4.8.3

2. 导入 Ingress-nginx 镜像

这些镜像是 ingress-nginx 启动时所需的镜像,由于国内的网络无法从国外下载镜像,因此需要提前把这些镜像下载好,导入到服务器中。

关于如何使用 Docker 拉取谷歌镜像,参考这篇博客:https://georgechan95.github.io/blog/b01d5c62.html

# 下载 ingress-nginx 需要的镜像
# 所有节点都需要导入这些镜像
docker pull registry.k8s.io/ingress-nginx/controller:v1.9.4
docker pull registry.k8s.io/defaultbackend-amd64:1.5
docker pull registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20231011-8b53cabe0
docker pull registry.k8s.io/ingress-nginx/opentelemetry:v20230721-3e2062ee5

3. 安装 Ingress-nginx

3.1 解压 Ingress-nginx 压缩包

# 安装包解压
$ tar -zxvf ingress-nginx-4.8.3.tgz

# 进入 ingress-nginx 解压后的目录
$ cd ingress-nginx

# 当前所在目录
$ pwd
/opt/k8s/10/ingress-nginx

# 查看 ingress-nginx 目录结构
$ tree .
.
├── CHANGELOG.md
├── Chart.yaml
├── .....
├── README.md.gotmpl
├── changelog
│   ├── Changelog-4.5.2.md
│   ├── .....
│   └── Changelog-4.8.3.md
├── changelog.md.gotmpl
├── ci
│   ├── controller-admission-tls-cert-manager-values.yaml
........
│   └── deployment-webhook-values.yaml
├── templates
│   ├── NOTES.txt
│   ├── admission-webhooks
│   │   ├── cert-manager.yaml
│   │   ├── job-patch
│   │   │   ├── clusterrole.yaml
│   │   │   ├── ......
│   │   │   └── serviceaccount.yaml
│   │   └── validating-webhook.yaml
│   ├── clusterrole.yaml
│   ├── .....
│   └── default-backend-serviceaccount.yaml
└── values.yaml

3.2 编辑 values.yaml

# 修改 values.yaml 文件
$ vim values.yaml

# 修改1:
# 修改如下内容:
controller
  hostNetwork: true # 使用主机网路
  dnsPolicy: ClusterFirstWithHostNet # Pod 的网络命名空间与主机共享,Pod 使用主机的网络栈
  kind: DaemonSet # 每个节点部署一个 ingress-nginx-controller
  ingressClassResource:
    default: true # 使用默认的Inginx类,默认是 nginx

# 修改2:
#注释 digest 相关内容
controller
  image:
    #digest: sha256:xxxxx
    #digestChroot: sha256:xxxxx
  admissionWebhooks:
    patch:
      image:
        #digest: sha256:xxxxx

将解压后的 ingress-nginx 目录内 values.yaml 文件中的 digest: sha256xxxx 所在的所有的行注释掉,避免因为下载镜像的指纹与文件要求不一致,无法运行

注释digest指纹信息

3.3 关于 dnsPolicy

ClusterFirstWithHostNet

  • 当 Pod 的 hostNetwork 设置为 true 时,使用该 DNS 策略。
  • 这意味着 Pod 的网络命名空间与主机共享,Pod 使用主机的网络栈。
  • 在此配置下,Pod 将首先尝试通过主机上的 DNS 解析 DNS 请求。如果主机上没有找到,则会将请求发送到 kube-dns 服务,由 kube-dns 服务进行处理。
  • 这种策略适用于需要与主机网络共享的特殊情况,但它不会为 Pod 提供专用的 DNS 解析功能。

ClusterFirst

  • 这是 Kubernetes 中默认的 DNS 策略。
  • 当 Pod 的 hostNetwork 设置为 false 或未设置时,使用该策略。
  • 在此策略下,Pod 首先尝试通过 kube-dns 服务解析 DNS 请求。如果 kube-dns 无法解析,则会向上级 DNS 服务器继续发起请求。
  • 这种策略适用于大多数情况,其中 Pod 需要使用 Kubernetes 集群的 DNS 服务解析其他 Pod 或服务的主机名。

3.4 安装 ingress-nginx

# 使用 Helm 安装 ingress-nginx
$ helm install ingress-nginx --namespace ingress-nginx --create-namespace .

# 查看 ingress-nginx release
$ helm list -n ingress-nginx
NAME         	NAMESPACE    	REVISION	UPDATED                                	STATUS  	CHART              	APP VERSION
ingress-nginx	ingress-nginx	1       	2025-06-26 18:35:32.209570796 +0800 CST	deployed	ingress-nginx-4.8.3	1.9.4

# 查看 IngressClass
$ kubectl get ingressclass
NAME    CONTROLLER             PARAMETERS   AGE
nginx   k8s.io/ingress-nginx   <none>       153m

# 查看 Service
$ kubectl get service -n ingress-nginx
NAME                                 TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             LoadBalancer   10.105.7.64     <pending>     80:32570/TCP,443:31991/TCP   117m
ingress-nginx-controller-admission   ClusterIP      10.102.42.201   <none>        443/TCP                      117m

# 查看 Pod
$ kubectl get pod -n ingress-nginx -o wide
NAME                             READY   STATUS    RESTARTS   AGE    IP              NODE         NOMINATED NODE   READINESS GATES
ingress-nginx-controller-pf6sb   1/1     Running   0          117m   192.168.6.141   k8s-node02   <none>           <none>
ingress-nginx-controller-qmb7h   1/1     Running   0          117m   192.168.6.140   k8s-node01   <none>           <none>

# 查看 DaemonSet
$ kubectl get daemonset -n ingress-nginx -o wide
NAME                       DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE    CONTAINERS   IMAGES                                            SELECTOR
ingress-nginx-controller   2         2         2       2            2           kubernetes.io/os=linux   118m   controller   registry.k8s.io/ingress-nginx/controller:v1.9.4   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx

4. 测试 Ingress-nginx

4.1 创建 Service 和 Deployment

httpproxy-dep-svc.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: my-nginx
          image: nginx:1.29.0
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 80
              protocol: TCP

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  namespace: default
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
  selector:
    app: nginx

执行资源清单

$ kubectl apply -f httpproxy-dep-svc.yaml

查看资源

$ kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   59d   <none>
nginx-svc    ClusterIP   10.111.16.251   <none>        80/TCP    8s    app=nginx

$ kubectl get deployment -o wide 
NAME           READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES         SELECTOR
nginx-deploy   2/2     2            2           16s   my-nginx     nginx:1.29.0   app=nginx

$ kubectl get pods -o wide
NAME                            READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
nginx-deploy-6fc4ff86dc-n76xc   1/1     Running   0          22s   172.16.58.249   k8s-node02   <none>           <none>
nginx-deploy-6fc4ff86dc-nlmw5   1/1     Running   0          22s   172.16.85.206   k8s-node01   <none>           <none>

4.2 创建 Ingress

ingress.yaml

apiVersion: networking.k8s.io/v1 # 指定 API 版本
kind: Ingress # 指定资源类型为 Ingress,表示这是一个用于管理 HTTP/HTTPS 流量的 Kubernetes 资源
metadata:
  name: ingress-httpproxy
  namespace: default
spec:
  ingressClassName: nginx # 指定此 Ingress 资源由名称为 nginx 的 IngressClass 处理,定义在 values.yaml 中 controller.ingressClassResource.name
  rules: # 定义了流量路由的规则,即如何根据域名(host)和路径(path)将请求转发到后端服务。
    - host: www.test-http-proxy.com # 指定此规则适用于请求的 HTTP 主机头(Host Header)为 www.test-http-proxy.com 的流量。客户端必须通过该域名访问, 如果省略 host,Ingress 会匹配所有域名(即通配规则)。
      http: # 定义了 HTTP 协议的路由规则
        paths: # 用于指定路径匹配规则
          - path: / # 指定匹配的 URL 路径为 /,即根路径,这是最常见的路径,表示匹配所有以 / 开头的请求
            pathType: Prefix # 定义路径匹配的类型为 Prefix,表示匹配以指定路径(/) 开头的所有请求
            backend: # 定义请求的转发目标,即后端服务
              service:
                name: nginx-svc # 指定后端服务的名称为 nginx-svc.(必须存在于同一命名空间,或通过 <namespace>/<service-name> 跨命名空间引用)
                port:
                  number: 80 # 指定目标 Service 的端口为 80

执行资源清单

$ curl http://www.test-http-proxy.com

查看资源

$ kubectl get ingress -o wide
NAME                CLASS   HOSTS                     ADDRESS   PORTS   AGE
ingress-httpproxy   nginx   www.test-http-proxy.com             80      18

4.3 修改主机 host 文件

修改host文件,将其中一台集群节点的IP,映射域名:www.test-http-proxy.com

$ cat /etc/hosts
10.20.1.140 www.test-http-proxy.com

测试Host文件域名映射

10.20.1.140 是 node节点的Ip,部署了 Ingress 控制器。这里通过 Ingress 控制器 将请求转发到 SVC。

4.4 浏览器访问域名

打开浏览器,访问 http://www.test-http-proxy.com, 通过访问 Ingress Controller ,访问到 Nginx Svc

$ kubectl get service -n ingress-nginx
NAME                                 TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             LoadBalancer   10.105.7.64     <pending>     80:32570/TCP,443:31991/TCP   117m
ingress-nginx-controller-admission   ClusterIP      10.102.42.201   <none>        443/TCP                      117m

Ingress-Nginx 实现 Http 代理

至此可以了解到通过使用 Ingress-Nginx 让外部流量能够访问集群内部的服务。

四、Ingress Nginx 使用

ingress的api版本历经过多次变化他们的配置项也不太一样分别是:

  • extensions/v1beta1:1.16版本之前使用
  • networking.k8s.io/v1beta1:1.19版本之前使用
  • networking.k8s.io/v1:1.19版本之后使用

1. Ingress-nginx HTTP 代理

资源清单:ingress-nginx-http-proxy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: my-nginx
          image: nginx:1.29.0
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 80 # 指定容器监听的端口
              protocol: TCP # 指定端口使用的协议,TCP 表示端口处理 TCP 流量,适合 nginx 的 HTTP 服务

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  namespace: default
spec:
  ports:
    - port: 80 # Service 对外暴露的端口号
      targetPort: 80 # Service 将流量转发到的目标 Pod 的端口号
      protocol: TCP
  selector:
    app: nginx # Service 将流量路由到带有标签 app=nginx 的 Pod

---

apiVersion: networking.k8s.io/v1 # 指定 API 版本
kind: Ingress # 指定资源类型为 Ingress,表示这是一个用于管理 HTTP/HTTPS 流量的 Kubernetes 资源
metadata:
  name: ingress-httpproxy
  namespace: default
spec:
  ingressClassName: nginx # 指定此 Ingress 资源由名称为 nginx 的 IngressClass 处理,定义在 values.yaml 中 controller.ingressClassResource.name
  rules: # 定义了流量路由的规则,即如何根据域名(host)和路径(path)将请求转发到后端服务。
    - host: www.test-http-proxy.com # 指定此规则适用于请求的 HTTP 主机头(Host Header)为 www.test-http-proxy.com 的流量。客户端必须通过该域名访问, 如果省略 host,Ingress 会匹配所有域名(即通配规则)。
      http: # 定义了 HTTP 协议的路由规则
        paths: # 用于指定路径匹配规则
          - path: / # 指定匹配的 URL 路径为 /,即根路径,这是最常见的路径,表示匹配所有以 / 开头的请求
            pathType: Prefix # 定义路径匹配的类型为 Prefix,表示匹配以指定路径(/) 开头的所有请求
            backend: # 定义请求的转发目标,即后端服务
              service:
                name: nginx-svc # 指定后端服务的名称为 nginx-svc.(必须存在于同一命名空间,或通过 <namespace>/<service-name> 跨命名空间引用)
                port:
                  number: 80 # 指定目标 Service 的端口为 80

执行资源清单

$ kubectl apply -f ingress-nginx-http-proxy.yaml 
deployment.apps/nginx-deploy created
service/nginx-svc created
ingress.networking.k8s.io/ingress-httpproxy created

查看部署资源

$ kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   59d   <none>
nginx-svc    ClusterIP   10.111.16.251   <none>        80/TCP    8s    app=nginx

$ kubectl get deployment -o wide 
NAME           READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES         SELECTOR
nginx-deploy   2/2     2            2           16s   my-nginx     nginx:1.29.0   app=nginx

$ kubectl get pods -o wide
NAME                            READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
nginx-deploy-6fc4ff86dc-n76xc   1/1     Running   0          22s   172.16.58.249   k8s-node02   <none>           <none>
nginx-deploy-6fc4ff86dc-nlmw5   1/1     Running   0          22s   172.16.85.206   k8s-node01   <none>           <none>

$ kubectl get ingress -o wide
NAME                CLASS   HOSTS                     ADDRESS   PORTS   AGE
ingress-httpproxy   nginx   www.test-http-proxy.com             80      18

修改主机 Host 文件

IP 可以是集群内部署了 Ingress-Controler 的任意一台服务器 IP

10.20.1.140 www.test-http-proxy.com

测试访问 HTTP

$ curl http://www.test-http-proxy.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

2. Ingress-nginx HTTPS 代理

2.1 生成证书和私钥

# 1. 创建证书扩展文件
$ vim http.ext
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = www.https-proxy.com
IP.1 = 127.0.0.1



# 2. 创建证书
# 生成证书步骤1 : 生成 CSR(证书签名请求) 和 私钥文件 tls.key
openssl req -new -newkey rsa:2048 -sha256 -nodes -out tls.csr -keyout tls.key -subj "/C=CN/ST=Beijing/L=Beijing/O=Super Inc./OU=Web Security/CN=www.https-proxy.com"

# 生成证书步骤2 : 生成证书tls.crt,并指定证书扩展文件
openssl x509 -req -days 365 -in tls.csr -signkey tls.key -out tls.crt -extfile http.ext -extensions v3_req

# 查看生成的证书文件
$ ls
http.ext  tls.crt  tls.csr  tls.key



# 3. 将证书和私钥存储到 Secret 
$ kubectl create secret tls ingress-nginx-tls  --key tls.key --cert tls.crt

查看证书 Secret

# 查看 Secret
$ kubectl get secret ingress-nginx-tls -n default
NAME                TYPE                DATA   AGE
ingress-nginx-tls   kubernetes.io/tls   2      22s

# 查看 Secret 详情
$ kubectl describe secret ingress-nginx-tls -n default
Name:         ingress-nginx-tls
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  kubernetes.io/tls

Data
====
tls.crt:  1436 bytes
tls.key:  1708 bytes

# 查看 Secret 数据
$ kubectl get secret ingress-nginx-tls -n default -o yaml
apiVersion: v1
data:
  tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQrRENDQXVDZ0F3SUJBZ0lVWk9iZ3V4cUR5bTlVWk1XUDROMEdnR3pTZkw4d0RRWUpLb1pJaHZjTkFRRUwKQlFBd2V6RUxNQWtHQTFVRUJoTUNRMDR4RURBT0JnTlZCQWdNQjBKbGFXcHBibWN4RURBT0JnTlZCQWNNQjBKbAphV3BwYm1jeEV6QVJCZ05WQkFvTUNsTjFjR1Z5SUVsdVl5NHhGVEFUQmdOVkJBc01ERmRsWWlCVFpXTjFjbWwwCmVURWNNQm9HQTFVRUF3d1RkM2QzTG1oMGRIQnpMWEJ5YjNoNUxtTnZiVEFlRncweU5UQTJNamN3TXpBeE1qWmEKRncweU5qQTJNamN3TXpBeE1qWmFNSHN4Q3pBSkJnTlZCQVlUQWtOT01SQXdEZ1lEVlFRSURBZENaV2xxYVc1bgpNUkF3RGdZRFZRUUhEQWRDWldscWFXNW5NUk13RVFZRFZRUUtEQXBUZFhCbGNpQkpibU11TVJVd0V3WURWUVFMCkRBeFhaV0lnVTJWamRYSnBkSGt4SERBYUJnTlZCQU1NRTNkM2R5NW9kSFJ3Y3kxd2NtOTRlUzVqYjIwd2dnRWkKTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDUVJkTE1TZGpNdHQ2NzVPclVhbmNRNTN5eQpTZitEYVZ2Q2xPdjlGNDRkbG1GSFlrVVZXRW9VQkNIRzdCM1pBb0pRWGFpaEJRbUl5UTNJV0o2ODhsWVpEOU1XClgzU212MGp3Q1A0SVcxaTYyVHBwb0JVRHhlNlI3SHhBQXJXeG9pMzV6Q1lFVVRoZzY3OExhWDRma04xR0pYY3AKaERqZ1FFZ3NqTmVwdGNGRVBLaUxicTNhNVlkRWdpTmpVTnh3dWpKY1RFYllkMXgwUFh5V1lYVDNDV29Fd3JUZQozcU0zWUxTdThjRXdIT21VUW13Rzhvc1p4c2lLeXZjN2MwK3JWWUpqeXR1MFJDRVRjY3Njb2hhSWpqT25xaTN0ClVhd0tKbG9Fa3M5Y2dCb05BSzFodXRDRk9UbzJMY3VZSjA1akhSdy84VXI4RG4rc0w4cGFFSWNqZ2VqOUFnTUIKQUFHamREQnlNQWtHQTFVZEV3UUNNQUF3Q3dZRFZSMFBCQVFEQWdYZ01CTUdBMVVkSlFRTU1Bb0dDQ3NHQVFVRgpCd01CTUNRR0ExVWRFUVFkTUJ1Q0UzZDNkeTVvZEhSd2N5MXdjbTk0ZVM1amIyMkhCSDhBQUFFd0hRWURWUjBPCkJCWUVGTU9jdUNxSTVpL3kwazBtSDVWeFFNaEdhRTA0TUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFBeHZ5LzUKWGE1TjRxc3B4WS9rN0NPSTZoT2VBTitqaGF1SWVMeUkrb1UvczkzVnVLTkRrQ0ErakEyRHRWQmhtQ0xrVUdnbQo1enN5MkJHTndZZW4zV05mTXZZUmQ1ZFhjK3ZzUVNaV2VROWwwZ3FKaTdTeEQwaDJZa3BOUlJVcy84RXRSOUJFCmFKSmNkYTV1dlVwT2VFQ3JrWVhGRnIvK09yZW9Mdi9MV3dtK3VLRytLd204YUU1V3Z6czM0SUlqM1pOMlk1ZVQKVDh3dVhhOVJqbU1mRldaaDA4UHJUd3RXT1R1cW5TQUZ3Z2tpeTBab0RtNFd5amlUNmluZWpzTlpSa2ZCcW5ieQpwQVN0eGlmUWk4S2hRNVUzOEhkUVMzYnpNdnFiS2g3ZlZoamh4Si8wNVBQVHE0NGU3eG56dnlEazFUaC9vWnZ0CjJLdUZuVVkxLzlMayt1U1cKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
  tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2d0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktrd2dnU2xBZ0VBQW9JQkFRQ1FSZExNU2RqTXR0NjcKNU9yVWFuY1E1M3l5U2YrRGFWdkNsT3Y5RjQ0ZGxtRkhZa1VWV0VvVUJDSEc3QjNaQW9KUVhhaWhCUW1JeVEzSQpXSjY4OGxZWkQ5TVdYM1NtdjBqd0NQNElXMWk2MlRwcG9CVUR4ZTZSN0h4QUFyV3hvaTM1ekNZRVVUaGc2NzhMCmFYNGZrTjFHSlhjcGhEamdRRWdzak5lcHRjRkVQS2lMYnEzYTVZZEVnaU5qVU54d3VqSmNURWJZZDF4MFBYeVcKWVhUM0NXb0V3clRlM3FNM1lMU3U4Y0V3SE9tVVFtd0c4b3NaeHNpS3l2YzdjMCtyVllKanl0dTBSQ0VUY2NzYwpvaGFJampPbnFpM3RVYXdLSmxvRWtzOWNnQm9OQUsxaHV0Q0ZPVG8yTGN1WUowNWpIUncvOFVyOERuK3NMOHBhCkVJY2pnZWo5QWdNQkFBRUNnZ0VBQm1OOUpldzRPWS9OMWFxdSs3M2FMTDYweVhnQzVLTm4rNDl1S0NIZ3BSbEUKRUszcFFCSE40cUhiTldIcElYTmR2aExPVlR1eDlDTnVaT1V6RHZhNU9YaTNWaVNKelJvbjJwbnFBVE02L3VLQQpnUmhrWXl0NE9NWFhnUVhOc2hmQkt2QmFGNTRFSGR0RlNyWCt3OXJvU0MzL3RKcmFZajNKSkdYajVVRTdRQnI4CkxZemUvaXp0TVAyeENMSytwL3hJa1JpRVRaVmRubmtaM2FEY3JtcGlmOGRUcGZMbDVYUlRTNWtvbitXMmdybkUKdFd3L3lsWUVzcHo2c1BPRWV0bDNWK3VNYVlsOW9sTEZtQ1M1NUJxQjRid05zSHQyMDdzRmQ2SmdmRFdpZE9yUwpOSWdqRXMxOVphSU9VZitRN254VkQrNGNWaVFJbHhJc21CVGNONjRlOFFLQmdRRERSQmJzdWs3aHQ4MDRwR2wzCnN3M2Q5NndDZHZyOEVtdU41ZDdScEtudG5RdkQvaVJjTS9nNGZlU2czQ1lTbUpCSFNwUDFmZE0wODZBTXBIbzMKcmw2RGtZZ2diUGM4QndHZGp2NDJUdmFYUkQ1T2tnSjlPcDUreHZLMFpmZWJVeERlT3k2SmhNNFFJck5GZVF1dgpCZ0lJSUlSRTJzOTdlak1FclNPQ21CSlNjUUtCZ1FDOUpXOTYwVjIxdkk2L2lBUzZ5eitlSytJaVRxYjh3TUxwCjZjTWR0UEhTdy9URkJ0RVFpSGJvYTUwZER5YVh5TXR4dUpvamNLUXN5ZzdZWlFxQnpheEkwZEIvR0dqRzNlM1oKNjYwQXVXZ0pSN0VOYit3N2pDdjVGa0NWTEg1MEcxbXM2RjlBRXk0ajlOOStuSDlOTEtzbHZmcmNYbFIvY09HeQp6Q29adjdWdFRRS0JnUUNaYkJWckdSUERqQ3dsOWlDY0dVYXJBZC9YNis1V1FvN1paaVRGcWRDT1R4ZWdmajNKCmFGZis0d1BSVkVoaDBoZUN2RmsyeVE4N0NyVFZXaUpoUDVNcFl4NkhBN2JhSmxNaG5lbWxlRE9PTk9PVHptdEEKUTkrbWt1QzkxMlJPV1Z6bWo2K0lBNTM0MVpydjJpVFE5ekovZWpVUytLMlBRanQxMENnWGd5N2FNUUtCZ1FDMQpFdVdLV215djB2ZUZmSjJxaFhFOTV4enhZd0tSN2FlcmIxS1BXZTQzcThqajVnYTNJUzFVaTlFNVJJdlp1eXlvCmplVmlFQy9iZ1FSOVBSMjE3a1FFNG5nTGRENjZRek8wNzk0TFYzTzFqcUI5RUt6Q3hRcER4MzNFVVhndGh4RnUKYW5ibFRIZGJqTTE0MURFNm5JeXI4UmY3WjRMVkRpZkRsNWltVmRWRjhRS0JnUUNnTlB6enkrQUJtVHFLVytXbAoxb0lzUlJlQjdDd1pxUjNUZ0FBaXdKOEpRTFdoREdiQzdJQ0FLVlZkNGZjeUtXVlovRWIrK3RZdUc5ZUpWUkY4CldzU2J1Y0phcktBN1k4UDUydDVtWUp6ZkZjb0hLNXVSVFlOVElFM2w4YmhnSmxqaVJPTER1a2N6cEhVdkJLZkYKYVg4UjNtR3hhZFJ4U25TZUhiN2QvNUFaVlE9PQotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg==
kind: Secret
metadata:
  creationTimestamp: "2025-06-27T03:10:37Z"
  name: ingress-nginx-tls
  namespace: default
  resourceVersion: "13338253"
  uid: fffb5d77-97c4-4237-8be9-a487d96dbf34
type: kubernetes.io/tls

2.2 创建资源清单

资源清单:ingress-nginx-https-proxy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-https
  template:
    metadata:
      labels:
        app: nginx-https
    spec:
      containers:
        - name: my-nginx
          image: nginx:1.29.0
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 80 # 指定容器监听的端口
              protocol: TCP # 指定端口使用的协议,TCP 表示端口处理 TCP 流量,适合 nginx 的 HTTP 服务

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-https-svc
  namespace: default
spec:
  ports:
    - port: 80 # Service 对外暴露的端口号
      targetPort: 80 # Service 将流量转发到的目标 Pod 的端口号
      protocol: TCP
  selector:
    app: nginx-https # Service 将流量路由到带有标签 app=nginx-https 的 Pod

---

apiVersion: networking.k8s.io/v1 # 指定 API 版本
kind: Ingress # 指定资源类型为 Ingress,表示这是一个用于管理 HTTP/HTTPS 流量的 Kubernetes 资源
metadata:
  name: ingress-https-proxy
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true" # HTTP 重定向为HTTPS, true表示强制重定向
spec:
  ingressClassName: nginx # 指定此 Ingress 资源由名称为 nginx 的 IngressClass 处理,定义在 values.yaml 中 controller.ingressClassResource.name
  rules: # 定义了流量路由的规则,即如何根据域名(host)和路径(path)将请求转发到后端服务。
    - host: www.https-proxy.com # 指定此规则适用于请求的 HTTP 主机头(Host Header)为 www.www.https-proxy.com 的流量。客户端必须通过该域名访问, 如果省略 host,Ingress 会匹配所有域名(即通配规则)。
      http: # 定义了 HTTP 协议的路由规则
        paths: # 用于指定路径匹配规则
          - path: / # 指定匹配的 URL 路径为 /,即根路径,这是最常见的路径,表示匹配所有以 / 开头的请求
            pathType: Prefix # 定义路径匹配的类型为 Prefix,表示匹配以指定路径(/) 开头的所有请求
            backend: # 定义请求的转发目标,即后端服务
              service:
                name: nginx-https-svc # 指定后端服务的名称为 nginx-https-svc.(必须存在于同一命名空间,或通过 <namespace>/<service-name> 跨命名空间引用)
                port:
                  number: 80 # 指定目标 Service 的端口为 80
  tls:
    - hosts:
        - www.https-proxy.com # 指定域名
      secretName: ingress-nginx-tls # 证书和私钥保存的 Secret

可以看到Ingress添加TLS配置也非常简单,只需要在 spec下添加一个 tls 字段即可:

  • hosts:证书所授权的域名列表
  • secretName:证书的 Secret 名字
  • ingressClassName: ingress class 的名字,1.22+需要配置

执行资源清单

$ kubectl apply -f ingress-nginx-https-proxy.yaml 
deployment.apps/nginx-deploy created
service/nginx-https-svc created
ingress.networking.k8s.io/ingress-https-proxy created

查看部署资源

$ kubectl get svc -o wide
NAME              TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR
kubernetes        ClusterIP   10.96.0.1       <none>        443/TCP   59d   <none>
nginx-https-svc   ClusterIP   10.99.219.148   <none>        80/TCP    96s   app=nginx-https

$ kubectl get deployment -o wide
NAME           READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES         SELECTOR
nginx-deploy   2/2     2            2           8s    my-nginx     nginx:1.29.0   app=nginx-https

$ kubectl get pods -o wide
NAME                            READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
nginx-deploy-7d6bd7f587-47kqv   1/1     Running   0          21s   172.16.85.213   k8s-node01   <none>           <none>
nginx-deploy-7d6bd7f587-92hhz   1/1     Running   0          21s   172.16.58.233   k8s-node02   <none>           <none>

$ kubectl get ingress -o wide
NAME                  CLASS   HOSTS                 ADDRESS   PORTS     AGE
ingress-https-proxy   nginx   www.https-proxy.com             80, 443   2m57s

修改主机 Host 文件

IP 可以是集群内部署了 Ingress-Controler 的任意一台服务器 IP

10.20.1.140 www.https-proxy.com

测试访问 HTTPS访问
端口号通过命令:kubectl get svc -n ingress-nginx 查看 443 映射端口

# 用命令行测试 https 请求,其中 -k 表示忽略自签名证书警告
$ curl -k https://www.https-proxy.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

浏览器访问HTTPS

需要将自签发的 tls.crt 证书导入到浏览器中,否则会有 “不安全” 的告警提示

如果在ingress中设置tls,即默认的http会被强制重定向到https,http即不可访问,如果需要http与https同时可以使用可以设置

  • nginx.ingress.kubernetes.io/ssl-redirect: “false” :禁用强制重定向,这样可以同时使用http与https

3. Ingress-nginx BasicAuth 代理

有些网站可能需要通过密码来访问,对于这类网站可以使用 Nginx 的 basic-auth 设置密码访 问,具体方法如下,由于需要使用 htpasswd 工具,所以需要安装httpd。

# 安装 htpasswd 工具
$ dnf -y install httpd-tools

# 使用 htpasswd 命令创建一个新的基本认证密码文件 auth,并为用户 george 设置密码。
$ htpasswd -c auth george
New password: 
Re-type new password: 
Adding password for user george

# 创建一个 Kubernetes Secret 资源,类型为 generic,用于存储基本认证的密码文件 auth,以便在 Ingress 或 Nginx 中启用 HTTP 基本认证。
$ kubectl create secret generic ingress-basic-auth --from-file=auth

查看 Secret

$ kubectl get secret ingress-basic-auth -o yaml
apiVersion: v1
data:
  auth: Z2VvcmdlOiRhcHIxJEpoZFB6aVNPJDVXcjhqTDYyQll5Nm5aa3ZHWlB3ejAK
kind: Secret
metadata:
  creationTimestamp: "2025-06-27T06:12:07Z"
  name: ingress-basic-auth
  namespace: default
  resourceVersion: "13361989"
  uid: 9550e4af-4a83-48d7-9b40-fc207303a192
type: Opaque

创建包含密码认证的Ingress

  • nginx.ingress.kubernetes.io/auth-type:认证类型,可以是 basic 和 digest
  • nginx.ingress.kubernetes.io/auth-secret:密码文件的 Secret 名称
  • nginx.ingress.kubernetes.io/auth-realm:需要密码认证的消息提醒

资源清单

ingress-nginx-basic-auth.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: my-nginx
          image: nginx:1.29.0
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 80 # 指定容器监听的端口
              protocol: TCP # 指定端口使用的协议,TCP 表示端口处理 TCP 流量,适合 nginx 的 HTTP 服务

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  namespace: default
spec:
  ports:
    - port: 80 # Service 对外暴露的端口号
      targetPort: 80 # Service 将流量转发到的目标 Pod 的端口号
      protocol: TCP
  selector:
    app: nginx # Service 将流量路由到带有标签 app=nginx 的 Pod

---

apiVersion: networking.k8s.io/v1 # 指定 API 版本
kind: Ingress # 指定资源类型为 Ingress,表示这是一个用于管理 HTTP/HTTPS 流量的 Kubernetes 资源
metadata:
  name: ingress-basic-auth
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/auth-type: basic # 认证类型
    nginx.ingress.kubernetes.io/auth-secret: ingress-basic-auth # 密码文件的 Secret 名称
    nginx.ingress.kubernetes.io/auth-realm: '请输入用户名和密码:' # 需要密码认证的消息提醒
spec:
  ingressClassName: nginx # 指定此 Ingress 资源由名称为 nginx 的 IngressClass 处理,定义在 values.yaml 中 controller.ingressClassResource.name
  rules: # 定义了流量路由的规则,即如何根据域名(host)和路径(path)将请求转发到后端服务。
    - host: auth.basic.com # 指定此规则适用于请求的 HTTP 主机头(Host Header)为 auth.basic.com 的流量。
      http: # 定义了 HTTP 协议的路由规则
        paths: # 用于指定路径匹配规则
          - path: / # 指定匹配的 URL 路径为 /,即根路径,这是最常见的路径,表示匹配所有以 / 开头的请求
            pathType: ImplementationSpecific # 表示路径匹配行为由 Ingress 控制器定义,对于 nginx Ingress 控制器,ImplementationSpecific 通常等同于 Prefix,即匹配以指定路径开头的请求。
            backend: # 定义请求的转发目标,即后端服务
              service:
                name: nginx-svc # 指定后端服务的名称为 nginx-svc.(必须存在于同一命名空间,或通过 <namespace>/<service-name> 跨命名空间引用)
                port:
                  number: 80 # 指定目标 Service 的端口为 80

执行资源清单

$ kubectl apply -f ingress-nginx-basic-auth.yaml

修改主机 Host 文件

IP 可以是集群内部署了 Ingress-Controler 的任意一台服务器 IP

10.20.1.140 auth.basic.com

浏览器访问测试

basic auth 认证测试-登录用户名/密码

basic auth 认证测试-登录成功

4. Ingress-nginx 域名重定向

官方说明https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#permanent-redirect

在 Nginx 作为代理服务器时,Redirect 可用于域名的重定向,比如访问 old.com 被重定向到 new.com。Ingress 可以更简单的实现 Redirect 功能,接下来用 ingress-redirect.com 作为旧域名, www.baidu.com 作为新域名进行演示:

相关配置项

  • permanent-redirect:重定向到的域名
  • permanent-redirect-code:重定向代码,不配置默认301(永久重定向,如有其他原因可自行配置)

资源清单:ingress-nginx-redirect.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: my-nginx
          image: nginx:1.29.0
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 80 # 指定容器监听的端口
              protocol: TCP # 指定端口使用的协议,TCP 表示端口处理 TCP 流量,适合 nginx 的 HTTP 服务

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  namespace: default
spec:
  ports:
    - port: 80 # Service 对外暴露的端口号
      targetPort: 80 # Service 将流量转发到的目标 Pod 的端口号
      protocol: TCP
  selector:
    app: nginx # Service 将流量路由到带有标签 app=nginx-https 的 Pod

---

apiVersion: networking.k8s.io/v1 # 指定 API 版本
kind: Ingress # 指定资源类型为 Ingress,表示这是一个用于管理 HTTP/HTTPS 流量的 Kubernetes 资源
metadata:
  name: ingress-redirect
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx" # 指定使用的Ingress控制器类名,与 ingressClassName 作用相同
    nginx.ingress.kubernetes.io/permanent-redirect: https://www.baidu.com # 永久重定向网址
    nginx.ingress.kubernetes.io/permanent-redirect-code: '301' # 永久重定向状态码
spec:
  ingressClassName: nginx # 指定此 Ingress 资源由名称为 nginx 的 IngressClass 处理,定义在 values.yaml 中 controller.ingressClassResource.name
  rules: # 定义了流量路由的规则,即如何根据域名(host)和路径(path)将请求转发到后端服务。
    - host: ingress-redirect.com # 指定此规则适用于请求的 HTTP 主机头(Host Header)为 ingress-redirect.com 的流量。客户端必须通过该域名访问, 如果省略 host,Ingress 会匹配所有域名(即通配规则)。

执行资源清单

$ kubectl apply -f ingress-nginx-redirect.yaml

修改主机host文件,添加域名映射

IP 可以是集群内部署了 Ingress-Controler 的任意一台服务器 IP

10.20.1.140 ingress-redirect.com

浏览器访问测试

http://ingress-redirect.com

域名重定向

5. Ingress-nginx Rewrite

官方示例:https://kubernetes.github.io/ingress-nginx/examples/rewrite/

相关配置项

  • nginx.ingress.kubernetes.io/rewrite-target: 重定向配置

5.1 案例

资源清单:ingress-nginx-rewrite.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: my-nginx
          image: nginx:1.29.0
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 80 # 指定容器监听的端口
              protocol: TCP # 指定端口使用的协议,TCP 表示端口处理 TCP 流量,适合 nginx 的 HTTP 服务

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  namespace: default
spec:
  ports:
    - port: 80 # Service 对外暴露的端口号
      targetPort: 80 # Service 将流量转发到的目标 Pod 的端口号
      protocol: TCP
  selector:
    app: nginx # Service 将流量路由到带有标签 app=nginx-https 的 Pod

---

apiVersion: networking.k8s.io/v1 # 指定 API 版本
kind: Ingress # 指定资源类型为 Ingress,表示这是一个用于管理 HTTP/HTTPS 流量的 Kubernetes 资源
metadata:
  name: ingress-rewrite
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2 # 对匹配的 URL 路径进行重写。$2 引用正则表达式捕获组
spec:
  ingressClassName: nginx # 指定此 Ingress 资源由名称为 nginx 的 IngressClass 处理,定义在 values.yaml 中 controller.ingressClassResource.name
  rules: # 定义了流量路由的规则,即如何根据域名(host)和路径(path)将请求转发到后端服务。
    - host: ingress-rewrite.com # 定义流量路由规则,基于主机名(host)。这里指定只处理发送到 ingress-rewrite.com 的请求
      http:
        paths:
          - path: /api(/|$)(.*) # 匹配以 /api 开头的路径,后面可以跟 / 或直接结束(|$ 表示路径结束),并捕获剩余部分 (.*) 作为捕获组 $2, 例如:/api、/api/、/api/anything 都会匹配
            pathType: ImplementationSpecific # 路径匹配的具体行为由 Ingress 控制器(NGINX)定义。通常与正则表达式结合使用,允许更灵活的匹配逻辑
            backend:
              service:
                name: nginx-svc
                port:
                  number: 80

执行资源清单

$ kubectl apply -f ingress-nginx-rewrite.yaml

修改主机host文件,添加域名映射

IP 可以是集群内部署了 Ingress-Controler 的任意一台服务器 IP

10.20.1.140 ingress-rewrite.com

访问域名,不加 /api 前缀:404

不加 /api 前缀:404

访问域名,添加 /api 前缀:成功访问到 nginx-svc Service 的默认页面

添加 /api 前缀:成功访问到 nginx-svc Service 的默认页面

访问域名,添加路径 /api/index.html 成功访问到 nginx-svc Service 的 /index.html 页面

访问路径 /api/index.html 成功访问到 nginx-svc Service 的 /index.html 页面

5.1 rewrite 和 redirect

在 Ingress 控制器中,rewrite 和 redirect 是两种不同的操作,它们的作用和行为有所不同:

Rewrite(重写)

  • 作用:重写是指修改请求的路径,但是客户端不会察觉到这个变化,它仅在服务器内部发生。在 Kubernetes 中,可以通过 Ingress 的注解来配置重写规则
  • 示例:比如你有一个服务部署在 /v1 路径下,但是你希望用户访问时不需要输入 /v1,那么你可以使用重写将请求从根路径 / 重写到 /v1

Redirect(重定向)

区别:

  • 影响范围:Rewrite 只在服务器内部修改请求路径,不会影响到客户端,而 Redirect 则会向客户端发送一个新的 URL,让客户端发起新的请求
  • 状态码:Rewrite 不涉及状态码的改变,而 Redirect 会向客户端发送一个重定向的 HTTP 状态码(例如 301 永久重定向、302 临时重定向等)
  • 可见性:Rewrite 对于客户端来说是透明的,而 Redirect 则会告知客户端发生了重定向

在选择使用 Rewrite 还是 Redirect 时,需要根据具体的需求来决定。如果你希望在不修改客户端请求的情况下修改路径,那么使用 Rewrite;如果你希望客户端知道发生了重定向,并且根据新的 URL 进行新的请求,那么使用 Redirect。

6. Ingress-nginx 错误代码重定向

这里的错误代码重定向分为全局设置与某个ingress设置

6.1 默认错误后端(全局)

错误代码重定向功能需要使用 helm 重新部署 ingress-nginx 控制器部署步骤如下:

6.1.1 修改 values.yaml

# 修改 ingress-nginx 目录内 valume.yml 文件
defaultBackend:
  enabled: true # 开启全局错误码重定向
  name: defaultbackend
  image:
    registry: registry.k8s.io
    image: defaultbackend-amd64
    tag: "1.5"
    pullPolicy: IfNotPresent

这里的镜像是 ingress-nginx 的默认镜像,需要提前下载并导入到服务器中

6.1.2 更新 Ingress Nginx

# 更新 Ingress Nginx
$ helm upgrade ingress-nginx . -n ingress-nginx

# 查看 Pod 是否更新,如果是则为刚创建的
$ kubectl get pod -n ingress-nginx
NAME                                           READY   STATUS        RESTARTS   AGE
ingress-nginx-controller-cpbcd                 1/1     Terminating   0          31h
ingress-nginx-controller-szlfb                 1/1     Running       0          25s
ingress-nginx-defaultbackend-f7797494f-t77x4   1/1     Running       0          39s
# 旧的 controller 正在关闭,新创建的在运行中,Ingress Nginx 更新成功

6.1.3 测试资源清单

ingress-nginx-global-errorcode.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: my-nginx
          image: nginx:1.29.0
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 80
              protocol: TCP

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  namespace: default
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
  selector:
    app: nginx

---

apiVersion: networking.k8s.io/v1 # 指定 API 版本
kind: Ingress # 指定资源类型为 Ingress,表示这是一个用于管理 HTTP/HTTPS 流量的 Kubernetes 资源
metadata:
  name: ingress-global-errorcode
  namespace: default
spec:
  ingressClassName: nginx # 指定此 Ingress 资源由名称为 nginx 的 IngressClass 处理,定义在 values.yaml 中 controller.ingressClassResource.name
  rules: # 定义了流量路由的规则,即如何根据域名(host)和路径(path)将请求转发到后端服务。
    - host: global.errorcode.com # 指定此规则适用于请求的 HTTP 主机头(Host Header)为 global.errorcode.com 的流量。
      http: # 定义了 HTTP 协议的路由规则
        paths: # 用于指定路径匹配规则
          - path: / # 指定匹配的 URL 路径为 /,即根路径,这是最常见的路径,表示匹配所有以 / 开头的请求
            pathType: Prefix # 定义路径匹配的类型为 Prefix,表示匹配以指定路径(/) 开头的所有请求
            backend: # 定义请求的转发目标,即后端服务
              service:
                name: nginx-svc # 指定后端服务的名称为 nginx-svc.(必须存在于同一命名空间,或通过 <namespace>/<service-name> 跨命名空间引用)
                port:
                  number: 80 # 指定目标 Service 的端口为 80

执行资源清单

$ kubectl apply -f ingress-nginx-global-errorcode.yaml

修改主机host文件,添加域名映射

IP 可以是集群内部署了 Ingress-Controler 的任意一台服务器 IP

10.20.1.140 global.errorcode.com

当开启 Ingress Nginx 全局错误码重定向时,此时请求不存在的路径,服务端会返回默认的内容

例如请求 http://ingress-rewrite.com/123.html

全局错误码重定向

6.2 单独声明错误后端

设置某个ingress的错误重定向会覆盖全局设置,示例如下

  • nginx.ingress.kubernetes.io/default-backend: 默认后端service名称
  • nginx.ingress.kubernetes.io/custom-http-errors: 那些错误代理重定向到默认后端svc

资源清单

ingress-nginx-single-errorcode.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: error-code-deploy # 用于当请求出现规定的错误码时,返回默认内容
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: error
  template:
    metadata:
      labels:
        app: error
    spec:
      containers:
        - name: error-web
          image: registry.k8s.io/defaultbackend-amd64:1.5
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 80
              protocol: TCP

---

apiVersion: v1
kind: Service
metadata:
  name: error-code-svc # 当请求异常,接收到规定的错误码时,请求会重定向到这个service,用来处理错误请求,返回默认内容
  namespace: default
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
  selector:
    app: error

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: my-nginx
          image: nginx:1.29.0
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 80
              protocol: TCP

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  namespace: default
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
  selector:
    app: nginx

---

apiVersion: networking.k8s.io/v1 # 指定 API 版本
kind: Ingress # 指定资源类型为 Ingress,表示这是一个用于管理 HTTP/HTTPS 流量的 Kubernetes 资源
metadata:
  name: ingress-single-errorcode
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/default-backend: 'error-code-svc' # 指定请求异常时,重定向到哪个SVC处理
    nginx.ingress.kubernetes.io/custom-http-errors: "404,415" # 哪些错误代理重定向到默认后端svc
spec:
  ingressClassName: nginx # 指定此 Ingress 资源由名称为 nginx 的 IngressClass 处理,定义在 values.yaml 中 controller.ingressClassResource.name
  rules: # 定义了流量路由的规则,即如何根据域名(host)和路径(path)将请求转发到后端服务。
    - host: single.errorcode.com # 指定此规则适用于请求的 HTTP 主机头(Host Header)为 single.errorcode.com 的流量。
      http: # 定义了 HTTP 协议的路由规则
        paths: # 用于指定路径匹配规则
          - path: / # 指定匹配的 URL 路径为 /,即根路径,这是最常见的路径,表示匹配所有以 / 开头的请求
            pathType: Prefix # 定义路径匹配的类型为 Prefix,表示匹配以指定路径(/) 开头的所有请求
            backend: # 定义请求的转发目标,即后端服务
              service:
                name: nginx-svc # 指定后端服务的名称为 nginx-svc.(必须存在于同一命名空间,或通过 <namespace>/<service-name> 跨命名空间引用)
                port:
                  number: 80 # 指定目标 Service 的端口为 80

为了体现出单独为 Ingress 声明错误码的处理效果,这里先将 ingress-nginx 的全局错误码处理关闭

# 修改 values.yaml
defaultBackend:
  enabled: false # 关闭全局错误码重定向
  name: defaultbackend
  image:
    registry: registry.k8s.io
    image: defaultbackend-amd64
    tag: "1.5"
    pullPolicy: IfNotPresent
    

# 更新 Ingress Nginx
$ helm upgrade ingress-nginx . -n ingress-nginx

执行资源清单

$ kubectl apply -f ingress-nginx-single-errorcode.yaml

修改主机host文件,添加域名映射

IP 可以是集群内部署了 Ingress-Controler 的任意一台服务器 IP

10.20.1.140 single.errorcode.com

测试:

使用浏览器访问一个不存在的路径,在没有错误码重定向时会返回 404, 如今为 Ingress 单独配置了错误码,会返回配置的 Service 的数据。

http://single.errorcode.com/api/index1.html

自定义错误码返回

7. Ingress-nginx 匹配请求头

使用 ingress-nginx 实现根据不同的请求头,将请求转发到不同的服务。需要先开启 ingress-nginx 的 snippet 功能。

7.1 开启 Snippet

# 编辑 ingress-nginx-controller ConfigMap
$ kubectl edit cm ingress-nginx-controller -n ingress-nginx

# 开启 snippet
apiVersion: v1
data:
  allow-snippet-annotations: "true"

7.2 编辑资源清单

ingress-nginx-match-request-header.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: snippet
  name: snippet-dep
spec:
  replicas: 1
  selector:
    matchLabels:
      app: snippet
  template:
    metadata:
      labels:
        app: snippet
    spec:
      containers:
        - name: snippet-deploy
          image: nginx:1.29.0
          imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: snippet
  name: snippet-svc
spec:
  ports:
    - name: 80-80
      port: 80
      targetPort: 80
      protocol: TCP
  selector:
    app: snippet
  type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: snippet-igs
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/server-snippet: |
      set $agentflag 0;
      if ($http_user_agent ~* "(Android|IPhone)") { # 如果是Android或IPhone访问会重定向到 www.baidu.com 的新网站
        set $agentflag 1;
      }
      if ($agentflag = 1) {
        return 302 http://www.baidu.com;
      }
spec:
  rules:
    - host: snippet.request.com
      http:
        paths:
          - path: /
            pathType: Prefix # 定义路径匹配的类型为 Prefix,表示匹配以指定路径(/) 开头的所有请求
            backend:
              service:
                name: snippet-svc
                port:
                  number: 80

执行资源清单

$ kubectl apply -f ingress-nginx-match-request-header.yaml

编辑Host文件

$ cat /etc/hosts
10.20.1.140 snippet.request.com

10.20.1.140 是 node 节点,部署了 Ingress 控制器

测试访问:默认请求头

$ curl http://snippet.request.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>

成功访问到 Nginx

测试访问:添加请求头

$ curl http://snippet.request.com -H 'User-Agent: Android'  -I
HTTP/1.1 302 Moved Temporarily
Date: Fri, 04 Jul 2025 07:08:56 GMT
Content-Type: text/html
Content-Length: 138
Connection: keep-alive
Location: http://www.baidu.com

请求重定向到了 www.baidu.com

8. Ingress-nginx 配置黑白名单

8.1. 配置方案

Ingress-nginx 配置黑白名单有两种方式:

  • Annotations:只对指定的ingress生效
  • ConfigMap:全局生效

configmap官方配置文档说明:https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/

若是同时配置了 Annotations 和 configmap,一般都是 annotations 生效,configmap 不生效,因为 annotations 优先级比 configmap 高

8.2 黑白名单的区别

  • 白名单是默认是拒绝所有,只允许一个地址去访问
  • 黑名单是不允许该地址去访问所有

黑白名单配置使用 configmap 还是 annotations

  • 黑名单建议使用 ConfigMap 去配置
  • 白名单建议使用 Annotations 去配置

8.3 ConfigMap 添加黑名单

配置黑名单禁止某一个或某一段 IP,需要在 Nginx Ingress 的 ConfigMap 中配置,比如将 10.20.1.141(多个配置逗号分隔)添加至黑名单。

configmap官方配置文档说明:https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/

8.3.1 编辑 Ingress-Nginx ConfigMap

$ kubectl  edit cm ingress-nginx-controller -n ingress-nginx
apiVersion: v1
data:
  allow-snippet-annotations: "true"
  block-cidrs: 10.20.1.141,10.20.1.149

编辑后保存!

8.3.2 测试资源清单

ingress-nginx-black-block.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: test
  name: test-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
        - image: nginx:1.29.0
          name: myapp

---

apiVersion: v1
kind: Service
metadata:
  labels:
    app: test
  name: test-svc
spec:
  ports:
    - name: 80-80
      port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: test
  type: ClusterIP

---

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: global.black.com
spec:
  rules:
    - host: global.black.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: test-svc
                port:
                  number: 80

执行资源清单

$ kubectl apply -f ingress-nginx-global-black.yaml

修改Host文件

# 在 10.20.1.140 服务器添加 Host 配置
echo "10.20.1.140 global.black.com" >> /etc/hosts

# 在 10.20.1.141 服务器添加 Host 配置
echo "10.20.1.141 global.black.com" >> /etc/hosts

访问测试

# 在 10.20.1.140 服务器上测试,可以成功访问 Ingress
$ curl global.block.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

# 在 10.20.1.141 服务器上测试,访问被禁止,全局配置生效
$ curl global.block.com
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>

8.4 Annotations 添加黑名单

资源清单: ingress-nginx-annotations-black.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: black
  name: black-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: black
  template:
    metadata:
      labels:
        app: black
    spec:
      containers:
        - image: nginx:1.29.0
          name: myapp

---

apiVersion: v1
kind: Service
metadata:
  labels:
    app: black
  name: black-svc
spec:
  ports:
    - name: 80-80
      port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: black
  type: ClusterIP

---

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/server-snippet: |
      deny 10.20.1.141;       # 拒绝特定 IP
      deny 192.168.6.0/24;    # 拒绝特定网段
      allow all;              # 允许其他 IP
  name: annotaions.black.com
spec:
  rules:
    - host: annotaions.black.com
      http:
        paths:
          - pathType: Prefix
            backend:
              service:
                name: black-svc
                port:
                  number: 80
            path: /

执行资源清单

$ kubectl apply -f ingress-nginx-annotations-black.yaml

修改Host文件

# 在 10.20.1.140 服务器添加 Host 配置
echo "10.20.1.140 annotaions.black.com" >> /etc/hosts

# 在 10.20.1.141 服务器添加 Host 配置
echo "10.20.1.141 annotaions.black.com" >> /etc/hosts

访问测试

# 在 10.20.1.140 服务器上测试,可以成功访问 Ingress
$ curl annotaions.black.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

# 在 10.20.1.141 服务器上测试,访问被禁止,全局配置生效
$ curl annotaions.black.com
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>

8.5 ConfigMap 设置白名单

白名单表示只允许某个IP可以访问

8.5.1 编辑 Ingress-Nginx ConfigMap

添加 whitelist-source-range 配置

$ kubectl  edit cm ingress-nginx-controller -n ingress-nginx
apiVersion: v1
data:
  allow-snippet-annotations: "true"
  block-cidrs: 10.20.1.141,10.20.1.149
  whitelist-source-range: 10.20.1.139,10.20.1.88

编辑后保存!

8.5.2 测试资源清单

ingress-nginx-global-white.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: test
  name: test-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
        - image: nginx:1.29.0
          name: myapp

---

apiVersion: v1
kind: Service
metadata:
  labels:
    app: test
  name: test-svc
spec:
  ports:
    - name: 80-80
      port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: test
  type: ClusterIP

---

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: global.white.com
spec:
  rules:
    - host: global.white.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: test-svc
                port:
                  number: 80

执行资源清单

$ kubectl apply -f ingress-nginx-global-white.yaml

修改Host文件

# 在 10.20.1.140 服务器添加 Host 配置
echo "10.20.1.140 global.white.com" >> /etc/hosts

# 在 10.20.1.139 服务器添加 Host 配置
echo "10.20.1.140 global.white.com" >> /etc/hosts

访问测试

# 在 10.20.1.139 服务器上测试,可以成功访问 Ingress
$ curl global.white.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

# 在 10.20.1.140 服务器上测试,访问被禁止,全局配置生效
$ curl global.white.com
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>

8.6 Annotations 添加白名单

资源清单: ingress-nginx-annotations-white.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: white
  name: white-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: white
  template:
    metadata:
      labels:
        app: white
    spec:
      containers:
        - image: nginx:1.29.0
          name: myapp

---

apiVersion: v1
kind: Service
metadata:
  labels:
    app: white
  name: white-svc
spec:
  ports:
    - name: 80-80
      port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: white
  type: ClusterIP

---

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/whitelist-source-range: "10.20.1.140"
  name: annotations.white.com
spec:
  rules:
    - host: annotations.white.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: white-svc
                port:
                  number: 80

执行资源清单

$ kubectl apply -f ingress-nginx-annotations-white.yaml

修改Host文件

# 在 10.20.1.140 服务器添加 Host 配置
echo "10.20.1.140 annotations.white.com" >> /etc/hosts

# 在 10.20.1.141 服务器添加 Host 配置
echo "10.20.1.141 annotations.white.com" >> /etc/hosts

访问测试

# 在 10.20.1.140 服务器上测试,可以成功访问 Ingress
$ curl annotations.white.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

# 在 10.20.1.141 服务器上测试,访问被禁止,全局配置生效
$ curl annotations.white.com
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>

9. Ingress-nginx 速率限制

有时候可能需要限制速率以降低后端压力,或者限制单个IP每秒的访问速率防止攻击。此时可以使用 Nginx 的 rate limit 进行配置

9.1 速率限制设置

#限制每秒的连接,单个 IP: 
nginx.ingress.kubernetes.io/limit-rps

#限制每分钟的连接,单个 IP: 
nginx.ingress.kubernetes.io/limit-rpm 

#限制客户端每秒传输的字节数,单位为 K,需要开启 proxy-buffering: 
nginx.ingress.kubernetes.io/limit-rate 

#速率限制白名单 
nginx.ingress.kubernetes.io/limit-whitelist

9.2 测试案例:无速率限制

资源清单 :ingress-nginx-rate-limit-pod.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: speed-deploy
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: speed
  template:
    metadata:
      labels:
        app: speed
    spec:
      containers:
        - name: myapp
          image: nginx:1.29.0
          imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
  namespace: default
  name: speed-svc
spec:
  selector:
    app: speed
  type: ClusterIP
  ports:
    - name: 80-80
      port: 80
      protocol: TCP
      targetPort: 80

执行资源清单

$ kubectl apply -f ingress-nginx-rate-limit-pod.yaml

编辑Host文件

# 在 10.20.1.140 服务器写入
echo "10.20.1.140 rate.limit.com" >> /etc/hosts

# 在 10.20.1.141 服务器写入
echo "10.20.1.141 rate.limit.com" >> /etc/hosts

测试在无Ingress 限制速率的情况下, 发起100次请求

# 安装 ab 工具
$ sudo yum install -y httpd-tools

# 测试发起100个请求,并发数是 10
$ ab -c 10 -n 100 http://rate.limit.com/ | grep requests
Complete requests:      100
Failed requests:        0
Time per request:       0.188 [ms] (mean, across all concurrent requests)
Percentage of the requests served within a certain time (ms)

结论:在没有速率限制的情况下,100个请求全部成功。

9.3 测试案例:使用 Ingress 限制请求速率

资源清单:ingress-nginx-rate-limit-ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: speed-ingress
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/limit-rps: "10"  # 每秒最多 10 个请求
    nginx.ingress.kubernetes.io/limit-whitelist: "10.20.1.140,192.168.6.0/24"  # 这些 IP 范围免于速率限制
spec:
  rules:
    - host: rate.limit.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: speed-svc
                port:
                  number: 80

执行资源清单

$ kubectl apply -f ingress-nginx-rate-limit-ingress.yaml

测试速率限制

# 在 10.20.1.141 服务器上使用 ab 同时发起100个请求
$ ab -c 10 -n 100 http://rate.limit.com/ | grep requests
Complete requests:      100
Failed requests:        49
Time per request:       0.205 [ms] (mean, across all concurrent requests)
Percentage of the requests served within a certain time (ms)
###
由于 Ingress 做了请求速率的限制,发起100个请求,有49个失败了
###


# 在 10.20.1.140 服务器上使用 ab 同时发起100个请求
$ ab -c 10 -n 100 http://rate.limit.com/ | grep requests
Complete requests:      100
Failed requests:        0
Time per request:       0.137 [ms] (mean, across all concurrent requests)
Percentage of the requests served within a certain time (ms)
###
虽然Ingress对请求做了速率限制,由于 10.20.1.140 服务器ip在ingress 速率限制的白名单中,因此请求速率不受限制,100个请求全部成功
###

10. Ingress-nginx 灰度或者金丝雀发布

10.1 概述

灰度发布(也称金丝雀发布,Canary Release)是一种软件部署策略,旨在降低新版本上线带来的风险。它通过将新版本逐步推送给一小部分用户或系统(称为“金丝雀”),观察其表现、稳定性及用户反馈,再决定是否推广到全部用户。以下是详细解释:

核心概念

  1. 逐步推广:新版本不会一次性部署到所有用户,而是先部署到小规模用户群(如1%的用户或特定区域)。
  2. 监控与验证:在灰度发布期间,开发团队会密切监控新版本的性能、错误率、用户体验等指标。
  3. 快速回滚:如果发现问题,可以迅速回滚到旧版本,减少对用户的影响。
  4. 金丝雀的由来:名称源于煤矿工人使用金丝雀鸟来检测矿井中有毒气体。如果鸟儿出现异常,工人会立即撤离。类似地,灰度发布通过小范围测试来“预警”潜在问题。

实施步骤

  1. 选择目标群体:确定一小部分用户或服务器作为“金丝雀”,可以基于地理位置、用户ID、设备类型等条件。
  2. 部署新版本:将新版本部署到选定群体,同时旧版本继续服务其他用户。
  3. 监控表现:使用监控工具(如日志分析、性能指标、用户反馈)评估新版本的稳定性。
  4. 逐步扩展:如果表现良好,逐步增加新版本的覆盖范围(如从1%到10%、50%直至100%)。
  5. 回滚或全量发布:若发现问题,回滚到旧版本;若一切正常,完成全量发布。

10.2 创建 V1 版本的 Ingress

资源清单: ingress-nginx-canary-release-v1.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: default
  name: canary-deploy-v1
  labels:
    app: v1
spec:
  replicas: 10
  selector:
    matchLabels:
      app: v1
  template:
    metadata:
      labels:
        app: v1
    spec:
      containers:
        - name: deploy-v1
          image: wangyanglinux/myapp:v1.0
          imagePullPolicy: IfNotPresent

---

apiVersion: v1
kind: Service
metadata:
  labels:
    app: v1
  name: canary-svc-v1
  namespace: default
spec:
  ports:
    - name: 80-80
      port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: v1
  type: ClusterIP

---

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: default
  name: ingress-v1
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  ingressClassName: "nginx"
  rules:
    - host: canary.release.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: canary-svc-v1
                port:
                  number: 80

执行资源清单

$ kubectl apply -f ingress-nginx-canary-release-v1.yaml

编辑Hosts文件

$ echo "10.20.1.140 canary.release.com" >> /etc/hosts

测试请求

$ curl http://canary.release.com
www.xinxianghf.com | hello MyAPP | version v1.0

10.3 创建 V2 版本的 Ingress

资源清单:ingress-nginx-canary-release-v2.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: default
  name: canary-deploy-v2
  labels:
    app: v2
spec:
  replicas: 10
  selector:
    matchLabels:
      app: v2
  template:
    metadata:
      labels:
        app: v2
    spec:
      containers:
        - name: deploy-v2
          image: wangyanglinux/myapp:v2.0
          imagePullPolicy: IfNotPresent

---

apiVersion: v1
kind: Service
metadata:
  labels:
    app: v2
  name: canary-svc-v2
  namespace: default
spec:
  ports:
    - name: 80-80
      port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: v2
  type: ClusterIP

---

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: default
  name: ingress-v2
  annotations:
    nginx.ingress.kubernetes.io/canary: "true" # 启用金丝雀发布模式
    nginx.ingress.kubernetes.io/canary-weight: "10" # 定义金丝雀服务的流量权重,单位为百分比
spec:
  ingressClassName: "nginx"
  rules:
    - host: canary.release.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: canary-svc-v2
                port:
                  number: 80

执行资源清单

$ kubectl apply -f ingress-nginx-canary-release-v2.yaml

编辑Hosts文件

$ echo "10.20.1.140 canary.release.com" >> /etc/hosts

测试请求

测试请求 100次, 查看请求汇总信息

# 做100次请求
$ for i in {1..100};do curl http://canary.release.com  >> sum;done

# 查看请求汇总信息
$ cat sum | sort | uniq -c
     92 www.xinxianghf.com | hello MyAPP | version v1.0
      8 www.xinxianghf.com | hello MyAPP | version v2.0

结论:请求了100次,其中 92次请求到了 v1.0 版本, 8次请求到 v2.0版本。v2.0 大约占了 10%

11. Ingress-nginx 代理后端 https 协议

如果后端服务是 https 协议,需要使用 nginx.ingress.kubernetes.io/backend-protocols 声明后端服务是 https 。这里代理K8s的web控制台作为示例。代理后访问默认会强制跳转到 https 协议,返回的证书也是服务本身的证书。

资源清单:ingress-nginx-proxy-https-pod.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: proxyhttps
  name: proxyhttps-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: proxyhttps
  template:
    metadata:
      labels:
        app: proxyhttps
    spec:
      containers:
        - image: wangyanglinux/tools:httpsv1
          name: myapp
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: proxyhttps
  name: proxyhttps-svc
spec:
  ports:
    - name: 443-443
      port: 443
      protocol: TCP
      targetPort: 443
  selector:
    app: proxyhttps
  type: ClusterIP

执行资源清单

$ kubectl apply -f ingress-nginx-proxy-https-pod.yaml

访问Service

# 查看 Service 资源
$ kubectl get svc -o wide
NAME             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE     SELECTOR
proxyhttps-svc   ClusterIP   10.103.15.21   <none>        443/TCP   3m25s   app=proxyhttps

# 访问Service
$ curl -k https://10.103.15.21
Hello, HTTPS!

$ curl http://10.103.15.21:443
Client sent an HTTP request to an HTTPS server.

当前Service只能使用 HTTPS 访问

只用 Ingress 代理后端 HTTPS 服务

资源清单:ingress-nginx-proxy-https-ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: HTTPS
  name: ingress.https.com
  namespace: default
spec:
  rules:
    - host: ingress.https.com
      http:
        paths:
          - path: /
            pathType: ImplementationSpecific
            backend:
              service:
                name: proxyhttps-svc
                port:
                  number: 443

执行资源清单

$ kubectl apply -f ingress-nginx-proxy-https-ingress.yaml

编辑Host文件

$ echo "10.20.1.140 ingress.https.com" >> /etc/hosts

请求测试

$ curl http://ingress.https.com
Hello, HTTPS!

结论:使用 Ingress 代理了后端HTTPS请求

12. Ingress-nginx 四层代理

在新版本的nginx也引入了四层代理的概念,可直接代理TCP与UDP协议,在ingress-nginx也可以通过四层代理实现service的代理,实现方式如下:

官方文档:https://kubernetes.github.io/ingress-nginx/user-guide/exposing-tcp-udp-services/

首先在使用 helm 部署 ingress-nginx 之后,需修改 nginx 启动资源的启动参数添加--tcp-services-configmap--udp-services-configmap 的配置启用四层代理,通过修改配置 configmap 资源进行四层代理的配置。

12.1TCP代理

修改 ingress-nginx 控制器

在 ingress-nginx-controller 中添加 --tcp-services-configmap 启动参数

$ kubectl  edit ds -n ingress-nginx ingress-nginx-controller

    spec:
      containers:
      - args:
        - /nginx-ingress-controller
        - --tcp-services-configmap=$(POD_NAMESPACE)/nginx-ingress-tcp-configmap
        
#参数说明如下
--tcp-services-configmap=$(POD_NAMESPACE)/  这里为固定,表示tcp配置选择ingress-nginx安装的命名空间的configmap资源
nginx-ingress-tcp-configmap  为configmap资源的名称

编辑 ConfigMap

nginx-ingress-tcp-configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-ingress-tcp-configmap
  namespace: ingress-nginx # ingress-nginx 所在的命名空间
data:
  "9000": "default/proxyhttps-svc:443"
$ kubectl apply -f nginx-ingress-tcp-configmap.yaml

Pod资源清单

ingress-nginx-tcp-proxy-pod.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: proxyhttps
  name: proxyhttps-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: proxyhttps
  template:
    metadata:
      labels:
        app: proxyhttps
    spec:
      containers:
        - image: wangyanglinux/tools:httpsv1
          name: myapp
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: proxyhttps
  name: proxyhttps-svc
spec:
  ports:
    - name: 443-443
      port: 443
      protocol: TCP
      targetPort: 443
  selector:
    app: proxyhttps
  type: ClusterIP

执行资源清单

$ kubectl apply -f ingress-nginx-tcp-proxy-pod.yaml

测试四层代理访问

$ kubectl get svc -o wide
NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE    SELECTOR
proxyhttps-svc   ClusterIP   10.96.172.123   <none>        443/TCP   63s    app=proxyhttps

# 首先直接访问 SVC,确认服务可用
$ curl -k https://10.96.172.123:443
Hello, HTTPS!

# 测试通过ingress 4层代理访问
$ curl -k https://10.20.1.140:9000
Hello, HTTPS!

12.2 UDP代理

修改 ingress-nginx 控制器

在 ingress-nginx-controller 中添加 --tcp-services-configmap 启动参数

$ kubectl  edit ds -n ingress-nginx ingress-nginx-controller

    spec:
      containers:
      - args:
        - /nginx-ingress-controller
        - --udp-services-configmap=$(POD_NAMESPACE)/nginx-ingress-udp-configmap
        
#参数说明如下
--tcp-services-configmap=$(POD_NAMESPACE)/  这里为固定,表示tcp配置选择ingress-nginx安装的命名空间的configmap资源
nginx-ingress-tcp-configmap  为configmap资源的名称

编辑 ConfigMap

nginx-ingress-udp-configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-ingress-udp-configmap
  namespace: ingress
data:
  "53": "kube-system/kube-dns:53"

13. Ingress-nginx 链路追踪

官方文档:https://kubernetes.github.io/ingress-nginx/user-guide/third-party-addons/opentracing/#jaeger

官方推荐的链路追踪插件为 Zipkin 或者 Jaeger。这里我们选用 Jaeger。

官方部署示例文件: https://raw.githubusercontent.com/jaegertracing/jaeger-kubernetes/master/all-in-one/jaeger-all-in-one-template.yml

13.1 部署 Jaeger

# 下载部署资源清单
wget https://raw.githubusercontent.com/jaegertracing/jaeger-kubernetes/master/all-in-one/jaeger-all-in-one-template.yml

修改 jaeger 资源清单

apiVersion: v1
kind: List
items:
- apiVersion: apps/v1 # 将版本修改为 apps/v1
  kind: Deployment
  metadata:
    name: jaeger
    labels:
      app: jaeger
      app.kubernetes.io/name: jaeger
      app.kubernetes.io/component: all-in-one
  spec:
    replicas: 1
    selector: # 添加选择器, apps/v1版本需要
      matchLabels:
        app: jaeger
    strategy:
      type: Recreate
    template:
      metadata:
        labels:
          app: jaeger
          app.kubernetes.io/name: jaeger
          app.kubernetes.io/component: all-in-one
        annotations:
          prometheus.io/scrape: "true"
          prometheus.io/port: "16686"
      spec:
          containers:
          -   env:
              - name: COLLECTOR_ZIPKIN_HTTP_PORT
                value: "9411"
              image: jaegertracing/all-in-one
              imagePullPolicy: IfNotPresent # 修改镜像下载策略,提前将镜像下载好
              name: jaeger
              ports:
                - containerPort: 5775
                  protocol: UDP
                - containerPort: 6831
                  protocol: UDP
                - containerPort: 6832
                  protocol: UDP
                - containerPort: 5778
                  protocol: TCP
                - containerPort: 16686
                  protocol: TCP
                - containerPort: 9411
                  protocol: TCP
              readinessProbe:
                httpGet:
                  path: "/"
                  port: 14269
                initialDelaySeconds: 5
- apiVersion: v1
  kind: Service
  metadata:
    name: jaeger-query
    labels:
      app: jaeger
      app.kubernetes.io/name: jaeger
      app.kubernetes.io/component: query
  spec:
    ports:
      - name: query-http
        port: 80
        protocol: TCP
        targetPort: 16686
    selector:
      app.kubernetes.io/name: jaeger
      app.kubernetes.io/component: all-in-one
    type: LoadBalancer
- apiVersion: v1
  kind: Service
  metadata:
    name: jaeger-collector
    labels:
      app: jaeger
      app.kubernetes.io/name: jaeger
      app.kubernetes.io/component: collector
  spec:
    ports:
    - name: jaeger-collector-tchannel
      port: 14267
      protocol: TCP
      targetPort: 14267
    - name: jaeger-collector-http
      port: 14268
      protocol: TCP
      targetPort: 14268
    - name: jaeger-collector-zipkin
      port: 9411
      protocol: TCP
      targetPort: 9411
    selector:
      app.kubernetes.io/name: jaeger
      app.kubernetes.io/component: all-in-one
    type: ClusterIP
- apiVersion: v1
  kind: Service
  metadata:
    name: jaeger-agent
    labels:
      app: jaeger
      app.kubernetes.io/name: jaeger
      app.kubernetes.io/component: agent
  spec:
    ports:
    - name: agent-zipkin-thrift
      port: 5775
      protocol: UDP
      targetPort: 5775
    - name: agent-compact
      port: 6831
      protocol: UDP
      targetPort: 6831
    - name: agent-binary
      port: 6832
      protocol: UDP
      targetPort: 6832
    - name: agent-configs
      port: 5778
      protocol: TCP
      targetPort: 5778
    clusterIP: None
    selector:
      app.kubernetes.io/name: jaeger
      app.kubernetes.io/component: all-in-one
- apiVersion: v1
  kind: Service
  metadata:
    name: zipkin
    labels:
      app: jaeger
      app.kubernetes.io/name: jaeger
      app.kubernetes.io/component: zipkin
  spec:
    ports:
    - name: jaeger-collector-zipkin
      port: 9411
      protocol: TCP
      targetPort: 9411
    clusterIP: None
    selector:
      app.kubernetes.io/name: jaeger
      app.kubernetes.io/component: all-in-one

可以将所有的 SVC、Deployment 都放到单独的命名空间中,这样就不会被误删除

执行 Jaeger 资源清单

$ kubectl apply -f jaeger-all-in-one-template.yml 

# 查看 SVC, !!! 注意:浏览器访问 jaeger 是通过 jaeger-query, 这里的 31272 就是对外暴露的端口
$ kubectl get svc
NAME               TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                               AGE
jaeger-agent       ClusterIP      None            <none>        5775/UDP,6831/UDP,6832/UDP,5778/TCP   12m
jaeger-collector   ClusterIP      10.99.111.240   <none>        14267/TCP,14268/TCP,9411/TCP          12m
jaeger-query       LoadBalancer   10.100.53.251   <pending>     80:31272/TCP                          12m
kubernetes         ClusterIP      10.96.0.1       <none>        443/TCP                               4d5h
zipkin             ClusterIP      None            <none>        9411/TCP                              12m

# 查看 Deployment
$ kubectl get deploy
NAME     READY   UP-TO-DATE   AVAILABLE   AGE
jaeger   1/1     1            1           20s

# 查看 Pod
$ kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
jaeger-cbfbf99b4-cxgq6   1/1     Running   0          22s

到此 Jaeger 就部署好了

注意:浏览器访问 jaeger 是通过 jaeger-query, 这里的 31272 就是对外暴露的端口,可以通过:http://物理机ip:31035 访问 Jaeger

13.2 ingress 设置

需要修改 ingress 的 configmap 文件,添加相应参数,开启 Ingress 链路追踪

$ kubectl edit cm -n ingress-nginx ingress-nginx-controller

apiVersion: v1
data:
  allow-snippet-annotations: "true"
  enable-opentracing: "true"   #开启链路追踪
  jaeger-collector-host: jaeger-agent.default.svc.cluster.local  #链路追踪的svc名称

重建 Ingress-Nginx Pod

# 查看Pod
$ kubectl get pods -n ingress-nginx
NAME                             READY   STATUS    RESTARTS   AGE
ingress-nginx-controller-25wk6   1/1     Running   0          150m
ingress-nginx-controller-qcbp2   1/1     Running   0          151m

# 删除Pod,等待重建
$ kubectl delete pod ingress-nginx-controller-25wk6 ingress-nginx-controller-qcbp2 -n ingress-nginx

浏览器访问Jaeger

http://10.20.1.139:31272/

浏览器访问Jaeger

查看请求

参考链接

https://zhangzhuo.ltd/articles/2022/03/20/1647773666928.html

https://www.cnblogs.com/tencent-cloud-native/p/13865502.html

https://k8s.whuanle.cn/4.network/3.ingress.html

https://www.cnblogs.com/linyb-geek/p/18153533


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 george_95@126.com