Nginx Ingress 在 Kubernetes 中的应用:详细教程 – wiki大全

Nginx Ingress 在 Kubernetes 中的应用:详细教程

引言

在现代云原生应用开发中,Kubernetes 已成为容器编排的事实标准。然而,如何将外部流量可靠、高效地路由到 Kubernetes 集群内部运行的服务,一直是许多开发者面临的挑战。Kubernetes 提供了 Ingress 资源对象,用于管理从集群外部到集群内部服务的 HTTP 和 HTTPS 路由。但 Ingress 本身只是一个规范,它需要一个具体的实现来发挥作用,这个实现就是 Ingress Controller。

在众多 Ingress Controller 中,Nginx Ingress Controller 凭借其高性能、稳定性和丰富的功能集,成为了社区中最流行、使用最广泛的选择之一。它利用 Nginx 作为反向代理和负载均衡器,将复杂的路由规则、TLS/SSL 终止、身份验证、请求重写等功能呈现在 Kubernetes Ingress 资源面前,使开发者能够以声明式的方式管理这些流量入口配置。

本教程将详细介绍如何在 Kubernetes 集群中部署和配置 Nginx Ingress Controller,并通过实例展示其基本和高级功能,帮助您更好地管理和暴露您的 Kubernetes 服务。

前提条件 (Prerequisites)

在开始部署和配置 Nginx Ingress Controller 之前,请确保您已经具备以下环境和工具:

  1. Kubernetes 集群: 一个正常运行的 Kubernetes 集群。可以是本地的 Minikube/Kind,云服务商提供的托管集群(如 GKE, AKS, EKS),或自建集群。
  2. kubectl: Kubernetes 命令行工具,已正确配置并能够连接到您的 Kubernetes 集群。您可以通过运行 kubectl cluster-info 来验证连接。
  3. Helm (推荐): Kubernetes 的包管理器,用于简化 Nginx Ingress Controller 的部署。本教程将主要使用 Helm 进行安装。如果您尚未安装 Helm,请参考其官方文档进行安装:https://helm.sh/docs/intro/install/

请确保上述工具均已安装并配置妥当,以便顺利进行后续的操作。

Nginx Ingress Controller 的安装

安装 Nginx Ingress Controller 最推荐的方式是使用 Helm。它允许您轻松地部署、配置和升级 Ingress Controller。

步骤 1: 添加 Helm 仓库

首先,您需要将 Nginx Ingress Controller 的 Helm 仓库添加到您的本地 Helm 配置中。

bash
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

  • helm repo add ingress-nginx ...: 将 Nginx Ingress Controller 的官方 Helm 仓库添加到您的 Helm 配置中,并将其命名为 ingress-nginx
  • helm repo update: 从所有配置的仓库中获取最新的 chart 信息。

步骤 2: 选择合适的安装方式 (LoadBalancer 或 NodePort)

Nginx Ingress Controller 需要一个外部可访问的 IP 地址或主机名来接收流量。这通常通过 Kubernetes Service 的类型来实现。

选项 A: 使用 LoadBalancer (推荐,适用于云环境)

如果您的 Kubernetes 集群运行在支持 LoadBalancer 类型的云提供商(如 AWS, GKE, Azure, DigitalOcean 等)上,这是最简单和推荐的方式。LoadBalancer Service 会自动为您配置一个外部 IP 地址。

bash
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx --create-namespace \
--set controller.service.type=LoadBalancer \
--set controller.hostNetwork=false

  • --namespace ingress-nginx --create-namespace: 在 ingress-nginx 命名空间中安装,如果该命名空间不存在则创建。
  • --set controller.service.type=LoadBalancer: 将 Ingress Controller 服务的类型设置为 LoadBalancer
  • --set controller.hostNetwork=false: 这是一个常见的配置,确保 Ingress Controller 不直接使用宿主机的网络,而是通过 Service 进行负载均衡。

选项 B: 使用 NodePort (适用于裸金属或本地环境,如 Minikube/Kind)

如果您的集群不支持 LoadBalancer Service,或者您在本地环境(如 Minikube、Kind)进行测试,可以使用 NodePort 类型。这将通过集群节点的特定端口暴露 Ingress Controller。

bash
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx --create-namespace \
--set controller.service.type=NodePort \
--set controller.hostNetwork=false

  • --set controller.service.type=NodePort: 将 Ingress Controller 服务的类型设置为 NodePort。您需要通过任意节点的 IP 地址加上 NodePort 暴露的端口来访问服务。

步骤 3: 验证安装

安装完成后,等待几分钟,然后检查 Ingress Controller Pod 和 Service 的状态:

bash
kubectl get pods --namespace ingress-nginx
kubectl get svc --namespace ingress-nginx

您应该能看到一个或多个 ingress-nginx Pod 处于 Running 状态,并且一个名为 ingress-nginx-controller 的 Service。

如果您使用的是 LoadBalancer 类型,kubectl get svc 的输出中,ingress-nginx-controller Service 的 EXTERNAL-IP 列应该会显示一个外部 IP 地址或主机名。在某些云提供商中,这可能需要几分钟才能分配完成。

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.xx.xx.xx <pending> 80:3xxxx/TCP,443:3xxxx/TCP 10s (Initially <pending>)

EXTERNAL-IP 显示一个有效 IP 后,您的 Nginx Ingress Controller 就成功安装并准备就绪了。

基本配置:暴露您的第一个应用

本节将指导您如何部署一个简单的 Web 应用程序,并通过 Nginx Ingress Controller 为其配置基本的 Ingress 规则,使其能够从外部访问。

步骤 1: 部署一个示例应用

我们将部署一个简单的 Nginx Web 服务器作为示例应用。

创建一个名为 demo-app.yaml 的文件,内容如下:

“`yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-web
labels:
app: demo-web
spec:
replicas: 2
selector:
matchLabels:
app: demo-web
template:
metadata:
labels:
app: demo-web
spec:
containers:
– name: nginx
image: nginx:latest
ports:
– containerPort: 80


apiVersion: v1
kind: Service
metadata:
name: demo-web-svc
spec:
selector:
app: demo-web
ports:
– protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
“`

应用此配置文件:

bash
kubectl apply -f demo-app.yaml

  • Deployment demo-web: 部署了 2 个 Nginx Pod。
  • Service demo-web-svc: 一个 ClusterIP 类型的 Service,将流量路由到带有 app: demo-web 标签的 Pod 的 80 端口。

验证 Pod 和 Service 是否成功创建:

bash
kubectl get pods -l app=demo-web
kubectl get svc demo-web-svc

步骤 2: 创建一个 Ingress 资源

现在,我们来创建一个 Ingress 资源,让 Nginx Ingress Controller 知道如何将外部请求路由到 demo-web-svc

创建一个名为 demo-ingress.yaml 的文件,内容如下:

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx # 指定使用 nginx Ingress Controller
rules:
- host: demo.example.com # 您需要将此域名解析到 Ingress Controller 的 EXTERNAL-IP
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: demo-web-svc
port:
number: 80

应用此 Ingress 配置文件:

bash
kubectl apply -f demo-ingress.yaml

  • ingressClassName: nginx: 这是 Kubernetes 1.19+ 版本中推荐的方式,用于明确指定哪个 Ingress Controller 应该处理此 Ingress 资源。我们安装的 Nginx Ingress Controller 默认会处理 ingressClassName: nginx 的 Ingress。
  • host: demo.example.com: 定义了此 Ingress 规则将匹配的主机名。您需要将 demo.example.com(或您自己的域名)的 DNS 记录配置为指向 Nginx Ingress Controller Service 的 EXTERNAL-IP
  • path: /pathType: Prefix: 表示所有以 / 开头的路径都将匹配此规则。Prefix 匹配方式会匹配请求路径的前缀。
  • backend: 定义了请求将被路由到的后端服务。这里是 demo-web-svc 的 80 端口。
  • nginx.ingress.kubernetes.io/rewrite-target: /: 这是一个 Nginx Ingress Controller 特有的 Annotation。它告诉 Ingress Controller 在将请求转发到后端服务之前,将请求路径重写为 /。这对于许多不期望接收完整路径的服务很有用。

验证 Ingress 资源是否成功创建:

bash
kubectl get ingress demo-ingress

您应该能看到 demo-ingress,其 ADDRESS 列显示 Nginx Ingress Controller 的外部 IP。

步骤 3: 配置 DNS 并测试访问

  1. 获取 Ingress Controller 的 EXTERNAL-IP:
    运行以下命令获取 Nginx Ingress Controller Service 的外部 IP 地址:

    “`bash
    kubectl get svc ingress-nginx-controller -n ingress-nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}’

    或者对于 NodePort,获取任一节点的IP地址和NodePort端口

    kubectl get svc ingress-nginx-controller -n ingress-nginx

    “`

  2. 配置 DNS (或修改 hosts 文件):
    将您在 Ingress 中定义的主机名 (demo.example.com) 解析到上一步获取到的 EXTERNAL-IP

    • 生产环境: 在您的域名注册商处添加一个 A 记录,将 demo.example.com 指向 EXTERNAL-IP
    • 测试环境: 修改您本地计算机的 hosts 文件(Windows: C:\Windows\System32\drivers\etc\hosts;Linux/macOS: /etc/hosts),添加一行:
      <EXTERNAL-IP> demo.example.com
      <EXTERNAL-IP> 替换为实际的 IP 地址。
  3. 通过浏览器访问:
    在浏览器中访问 http://demo.example.com。您应该能看到 Nginx 的默认欢迎页面。

恭喜您!您已经成功地通过 Nginx Ingress Controller 将一个 Kubernetes 服务暴露到外部。

高级功能

Nginx Ingress Controller 不仅仅提供基本的 HTTP 路由,它还支持一系列高级功能,可以满足更复杂的流量管理需求。

1. TLS/SSL 终止

在生产环境中,为网站启用 HTTPS 是必不可少的。Nginx Ingress Controller 可以作为 TLS/SSL 的终止点,处理加密和解密,然后将未加密的流量转发到后端服务,从而减轻后端服务的负担。

要实现 TLS 终止,您需要一个 TLS 证书和私钥。在 Kubernetes 中,这些通常存储在一个 Secret 中。

步骤 A: 创建 TLS Secret

假设您已经拥有 demo.example.com 的 SSL 证书和私钥(例如通过 Let’s Encrypt 或其他证书颁发机构获得)。

bash
kubectl create secret tls demo-tls-secret --key tls.key --cert tls.crt

  • tls.key: 您的私钥文件。
  • tls.crt: 您的证书文件。

步骤 B: 更新 Ingress 资源

修改 demo-ingress.yaml,添加 tls 部分:

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
tls:
- hosts:
- demo.example.com
secretName: demo-tls-secret # 引用上面创建的 Secret
rules:
- host: demo.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: demo-web-svc
port:
number: 80

应用更新后的 Ingress:

bash
kubectl apply -f demo-ingress.yaml

现在,当您通过 https://demo.example.com 访问时,Nginx Ingress Controller 将使用 demo-tls-secret 中的证书来终止 TLS 连接。

2. Path-based Routing (基于路径的路由)

除了根据主机名路由外,Ingress 还可以根据请求的 URL 路径进行路由。这意味着您可以将不同的路径映射到不同的后端服务。

示例:
假设您有一个 blog 服务,希望通过 demo.example.com/blog 访问。

首先,部署一个新的 blog 应用和服务 (以 Nginx 为例):

“`yaml

blog-app.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: blog-web
labels:
app: blog-web
spec:
replicas: 1
selector:
matchLabels:
app: blog-web
template:
metadata:
labels:
app: blog-web
spec:
containers:
– name: nginx
image: nginxdemos/hello:latest # 一个简单的带路径响应的Nginx镜像
ports:
– containerPort: 80


apiVersion: v1
kind: Service
metadata:
name: blog-web-svc
spec:
selector:
app: blog-web
ports:
– protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
“`

bash
kubectl apply -f blog-app.yaml

然后,更新 Ingress 规则以包含 blog 路径:

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-ingress
annotations:
# 移除或根据需要调整 rewrite-target,因为不同的路径可能需要不同的重写行为
# nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
tls:
- hosts:
- demo.example.com
secretName: demo-tls-secret
rules:
- host: demo.example.com
http:
paths:
- path: / # 主路径路由到 demo-web
pathType: Prefix
backend:
service:
name: demo-web-svc
port:
number: 80
- path: /blog # /blog 路径路由到 blog-web
pathType: Prefix
backend:
service:
name: blog-web-svc
port:
number: 80
# 对于 /blog 路径,如果后端服务不期望 /blog 前缀,可以使用 rewrite
# annotations:
# nginx.ingress.kubernetes.io/rewrite-target: /

注意: pathType 有多种选择:
* Prefix: 基于 URL 路径前缀匹配。
* Exact: 精确匹配 URL 路径。
* ImplementationSpecific: 默认类型,行为取决于 Ingress Controller。

应用更新后的 Ingress:

bash
kubectl apply -f demo-ingress.yaml

现在,访问 https://demo.example.com 会访问到 demo-web,而 https://demo.example.com/blog 则会访问到 blog-web

3. Name-based Virtual Hosts (基于名称的虚拟主机)

Nginx Ingress Controller 允许您在同一个 Ingress Controller 后面托管多个域名,每个域名对应不同的后端服务。

示例:
部署一个新的 admin 应用和服务,希望通过 admin.example.com 访问。

“`yaml

admin-app.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: admin-web
labels:
app: admin-web
spec:
replicas: 1
selector:
matchLabels:
app: admin-web
template:
metadata:
labels:
app: admin-web
spec:
containers:
– name: nginx
image: nginx:latest
ports:
– containerPort: 80


apiVersion: v1
kind: Service
metadata:
name: admin-web-svc
spec:
selector:
app: admin-web
ports:
– protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
“`

bash
kubectl apply -f admin-app.yaml

然后,创建一个新的 Ingress 资源(或者修改现有 Ingress)来处理 admin.example.com

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-host-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
tls: # 如果需要,为 admin.example.com 配置单独的 TLS Secret
- hosts:
- demo.example.com
secretName: demo-tls-secret
- hosts:
- admin.example.com
secretName: admin-tls-secret # 假设您为 admin.example.com 创建了单独的 Secret
rules:
- host: demo.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: demo-web-svc
port:
number: 80
- path: /blog
pathType: Prefix
backend:
service:
name: blog-web-svc
port:
number: 80
- host: admin.example.com # 新增的主机规则
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: admin-web-svc
port:
number: 80

记得在 DNS 中为 admin.example.com 添加 A 记录,指向 Ingress Controller 的 EXTERNAL-IP

4. URL 重写 (Rewrites)

Nginx Ingress Controller 提供了强大的 URL 重写功能,通过 nginx.ingress.kubernetes.io/rewrite-target Annotation 实现。这在后端服务不希望接收原始 URL 路径时非常有用。

  • nginx.ingress.kubernetes.io/rewrite-target: /:将所有匹配的路径重写为 /
  • nginx.ingress.kubernetes.io/rewrite-target: /$1:配合正则表达式使用,捕获路径的一部分进行重写。

示例:
如果您的服务只期望接收 /,但您想通过 /app/* 路径访问:

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rewrite-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: / # 重写目标
spec:
ingressClassName: nginx
rules:
- host: rewrite.example.com
http:
paths:
- path: /app(/|$)(.*) # 使用正则表达式匹配 /app/ 后的所有内容
pathType: Prefix
backend:
service:
name: demo-web-svc
port:
number: 80

访问 http://rewrite.example.com/app/some/path 将会被重写为 http://demo-web-svc/some/path

5. 认证 (Authentication)

您可以通过 Nginx Ingress Controller 添加基本的 HTTP 认证(Basic Auth),以保护您的后端服务。

步骤 A: 创建 Basic Auth Secret

首先,生成一个包含用户密码的 htpasswd 文件:

“`bash

安装 htpasswd 工具,如果尚未安装

For Debian/Ubuntu: sudo apt-get install apache2-utils

For CentOS/RHEL: sudo yum install httpd-tools

htpasswd -c auth/users admin # 创建用户 ‘admin’,会提示输入密码
“`

然后,将此文件内容创建为一个 Kubernetes Secret:

bash
kubectl create secret generic basic-auth-secret --from-file=auth/users

步骤 B: 更新 Ingress 资源

在 Ingress 资源中添加认证相关的 Annotation:

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: protected-ingress
annotations:
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: basic-auth-secret # 引用上面创建的 Secret
nginx.ingress.kubernetes.io/auth-realm: "Authentication Required - Nginx Ingress"
spec:
ingressClassName: nginx
rules:
- host: protected.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: demo-web-svc
port:
number: 80

应用此 Ingress:

bash
kubectl apply -f protected-ingress.yaml

现在,当您访问 http://protected.example.com 时,浏览器会弹出一个认证对话框,要求您输入用户名和密码。

总结

通过本教程,您应该已经对 Nginx Ingress Controller 在 Kubernetes 中的应用有了深入的了解。我们从其基本概念入手,逐步介绍了如何利用 Helm 部署 Nginx Ingress Controller,并通过一个简单的 Web 应用展示了如何配置基本的 Ingress 规则,使其能够对外暴露服务。

更重要的是,我们探索了 Nginx Ingress Controller 的强大高级功能,包括:

  • TLS/SSL 终止:保障数据传输安全,并减轻后端服务处理加密的负担。
  • Path-based Routing (基于路径的路由):根据 URL 路径将请求精确地分发到不同的后端服务。
  • Name-based Virtual Hosts (基于名称的虚拟主机):在同一 Ingress Controller 下托管和管理多个域名。
  • URL 重写:灵活地修改请求路径,以适应后端服务的期望。
  • 认证:通过 Basic Auth 等方式为服务添加一层访问控制。

Nginx Ingress Controller 不仅提供高性能的 HTTP/HTTPS 路由,还通过其丰富的 Annotation 支持,将 Nginx 的强大功能以 Kubernetes 原生声明式的方式呈现出来,极大地简化了流量管理和应用暴露的复杂性。掌握 Nginx Ingress Controller 的使用,是任何 Kubernetes 用户管理生产级流量不可或缺的技能。希望本教程能帮助您更好地利用 Nginx Ingress Controller 来优化您的 Kubernetes 应用交付!

滚动至顶部