011-Kubernetes Ingress-Nginx

一、负载均衡器

负载均衡器有两类,区别在于 四层网络七层网络 的支持,传输层在第四层,这层协议有 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

修改主机 host 文件

测试Host文件域名映射

4.4 浏览器访问域名

打开浏览器,访问 http://www.test-http-proxy.com:32570/ ,其中 32570 端口是在创建 ingress-nginx 时自动分配的物理端口,可以通过命令查看:

$ 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

192.168.6.139 www.test-http-proxy.com

测试访问 HTTP

$ curl http://www.test-http-proxy.com:32570
<!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

192.168.6.139 www.https-proxy.com

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

# 用命令行测试 https 请求,其中 -k 表示忽略自签名证书警告
$ curl -k https://www.https-proxy.com:31991/
<!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

192.168.6.139 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

192.168.6.139 ingress-redirect.com

浏览器访问测试

http://ingress-redirect.com:32570/

域名重定向

5. Ingress-nginx Rewrite

5.1 案例

5.1 rewrite 和 redirect

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

7. Ingress-nginx 匹配请求头

8. Ingress-nginx 配置黑白名单

9. Ingress-nginx 速率限制

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

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

12. Ingress-nginx 四层代理

13. Ingress-nginx 链路追踪

参考链接

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