在 Kubernetes 集群中,暴露服务给外部访问是一个常见需求。Service 虽然能实现服务发现和负载均衡,但在大规模应用场景下,NodePort 和 LoadBalancer 两种暴露方式存在明显局限。本文将详细介绍 Kubernetes Ingress 资源对象,包括其工作原理、部署方式及实际应用案例。
一、Ingress 概述
传统 Service 暴露方式的不足
Kubernetes 中 Service 对集群外暴露服务的主要方式有两种,但都存在明显缺点:
- NodePort 方式:会占用大量集群机器端口,随着服务增多,端口管理变得复杂
- LoadBalancer 方式:每个 Service 都需要一个独立的负载均衡器,造成资源浪费且依赖外部设备支持
Ingress 的优势
Ingress 作为 Kubernetes 的一种资源对象,仅需一个 NodePort 或 LoadBalancer 即可满足多个 Service 的暴露需求,有效解决了上述问题。
核心概念
Ingress 实现反向代理和负载均衡的核心依赖两个组件:
- Ingress:Kubernetes 中的资源对象,定义请求如何转发到 Service 的规则
- Ingress Controller:具体实现反向代理及负载均衡的程序(如 Nginx、Contour、Haproxy 等),负责解析 Ingress 规则并转化为实际的代理配置
工作原理(以 Nginx 为例)
- 用户编写 Ingress 规则,定义域名与 Service 的映射关系
- Ingress Controller 动态感知规则变化,生成对应的 Nginx 反向代理配置
- Ingress Controller 将配置更新到运行中的 Nginx Pod
- 最终由配置好规则的 Nginx 提供外部访问服务
二、Ingress 环境搭建
部署 Ingress Controller
以 Nginx Ingress Controller 为例,部署步骤如下:
bash
运行
# 创建工作目录
mkdir ingress-controller
cd ingress-controller/
# 获取指定版本的ingress-nginx(本文使用v1.12.0)
wget https://github.com/kubernetes/ingress-nginx/releases/tag/controller-v1.12.0/ingress-nginx-controller-v1.12.0.zip
unzip ingress-nginx-controller-v1.12.0.zip
cd ingress-nginx-controller-v1.12.0/deploy/static/provider/cloud
# 部署ingress-nginx
kubectl apply -f deploy.yaml
# 检查部署状态
kubectl -n ingress-nginx get pod
kubectl -n ingress-nginx get svc
外部访问策略说明
在部署配置中,externalTrafficPolicy参数有两种取值:
- Cluster:流量会在集群所有节点间负载均衡,可能导致额外网络跳转
- Local:流量仅转发到接收请求节点上的服务实例,避免额外跳转但可能导致流量分布不均
三、Ingress 应用案例
1. NodePort 模式验证
准备 Service 和 Pod
创建nginx.yaml文件:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-deploy
name: nginx-deploy
spec:
replicas: 3
selector:
matchLabels:
app: nginx-deploy
template:
metadata:
labels:
app: nginx-deploy
spec:
containers:
- image: nginx:latest
imagePullPolicy: IfNotPresent
name: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx-deploy
name: nginx-svc
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx-deploy
type: ClusterIP
部署并检查:
bash
运行
kubectl apply -f nginx.yaml
kubectl get pod
kubectl get svc
配置 Ingress 规则
创建ingress-http.yaml文件:
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
spec:
ingressClassName: nginx
rules:
- host: nginx.jx.com
http:
paths:
- backend:
service:
name: nginx-svc
port:
number: 80
path: /
pathType: Prefix
其中pathType有两种主要类型:
- Exact:精确匹配,只有路径完全一致才会匹配
- Prefix:前缀匹配,只要请求路径以前缀开头就会匹配
部署并检查 Ingress:
bash
运行
kubectl create -f ingress-http.yaml
kubectl get ingress nginx-ingress
kubectl describe ingress nginx-ingress
测试访问
配置 hosts 解析(指向运行 ingress-controller 的节点 IP):
plaintext
192.168.158.17 nginx.jx.com
使用域名访问测试:
bash
运行
curl nginx.jx.com:31502
2. LoadBalancer 模式验证
配置准备
启用严格 ARP 模式:
shell
kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e "s/strictARP: false/strictARP: true/" | \
kubectl apply -f - -n kube-system
启用严格 ARP 模式的原因:
- 避免 ARP 冲突,防止多个 Pod 响应同一个 ARP 请求
- 确保流量正确分发到预期的 Pod
- 增强网络安全性和稳定性,防止恶意干扰
部署 MetalLB
MetalLB 为非云环境提供 LoadBalancer 支持:
shell
# 部署metallb
cd /root/metallb-0.14.8/config/manifests
kubectl apply -f metallb-native.yaml
# 创建IP地址池
cat > IPAddressPool.yaml<<EOF
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: planip-pool
namespace: metallb-system
spec:
addresses:
- 192.168.158.135-192.168.158.150
EOF
# 关联IP地址池
cat > L2Advertisement.yaml<<EOF
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: planip-pool
namespace: metallb-system
spec:
ipAddressPools:
- planip-pool
EOF
# 应用配置
kubectl apply -f IPAddressPool.yaml
kubectl apply -f L2Advertisement.yaml
多域名路由配置
创建包含多个域名规则的 Ingress:
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
spec:
ingressClassName: nginx
rules:
- host: nginx.jx.com
http:
paths:
- backend:
service:
name: nginx-svc
port:
number: 80
path: /
pathType: Prefix
- host: nginx2.jx.com
http:
paths:
- backend:
service:
name: nginx-svc1
port:
number: 80
path: /
pathType: Prefix
修改 Ingress 服务类型为 LoadBalancer:
bash
运行
kubectl -n ingress-nginx edit svc ingress-nginx-controller
# 将type修改为LoadBalancer
测试访问:
bash
运行
curl nginx.jx.com
curl nginx2.jx.com