Langchain系列文章目录

01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
08-【万字长文】MCP深度解析:打通AI与世界的“USB-C”,模型上下文协议原理、实践与未来

Python系列文章目录

PyTorch系列文章目录

机器学习系列文章目录

深度学习系列文章目录

Java系列文章目录

JavaScript系列文章目录

Python系列文章目录

Go语言系列文章目录

Docker系列文章目录

01-【Docker-Day 1】告别部署噩梦:为什么说 Docker 是每个开发者的必备技能?
02-【Docker-Day 2】从零开始:手把手教你在 Windows、macOS 和 Linux 上安装 Docker
03-【Docker-Day 3】深入浅出:彻底搞懂 Docker 的三大核心基石——镜像、容器与仓库
04-【Docker-Day 4】从创建到删除:一文精通 Docker 容器核心操作命令
05-【Docker-Day 5】玩转 Docker 镜像:search, pull, tag, rmi 四大金刚命令详解
06-【Docker-Day 6】从零到一:精通 Dockerfile 核心指令 (FROM, WORKDIR, COPY, RUN)
07-【Docker-Day 7】揭秘 Dockerfile 启动指令:CMD、ENTRYPOINT、ENV、ARG 与 EXPOSE 详解
08-【Docker-Day 8】高手进阶:构建更小、更快、更安全的 Docker 镜像
09-【Docker-Day 9】实战终极指南:手把手教你将 Node.js 应用容器化
10-【Docker-Day 10】容器的“持久化”记忆:深入解析 Docker 数据卷 (Volume)
11-【Docker-Day 11】Docker 绑定挂载 (Bind Mount) 实战:本地代码如何与容器实时同步?
12-【Docker-Day 12】揭秘容器网络:深入理解 Docker Bridge 模式与端口映射
13-【Docker-Day 13】超越默认Bridge:精通Docker Host、None与自定义网络模式
14-【Docker-Day 14】Docker Compose深度解析
15-【Docker-Day 15】一键部署 WordPress!Docker Compose 实战终极指南
16-【Docker-Day 16】告别单机时代:为什么 Docker Compose 不够用,而你需要 Kubernetes?
17-【Docker-Day 17】K8s 架构全解析:深入理解 Kubernetes 的大脑 (Master) 与四肢 (Node)
18-【Docker-Day 18】告别选择困难症:一文掌握 Minikube、kind、k3d,轻松搭建你的第一个 K8s 集群
19-【Docker-Day 19】万物皆 YAML:掌握 Kubernetes 声明式 API 的艺术
20-【Docker-Day 20】揭秘 Kubernetes 的原子单位:深入理解 Pod
21-【Docker-Day 21】Pod的守护神:ReplicaSet与ReplicationController,轻松实现应用高可用
22-【K8s-Day 22】深入解析 Kubernetes Deployment:现代应用部署的基石与滚动更新的艺术
23-【K8s-Day 23】从 Pod 的“失联”到 Service 的“牵线”:深入理解 ClusterIP 核心原理
24-【Docker-Day 24】K8s网络解密:深入NodePort与LoadBalancer,让你的应用走出集群
25-【Docker-Day 25】深入理解 Kubernetes Namespace:实现多租户与环境隔离的利器
26-【Docker-Day 26】K8s实战演练:从零开始部署一个完整的前后端分离Web应用
27-【K8s-Day 27】应用的“体检医生”:深入解析 Kubernetes 健康检查探针 (Probe)
28-【Docker-Day 28】K8s 核心配置管理:解密 ConfigMap,告别硬编码!
29-【Docker-Day 29】K8s 安全第一课:揭秘敏感信息管理器 Secret
30-【Docker-Day 30】解密 K8s 的“硬盘”:深入理解 PersistentVolume (PV) 与 PersistentVolumeClaim (PVC)
31-【Docker-Day 31】告别手动创建 PV!一文搞懂 Kubernetes StorageClass 工作原理与实战
32-【K8s-Day 32】StatefulSet 深度解析:为你的数据库和有状态应用保驾护航
33-【Docker-Day 33】掌握 K8s 任务调度:DaemonSet、Job、CronJob 实战指南
34-【Docker-Day 34】Kubernetes Ingress 详解:从小白到精通的 K8s 流量路由指南
35-【Docker-Day 35】实战部署 Nginx Ingress Controller:集群流量入口的终极指南


文章目录


摘要

在上一篇文章中,我们理论学习了 Kubernetes Ingress 的概念,它作为集群流量的七层路由规则,为服务暴露提供了灵活的解决方案。然而,仅有规则是不够的,还需要一个执行者——Ingress Controller。本文将聚焦于社区最流行、功能最强大的 Nginx Ingress Controller,通过详尽的步骤和实战案例,手把手带你完成从部署、配置到实现 HTTPS 加密的完整流程,让你彻底掌握这个 Kubernetes 集群的“守门神”。

一、前情回顾:为什么需要 Ingress Controller?

在深入实践之前,让我们快速回顾一下 Ingress 与 Ingress Controller 之间的关系,这对于理解后续操作至关重要。

1.1 Ingress 资源:一套“交通规则”

在 Kubernetes 中,Ingress 资源本身不具备任何网络功能。它更像是一份声明式的配置文件,一份详细的“交通规则说明书”。这份说明书定义了外部 HTTP/HTTPS 流量应该如何被路由到集群内部的 Service

例如,你可以定义如下规则:

  • 访问 http://a.example.com 的流量,请转发到 service-a
  • 访问 http://b.example.com 的流量,请转发到 service-b
  • 访问 http://example.com/api 的流量,请转发到 api-service

这些规则以 YAML 格式存储在 etcd 中,等待被“人”读取和执行。

1.2 Ingress Controller:执行规则的“交通警察”

Ingress Controller 就是读取并执行这些 Ingress 规则的“交通警察”。它是一个运行在集群中的 Pod,通常是一个反向代理服务器(如 Nginx、HAProxy 等),其核心职责是:

  1. 监听(Watch):通过与 Kubernetes API Server 通信,持续监听集群中 IngressServiceEndpoint 等资源的变化。
  2. 动态配置:当检测到 Ingress 规则发生变化时,Ingress Controller 会根据新的规则动态地更新其内部的反向代理配置(例如,生成新的 nginx.conf 文件并重新加载)。
  3. 流量转发:它作为一个暴露在集群边缘的入口点(通常通过 NodePortLoadBalancer 类型的 Service),接收所有外部流量,并根据内存中的路由规则,将流量精确地转发到后端对应的 Service

下图清晰地展示了这一流程:

graph TD
    subgraph Internet
        User[用户]
    end

    subgraph Kubernetes Cluster
        subgraph "Node"
            ControllerService[Ingress Controller Service <br/> (Type: LoadBalancer/NodePort)]
        end

        subgraph "ingress-nginx Namespace"
            ControllerPod[Ingress Controller Pod <br/> (Nginx)]
        end

        subgraph "app-a Namespace"
            ServiceA[Service A] --> PodA1[Pod A-1]
            ServiceA --> PodA2[Pod A-2]
        end

        subgraph "app-b Namespace"
            ServiceB[Service B] --> PodB1[Pod B-1]
        end

        APIServer((API Server)) -- watches --> ControllerPod
        ControllerPod -- reads --> IngressRule(Ingress Resource <br/> a.com -> Service A <br/> b.com -> Service B)
        APIServer -- stores --> IngressRule
    end

    User -- "a.com" --> ControllerService
    ControllerService -- "a.com traffic" --> ControllerPod
    ControllerPod -- forwards to --> ServiceA

    User -- "b.com" --> ControllerService
    ControllerService -- "b.com traffic" --> ControllerPod
    ControllerPod -- forwards to --> ServiceB

    style ControllerPod fill:#f9f,stroke:#333,stroke-width:2px
    style IngressRule fill:#ccf,stroke:#333,stroke-width:2px

1.3 为什么选择 Nginx Ingress Controller?

Kubernetes 社区支持多种 Ingress Controller 实现,但 Nginx Ingress Controller 无疑是应用最广泛、社区最活跃、功能最丰富的选择之一。它由 Kubernetes 官方维护,基于性能卓越的 Nginx 服务器,提供了稳定可靠的流量管理能力,是大多数场景下的首选。

二、部署 Nginx Ingress Controller

部署 Nginx Ingress Controller 主要有两种主流方式:使用官方 YAML 清单或使用 Helm 包管理器。

2.1 部署方式选择

(1) 官方 YAML 清单部署 (本文重点)

这是最基础、最透明的方式。通过直接应用官方提供的 YAML 文件,你可以清晰地看到部署过程创建了哪些 Kubernetes 资源,有助于深入理解其工作原理。

(2) Helm 包管理器部署

Helm 像是 Kubernetes 的 aptyum,它将应用所需的所有资源打包成一个 Chart。使用 Helm 部署可以简化配置和版本管理,更适合生产环境的自动化部署。我们将在后续章节中详细介绍 Helm。

2.2 使用官方 YAML 进行部署

我们将采用官方 YAML 清单的方式进行部署,以便更好地理解其内部构造。

(1) 获取部署清单文件

Nginx Ingress Controller 的官方部署文件托管在 GitHub 上。你可以直接从其代码仓库中找到适用于你所在云环境或裸金属环境的部署文件。
通用部署文件的地址通常是固定的:

https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.1/deploy/static/provider/cloud/deploy.yaml

注意:请将 v1.10.1 替换为你需要部署的最新稳定版本号。你可以在 Ingress-Nginx Releases 页面查看所有可用版本。

(2) 执行部署命令

我们使用 kubectl apply 命令,直接从 URL 应用这个 YAML 文件,Kubernetes 会自动下载并创建其中定义的所有资源。

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.1/deploy/static/provider/cloud/deploy.yaml

执行后,你会看到一系列资源被创建的提示。

(3) 验证部署状态

部署命令执行后,所有相关的资源都会被创建在一个名为 ingress-nginx 的 Namespace 中。

  1. 检查 Pod 状态

    # 查看 ingress-nginx 命名空间下的所有 Pod
    kubectl get pods -n ingress-nginx
    

    你应该能看到一个名为 ingress-nginx-controller-xxxxxxxx-xxxxx 的 Pod 处于 Running 状态。

  2. 检查 Service 状态

    # 查看 ingress-nginx 命名空间下的所有 Service
    kubectl get svc -n ingress-nginx
    

    你会看到一个名为 ingress-nginx-controller 的 Service。如果你的集群在公有云上,它的 TYPE 应该是 LoadBalancer,并且在 EXTERNAL-IP 列会分配一个公网 IP。如果是在本地环境(如 Minikube)或裸金属集群,TYPE 可能是 NodePort

2.3 剖析核心部署资源

deploy.yaml 文件看似复杂,但其核心是创建了以下几类关键资源来保证 Controller 的正常运行:

(1) Namespace 与 RBAC
  • Namespace (ingress-nginx): 为 Ingress Controller 创建一个独立的命名空间,使其与其他应用隔离开,便于管理。
  • RBAC (ServiceAccount, ClusterRole, ClusterRoleBinding): 这是为了授权。Ingress Controller 需要权限去读取(get, list, watch)集群范围内的 IngressServiceEndpoint 等资源,以便动态生成路由配置。ClusterRole 定义了需要哪些权限,ClusterRoleBinding 则将这些权限授予了 ingress-nginxServiceAccount
(2) Deployment:Controller 核心

这是整个 Ingress Controller 的核心,它定义了如何运行 Controller 的 Pod。

  • 镜像: 使用官方的 ingress-nginx/controller 镜像。
  • 参数: 启动容器时传入了 --publish-service--ingress-class 等关键参数。
  • 端口: 暴露了 80(HTTP)、443(HTTPS)和 8443(Webhook)等端口。
(3) Service:暴露 Controller

这个 Service 的作用是将 Ingress Controller 的 Pod 暴露给外部流量。

  • Type: LoadBalancer (云环境): 在公有云上,这会自动创建一个云厂商的负载均衡器,并将外部流量导向 Controller Pod 的 80 和 443 端口。这是最常用的生产环境暴露方式。
  • Type: NodePort (本地/裸金属): 如果没有云厂商的负载均衡器,Service 会在集群的每个 Node 上暴露一个相同的端口,外部流量可以通过 http://<NodeIP>:<NodePort> 访问到 Controller。

三、实战:配置 Ingress 规则路由流量

现在 Ingress Controller 已经就位,让我们创建一些后端应用,并用 Ingress 规则将它们暴露出去。

3.1 准备后端应用

我们将创建两个简单的 Web 应用(webapp-awebapp-b),它们分别返回自己的身份信息。

(1) 创建示例应用 Deployment

创建一个名为 app-deploy.yaml 的文件:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp-a-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: webapp-a
  template:
    metadata:
      labels:
        app: webapp-a
    spec:
      containers:
      - name: webapp-a
        image: nginxdemos/hello:plain-text # 一个简单的返回纯文本的 Nginx 镜像
        ports:
        - containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp-b-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: webapp-b
  template:
    metadata:
      labels:
        app: webapp-b
    spec:
      containers:
      - name: webapp-b
        image: httpd:2.4 # 使用 Apache httpd 镜像作为区分
        ports:
        - containerPort: 80
(2) 创建示例应用 Service

继续在 app-deploy.yaml 中添加 Service 定义:

---
apiVersion: v1
kind: Service
metadata:
  name: service-a
spec:
  selector:
    app: webapp-a
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: service-b
spec:
  selector:
    app: webapp-b
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

应用这个文件:

kubectl apply -f app-deploy.yaml

3.2 配置 Ingress 规则

接下来,我们将创建 Ingress 规则来定义路由。

(1) 场景一:基于域名的路由

创建一个 ingress-host-based.yaml 文件,将 a.example.com 指向 service-ab.example.com 指向 service-b

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: host-based-ingress
  annotations:
    # 指定使用哪个 Ingress Controller,这里的 'nginx' 对应 Controller 的 ingress-class
    kubernetes.io/ingress.class: "nginx" 
spec:
  rules:
  - host: "a.example.com"
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: service-a
            port:
              number: 80
  - host: "b.example.com"
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: service-b
            port:
              number: 80

应用该规则:

kubectl apply -f ingress-host-based.yaml
(2) 场景二:基于路径的路由

你也可以在同一个域名下,根据不同的 URL 路径路由到不同服务。例如,创建一个 ingress-path-based.yaml 文件:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: path-based-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    # 对于路径重写,Nginx Ingress 需要这个 annotation
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: "example.com"
    http:
      paths:
      - path: /app-a
        pathType: Prefix
        backend:
          service:
            name: service-a
            port:
              number: 80
      - path: /app-b
        pathType: Prefix
        backend:
          service:
            name: service-b
            port:
              number: 80

注意: nginx.ingress.kubernetes.io/rewrite-target: / 这个注解非常重要。它告诉 Nginx Ingress Controller,在将请求转发到后端 Pod 之前,将 URL 中的 /app-a/app-b 部分去掉。否则,后端应用收到的请求路径将是 /app-a,如果应用本身不处理这个子路径,就会导致 404。

3.3 测试 Ingress 路由

(1) 获取 Ingress 入口 IP

首先,获取 Ingress Controller Service 的外部 IP 地址。

kubectl get svc -n ingress-nginx ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
# 如果上面命令无输出(例如使用NodePort),可以获取任一节点的IP
# export INGRESS_IP=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}')
# export INGRESS_PORT=$(kubectl get svc -n ingress-nginx -o jsonpath='{.spec.ports[?(@.name=="http")].nodePort}')

假设我们获取到的 EXTERNAL-IP203.0.113.10

(2) 配置本地 DNS 解析 (hosts 文件)

为了让你的电脑能解析 a.example.comb.example.com,需要修改本地的 hosts 文件。

  • Linux/macOS: /etc/hosts
  • Windows: C:\Windows\System32\drivers\etc\hosts

在文件中添加以下行:

203.0.113.10 a.example.com
203.0.113.10 b.example.com
(3) 使用 curl 命令验证

现在,打开终端,使用 curl 进行测试:

# 测试 a.example.com
curl http://a.example.com
# 你应该会看到来自 webapp-a Pod 的响应,内容类似:
# Server address: 10.244.1.5:80
# Server name: webapp-a-deployment-xxxx-xxxx
# ...

# 测试 b.example.com
curl http://b.example.com
# 你应该会看到来自 webapp-b Pod 的响应,内容是 "It works!"

测试成功!这表明 Ingress Controller 已经根据我们定义的规则,正确地将流量分发到了不同的后端服务。

四、进阶:为 Ingress 配置 TLS/SSL (HTTPS)

在生产环境中,为网站启用 HTTPS 是必不可少的。Ingress 让这个过程变得非常简单。

4.1 生成自签名证书

对于演示,我们使用 openssl 生成一个自签名的证书。在生产环境中,你应该使用由受信任的证书颁发机构(CA)签发的证书,或者使用 Let’s Encrypt 自动签发。

# 生成私钥和证书签名请求(CSR)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout tls.key \
  -out tls.crt \
  -subj "/CN=a.example.com/O=my-org"

这个命令会生成两个文件:tls.key (私钥) 和 tls.crt (证书)。

4.2 创建 TLS Secret

Kubernetes 使用一种特殊的 Secret 类型 kubernetes.io/tls 来存储 TLS 证书和私钥。

kubectl create secret tls my-tls-secret \
  --key tls.key \
  --cert tls.crt

这会创建一个名为 my-tls-secret 的 Secret,其中包含了我们的证书和私钥。

4.3 更新 Ingress 资源以启用 TLS

现在,修改之前的 ingress-host-based.yaml 文件,为其添加 tls 配置段。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: host-based-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  tls: # <-- 新增 TLS 配置
  - hosts:
    - a.example.com
    secretName: my-tls-secret # <-- 引用我们刚刚创建的 Secret
  rules:
  - host: "a.example.com"
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: service-a
            port:
              number: 80
  # ... b.example.com 的规则保持不变 ...

应用更新后的配置:

kubectl apply -f ingress-host-based.yaml

Ingress Controller 会自动检测到这个变化,并开始在 443 端口上为 a.example.com 提供 TLS 服务。

4.4 验证 HTTPS 访问

使用 curl 来测试 HTTPS 连接。由于我们用的是自签名证书,需要加上 -k (或 --insecure) 选项来跳过证书验证。

curl -k https://a.example.com
# 响应应与之前 HTTP 访问相同,但这次是通过加密连接获取的

curl --head -k https://a.example.com
# 查看响应头,你会看到 HTTP/2 或 HTTP/1.1 200 OK,以及 Nginx 返回的头信息

五、常见问题与排查思路 (FAQ)

5.1 Ingress Controller Pod 状态异常

如果 ingress-nginx-controller Pod 没有处于 Running 状态(如 CrashLoopBackOff),首先使用 kubectl logskubectl describe pod 查看日志和事件,通常能定位到配置错误或权限问题。

5.2 访问域名返回 404 Not Found

这通常是 Nginx Ingress Controller 自身的 404 页面,意味着流量已到达 Controller,但 Controller 没能找到匹配的路由规则。

  • 检查 Ingress 规则kubectl describe ingress <ingress-name> 确认 hostpath 是否正确。
  • 检查 Ingress Class:确保 Ingress 资源的 kubernetes.io/ingress.class 注解与 Controller 的启动参数一致。

5.3 访问域名返回 503 Service Temporarily Unavailable

这表示 Controller 找到了路由规则,但无法将流量转发到后端服务。

  • 检查后端 Service 和 Endpointkubectl describe service <service-name>,确认 Endpoints 字段有健康的 Pod IP 地址。如果没有,说明 Service 的 selector 可能与 Pod 的 labels 不匹配,或者后端 Pod 自身没有准备就绪。
  • 检查网络策略:如果集群中启用了 NetworkPolicy,请确保有策略允许 Ingress Controller Pod 访问后端应用的 Pod。

5.4 Ingress 资源没有分配 ADDRESS

执行 kubectl get ingress 时,如果 ADDRESS 列为空,通常意味着:

  • Ingress Controller 没有正确运行。
  • Controller 的 Service (ingress-nginx-controller) 没有成功获取外部 IP(在云环境中可能需要一些时间,或者配置有误)。

六、总结

本文通过一个完整的实战演练,详细介绍了如何在 Kubernetes 集群中部署和使用 Nginx Ingress Controller。我们完成了以下核心任务:

  1. 理解了核心概念:明确了 Ingress 资源(规则)与 Ingress Controller(执行者)之间的主从关系,它是 Kubernetes 流量管理的核心组件。
  2. 成功部署 Controller:通过官方 YAML 清单,我们成功部署了 Nginx Ingress Controller,并剖析了其依赖的关键 K8s 资源,如 RBAC、Deployment 和 Service。
  3. 掌握了流量路由:我们实践了两种最常见的路由策略——基于域名和基于路径的路由,并学会了如何通过 hosts 文件和 curl 命令进行有效的测试。
  4. 实现了 HTTPS 加密:通过创建 TLS Secret 并更新 Ingress 资源,我们为应用启用了安全的 HTTPS 访问,这是生产环境的必备技能。
  5. 获得了排错能力:总结了部署和使用过程中最常见的几类问题及其排查思路,为解决实际问题提供了指导。

至此,你已经具备了在 Kubernetes 中管理七层应用流量的基础能力。Ingress Controller 的功能远不止于此,它还支持认证、限流、路径重写等高级功能,我们将在后续文章中继续探索。


Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐