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 之前,请确保您已经具备以下环境和工具:
- Kubernetes 集群: 一个正常运行的 Kubernetes 集群。可以是本地的 Minikube/Kind,云服务商提供的托管集群(如 GKE, AKS, EKS),或自建集群。
- kubectl: Kubernetes 命令行工具,已正确配置并能够连接到您的 Kubernetes 集群。您可以通过运行
kubectl cluster-info来验证连接。 - 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 并测试访问
-
获取 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
“`
-
配置 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 地址。
- 生产环境: 在您的域名注册商处添加一个 A 记录,将
-
通过浏览器访问:
在浏览器中访问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 应用交付!