1、介绍
在前面文章中已经提到,Service对集群之外暴露服务的主要方式有两种:NodePort和LoadBalancer,但是这两种方式,都有一定的缺点:
NodePort方式的缺点是会占用很多集群机器的端口,那么当集群服务变多的时候,这个缺点就愈发明显。
LB方式的缺点是每个service需要一个LB,浪费、麻烦,并且需要kubernetes之外设备的支持。
基于这种现状,kubernetes提供了Ingress资源对象,Ingress只需要一个NodePort或者一个LB就可以满足暴露多个Service的需求。工作机制大致如下图表示:
在Kubernetes中,Ingress是管理Kubernetes集群内部服务的外部访问的API对象。
实际上,Ingress相当于一个7层的负载均衡器,是kubernetes对反向代理的一个抽象,它的工作原理类似于Nginx,可以理解成在Ingress里建立诸多映射规则,Ingress Controller通过监听这些配置规则并转化成Nginx的反向代理配置 , 然后对外部提供服务。在这里有两个核心概念:
-
ingress:kubernetes中的一个对象,作用是定义请求如何转发到service的规则
-
ingress controller:具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,根据配置的规则来实现请求转发,实现方式有很多,比如Nginx, Contour, Haproxy等等


Ingress-Nginx github 地址:https://github.com/kubernetes/ingress-nginx
Ingress-Nginx 官方网站:https://kubernetes.github.io/ingress-nginx
版本与k8s对照表
| Supported | Ingress-NGINX version | k8s supported version | Alpine Version | Nginx Version | Helm Chart Version |
|---|---|---|---|---|---|
| ? | v1.10.1 | 1.29, 1.28, 1.27, 1.26 | 3.19.1 | 1.25.3 | 4.10.1* |
| ? | v1.10.0 | 1.29, 1.28, 1.27, 1.26 | 3.19.1 | 1.25.3 | 4.10.0* |
| ? | v1.9.6 | 1.29, 1.28, 1.27, 1.26, 1.25 | 3.19.0 | 1.21.6 | 4.9.1* |
| ? | v1.9.5 | 1.28, 1.27, 1.26, 1.25 | 3.18.4 | 1.21.6 | 4.9.0* |
| ? | v1.9.4 | 1.28, 1.27, 1.26, 1.25 | 3.18.4 | 1.21.6 | 4.8.3 |
| ? | v1.9.3 | 1.28, 1.27, 1.26, 1.25 | 3.18.4 | 1.21.6 | 4.8.* |
| ? | v1.9.1 | 1.28, 1.27, 1.26, 1.25 | 3.18.4 | 1.21.6 | 4.8.* |
| ? | v1.9.0 | 1.28, 1.27, 1.26, 1.25 | 3.18.2 | 1.21.6 | 4.8.* |
| v1.8.4 | 1.27, 1.26, 1.25, 1.24 | 3.18.2 | 1.21.6 | 4.7.* | |
| v1.7.1 | 1.27, 1.26, 1.25, 1.24 | 3.17.2 | 1.21.6 | 4.6.* | |
| v1.6.4 | 1.26, 1.25, 1.24, 1.23 | 3.17.0 | 1.21.6 | 4.5.* | |
| v1.5.1 | 1.25, 1.24, 1.23 | 3.16.2 | 1.21.6 | 4.4.* | |
| v1.4.0 | 1.25, 1.24, 1.23, 1.22 | 3.16.2 | 1.19.10† | 4.3.0 | |
| v1.3.1 | 1.24, 1.23, 1.22, 1.21, 1.20 | 3.16.2 | 1.19.10† | 4.2.5 |
部署 Ingress-Nginx
# https://kubernetes.github.io/ingress-nginx/deploy/
# 下载部署用yaml文件,大家根据自己的k8s版本更换版本号
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.6.4/deploy/static/provider/cloud/deploy.yaml
# 修改镜像地址为国内镜像地址,否则镜像拉取会失败
vim deploy.yaml
# -----------------------------------------------------------------
# 在第439行
# 将image改为registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.6.3
# 教室局域网可以使用:192.168.57.200:8099/ingress-nginx/controller:v1.6.3
# 第536行和第585行
# 将registry.k8s.io/ingress-nginx/替换为registry.aliyuncs.com/google_containers/
# 教室局域网可以使用:192.168.57.200:8099/ingress-nginx/kube-webhook-certgen:v20220916-gd32f8c343
# -----------------------------------------------------------------
kubectl apply -f deploy.yaml
# 教室局域网专用版本,针对无法使用外网的情况。(已安装,可忽略)
# wget http://192.168.57.200/Software/ingress-nginx-v1.6.3-deploy.yaml
# kubectl apply -f ingress-nginx-v1.6.3-deploy.yaml
[root@k8s-master ~]# kubectl get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-db6jl 0/1 Completed 0 5h6m
ingress-nginx-admission-patch-m6rvd 0/1 Completed 0 5h6m
ingress-nginx-controller-7998c976fc-ln7z9 1/1 Running 0 5h6m
# 查看ingress-nginx-controller svc 注意: 80:30577/TCP,443:32667/TCP 此处 30577和32667 后续需要使用到
[root@k8s-master ~]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.68.155.84 <pending> 80:30577/TC,443:32667/TCP 5h6m
ingress-nginx-controller-admission ClusterIP 10.68.89.135 <none> 443/TCP 5h6m
2、准备Service、Pod
为了后面的实验比较方便,创建如下图所示的模型
安装上述图片模型,我们创建3个Nginx Pod和3个Tomcat Pod,并分别为他们创建servce ,yaml文件名叫tomcat-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: dev
spec:
replicas: 3
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deployment
namespace: dev
spec:
replicas: 3
selector:
matchLabels:
app: tomcat-pod
template:
metadata:
labels:
app: tomcat-pod
spec:
containers:
- name: tomcat
image: tomcat:8.0
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: dev
spec:
selector:
app: nginx-pod
clusterIP: None
type: ClusterIP
ports:
- port: 80
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: tomcat-service
namespace: dev
spec:
selector:
app: tomcat-pod
clusterIP: None
type: ClusterIP
ports:
- port: 8080
targetPort: 8080
执行文件并查看创建结果
# 1.先创建dev命令空间
[root@k8s-master ~]# kubectl create ns dev
# 2.创建nginx-deployment和tomcat-deployment
[root@k8s-master ~]# kubectl apply -f tomcat-nginx.yaml
deployment.apps/nginx-deployment created
deployment.apps/tomcat-deployment created
service/nginx-service created
service/tomcat-service created
[root@k8s-master ~]#
# 3.查看 deploy
[root@k8s-master ~]# kubectl get deploy -n dev
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 2/3 3 2 7s
tomcat-deployment 3/3 3 3 7s
[root@k8s-master ~]#
# 4.查看pod
[root@k8s-master ~]# kubectl get pod -n dev
NAME READY STATUS RESTARTS AGE
nginx-deployment-69cbb4f6b6-2nwkd 1/1 Running 0 13s
nginx-deployment-69cbb4f6b6-lsqcp 1/1 Running 0 13s
nginx-deployment-69cbb4f6b6-rmfzc 0/1 ContainerCreating 0 13s
tomcat-deployment-798c966d9d-cg59r 1/1 Running 0 13s
tomcat-deployment-798c966d9d-s5blw 1/1 Running 0 13s
tomcat-deployment-798c966d9d-zrjdf 1/1 Running 0 13s
# 5.查看svc
[root@k8s-master ~]# kubectl get svc -n dev
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service ClusterIP None <none> 80/TCP 17s
tomcat-service ClusterIP None <none> 8080/TCP 17s
3.在本机配置host
更改本机host,模拟两个域名
# 我的master IP 为192.168.8.201 模拟 nginx域名为 nginx.lz.com
[root@k8s-master ~]# echo "192.168.8.201 nginx.lz.com" >> /etc/hosts
# 我的master IP 为192.168.8.201 模拟 tomcat域名为 tomcat.lz.com
[root@k8s-master ~]# echo "192.168.8.201 tomcat.lz.com" >> /etc/hosts
# 查看已添加hosts
[root@k8s-master ~]# cat /etc/hosts
192.168.8.201 nginx.lz.com
192.168.8.201 tomcat.lz.com
4、Http代理
创建ingress-http.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-http
namespace: dev
spec:
# 这个很关键,如果写错会导致访问404
ingressClassName: nginx
rules:
- host: nginx.lz.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
- host: tomcat.lz.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tomcat-service
port:
number: 8080
ingressClassName 如果忘记自己设置的是什么,可以通过以下方式查询
命令:
kubectl describe deploy ingress-nginx-controller -n ingress-nginx
实际操作
# 创建
[root@k8s-master ~]# kubectl apply -f ingress-http.yaml
ingress.networking.k8s.io/ingress-http created
# 查看ingress
[root@k8s-master ~]# kubectl get ing ingress-http -n dev
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-http nginx nginx.lz.com,tomcat.lz.com 80 64s
# 查看ingress详情
[root@k8s-master ~]# kubectl describe ing ingress-http -n dev
Name: ingress-http
Labels: <none>
Namespace: dev
Address:
Ingress Class: ingress
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
# 可以看出域名 nginx.lz.com 代理了后端 三个nginx pod 访问
nginx.lz.com
/ nginx-service:80 (172.17.169.187:80,172.17.169.190:80,172.17.36.106:80)
# 可以看出域名 tomcat.lz.com 代理了后端 三个tomcat pod
tomcat.lz.com
/ tomcat-service:8080 (172.17.169.185:8080,172.17.169.188:8080,172.17.36.105:8080)
Annotations: <none>
Events: <none>
# 还记得上篇文章中我们 安装完ingree-nginx 后,查看 ingress-nginx-controller service的结果吗
# 在上面我们已经安装完ingress-http 如果想在外部访问则需此处PORTS,这个端口意思是,如果ing代理的是http即80端口,则外部访问需要使用30577(随机生成的,可以自定义)端口访问,如果ing代理的是https即443端口,则外部访问需要使用32667(也是随机生成,当然可以自定义)端口访问
[root@k8s-master ~]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.15.245.169 <none> 80:30577/TCP,443:32667/TCP 41h
ingress-nginx-controller-admission ClusterIP 10.0.156.229 <none> 443/TCP
# 本次实例我们的tomcat和nginx都是80 端口,所以访问的时候都需要在域名 后面增加 :30577 才可正常访问
本机访问效果
5、Https代理
5.1、创建证书
实际生产我们需要申请https nginx证书,这里我们就模拟创建一个证书
# 创建证书
[root@k8s-master ~]# openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/C=CN/ST=BJ/L=BJ/O=nginx/CN=lz.com"
Generating a 2048 bit RSA private key
...........+++
..............................+++
writing new private key to 'tls.key'
-----
# 证书已创建
[root@k8s-master ~]# ls
tls.crt tls.key
# 创建密钥 这个秘钥创建,如果不会先记着,后续有讲解
[root@k8s-master ~]# kubectl create secret tls tls-secret --key tls.key --cert tls.crt
secret/tls-secret created
# 查看已创建秘钥
[root@k8s-master ~]# kubectl get secret
NAME TYPE DATA AGE
tls-secret kubernetes.io/tls 2 6s
# 5.2、创建ingress-https.yaml
vim ingress-https.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-https
namespace: dev
spec:
tls:
- hosts:
- nginx.lz.com
- tomcat.lz.com
secretName: tls-secret # 指定秘钥
# 这个很关键,如果写错会导致访问404
ingressClassName: nginx
rules:
- host: nginx.lz.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
- host: tomcat.lz.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tomcat-service
port:
number: 8080
5.3、实例操作效果
# 创建
[root@k8s-master ~]# kubectl apply -f ingress-https.yaml
ingress.networking.k8s.io/ingress-https created
[root@k8s-master ~]#
# 查看ing
[root@k8s-master ~]# kubectl get ing ingress-https -n dev
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-https ingress-nginx nginx.lz.com,tomcat.lz.com 80, 443 7s
# 查看ing 详情
[root@k8s-master ~]# kubectl describe ing ingress-https -n dev
Name: ingress-https
Labels: <none>
Namespace: dev
Address:
Ingress Class: ingress-nginx
Default backend: <default>
# TLS已关联
TLS:
tls-secret terminates nginx.lz.com,tomcat.lz.com
Rules:
# 规则也已经创建
Host Path Backends
---- ---- --------
nginx.lz.com
/ nginx-service:80 (172.17.169.187:80,172.17.169.190:80,172.17.36.106:80)
tomcat.lz.com
/ tomcat-service:8080 (172.17.169.185:8080,172.17.169.188:8080,172.17.36.105:8080)
Annotations: <none>
Events: <none>
# 查看访问443 需要什么用什么端口 此处是32667
[root@k8s-master ~]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.15.245.169 <none> 80:30577/TCP,443:32667/TCP 41h
ingress-nginx-controller-admission ClusterIP 10.0.156.229 <none> 443/TCP
# 在本地访问 https://tomcat.lz.com:32667 和 https://nginx.lz.com:32667 查看效果
Ingress-Nginx 实战
一、安装Ingress-Nginx控制器
1. 部署Ingress-Nginx(兼容K8s 1.23+)
# 部署稳定版控制器(v1.2.1)
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.2.1/deploy/static/provider/cloud/deploy.yaml
# 等待控制器就绪(约2-3分钟)
kubectl wait --namespace ingress-nginx \
--for=condition=ready pod \
--selector=app.kubernetes.io/component=controller \
--timeout=120s
2. 确认部署状态
# 查看命名空间下的Pod(应在2个node上调度)
kubectl get pods -n ingress-nginx -o wide
# 查看Service(记录80端口对应的NodePort,如31234)
kubectl get svc -n ingress-nginx ingress-nginx-controller
二、部署Nginx和Tomcat服务
1. 部署Nginx应用
创建nginx-deploy.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-app
spec:
replicas: 2 # 2个副本,分布在2个node上
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21
ports:
- containerPort: 80
# 自定义首页内容,便于区分
command: ["/bin/sh", "-c"]
args:
- echo "<h1>Welcome to Nginx Service</h1>" > /usr/share/nginx/html/index.html;
nginx -g "daemon off;";
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: ClusterIP # 内部服务,无需外部暴露
2. 部署Tomcat应用
创建tomcat-deploy.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-app
spec:
replicas: 2
selector:
matchLabels:
app: tomcat
template:
metadata:
labels:
app: tomcat
spec:
containers:
- name: tomcat
image: tomcat:9.0
ports:
- containerPort: 8080
# 自定义欢迎页
command: ["/bin/sh", "-c"]
args:
- echo "<h1>Welcome to Tomcat Service</h1>" > /usr/local/tomcat/webapps/ROOT/index.html;
catalina.sh run;
---
apiVersion: v1
kind: Service
metadata:
name: tomcat-svc
spec:
selector:
app: tomcat
ports:
- port: 80
targetPort: 8080 # Tomcat默认端口是8080
type: ClusterIP
3. 执行部署
kubectl apply -f nginx-deploy.yaml
kubectl apply -f tomcat-deploy.yaml
# 验证部署(确认Pod分布在2个node上)
kubectl get pods -o wide
三、配置Ingress路由规则
创建ingress-config.yaml(通过路径区分Nginx和Tomcat):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-tomcat-ingress
annotations:
# 路径重写:去掉前缀后转发到服务
nginx.ingress.kubernetes.io/rewrite-target: /
# 启用负载均衡(多副本时生效)
nginx.ingress.kubernetes.io/load-balance: round_robin
spec:
ingressClassName: nginx # 指定Ingress控制器类型
rules:
- http: # 无域名,使用IP+路径访问
paths:
- path: /nginx # 访问路径:IP:端口/nginx → 路由到Nginx
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
- path: /tomcat # 访问路径:IP:端口/tomcat → 路由到Tomcat
pathType: Prefix
backend:
service:
name: tomcat-svc
port:
number: 80
应用配置:
kubectl apply -f ingress-config.yaml
# 查看Ingress规则
kubectl get ingress nginx-tomcat-ingress
四、访问测试
1. 获取访问地址
# 获取任意node节点的IP(选一个能从外部访问的node)
NODE_IP=$(kubectl get nodes node-1 -o jsonpath='{.status.addresses[0].address}') # 替换node-1为实际节点名
# 获取Ingress的NodePort端口
INGRESS_PORT=$(kubectl get svc -n ingress-nginx ingress-nginx-controller -o jsonpath='{.spec.ports[0].nodePort}')
echo "Nginx访问地址:http://$NODE_IP:$INGRESS_PORT/nginx"
echo "Tomcat访问地址:http://$NODE_IP:$INGRESS_PORT/tomcat"
2. 测试访问
# 测试Nginx服务
curl http://$NODE_IP:$INGRESS_PORT/nginx
# 预期输出:<h1>Welcome to Nginx Service</h1>
# 测试Tomcat服务
curl http://$NODE_IP:$INGRESS_PORT/tomcat
# 预期输出:<h1>Welcome to Tomcat Service</h1>
也可在浏览器中访问上述地址,验证页面内容。
五、负载均衡验证(可选)
由于两个服务都部署了2个副本(分布在不同node上),可验证负载均衡效果:
- 查看Nginx Pod的IP:
bash
kubectl get pods -l app=nginx -o jsonpath='{range .items[*]}{.status.podIP}{"\n"}{end}'
- 多次访问并查看日志(确认请求分发到不同Pod):
```bash # 连续访问5次 for i in {1..5}; do curl http://$NODE_IP:$INGRESS_PORT/nginx; done
# 查看每个Nginx Pod的访问日志 for pod in $(kubectl get pods -l app=nginx -o jsonpath='{.items[*].metadata.name}'); do echo "Logs from $pod:" kubectl logs $pod | grep "GET /" done ```
六、配置说明
- 多节点调度:通过
replicas: 2确保服务分布在2个node上,提高可用性。 - 路径路由:通过
/nginx和/tomcat路径区分两个服务,无需域名。 - 负载均衡:Ingress-Nginx默认会对多副本服务进行轮询负载均衡。
- 路径重写:
rewrite-target: /确保服务收到的是根路径请求(而非带前缀的路径)。
如果需要通过域名访问(如nginx.example.com和tomcat.example.com),只需在Ingress规则中添加host字段并配置本地hosts解析即可。