一、概述
Service对集群之外暴露服务的主要方式有两种:NotePort和LoadBalancer,但是这两种方式,都有一定的缺点:
-
NodePort方式的缺点是会占用很多集群机器的端口,那么当集群服务变多的时候,这个缺点就愈发明显。
-
LB方式的缺点是每个service需要一个LB,浪费、麻烦,并且需要kubernetes之外设备的支持。
基于这种现状,kubernetes提供了Ingress资源对象,Ingress只需要一个NodePort或者一个LB就可以满足暴露多个Service的需求。工作机制大致如下图表示:

实际上,Ingress相当于一个7层的负载均衡器,是kubernetes对反向代理的一个抽象,它的工作原理类似于Nginx,可以理解成在Ingress里建立诸多映射规则,Ingress Controller通过监听这些配置规则并转化成Nginx的反向代理配置 , 然后对外部提供服务。在这里有两个核心概念:
-
ingress:kubernetes中的一个对象,作用是定义请求如何转发到service的规则
-
ingress controller:具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,根据配置的规则来实现请求转发,实现方式有很多,比如Nginx, Contour, Haproxy等等
Ingress(以Nginx为例)的工作原理如下:
-
用户编写Ingress规则,说明哪个域名对应kubernetes集群中的哪个Service
-
Ingress控制器动态感知 Ingress服务规则的变化,然后生成一段对应的Nginx反向代理配置
-
Ingress控制器会将生成的Nginx配置写入到一个运行着的Nginx服务中的pod,并动态更新
-
到此为止,其实真正在工作的就是一个Nginx了,内部配置了用户定义的请求转发规则

版本对比图

二、 Ingress应用案例
2.1 环境准备
搭建ingress环境
创建文件夹
root@k8s-master01 \~\]# mkdir ingress-controller \[root@k8s-master01 \~\]# cd ingress-controller/ # 获取ingress-nginx,本次案例使用的是1.12.0版本 \[root@k8s-master01 ingress-controller\]# wget https://github.com/kubernetes/ingress-nginx/releases/tag/controller-v1.12.0/ingress-nginx-controller-v1.12.0.zip \[root@k8s-master01 ingress-controller\]# unzip ingress-nginx-controller-v1.12.0.zip \[root@k8s-master01 ingress-controller\]# cd ingress-nginx-controller-v1.12.0/deploy/static/provider/cloud \[root@k8s-master01 cloud\]# ls deploy.yaml kustomization.yaml #####外部访问策略: externalTrafficPolicy: Local ### Cluster:流量会在集群内的所有节点之间进行负载均衡,可能会导致网络跳转,即流量可能会先到达一个节点,然后再被转发到其他节点上的服务实例。 ### Local:流量只会被转发到接收请求的节点上的服务实例,这样可以避免额外的网络跳转,但可能会导致某些节点上的服务实例接收不到流量,尤其是当服务实例在集群中分布不均匀时。 ##查看并修改镜像源为如下: \[root@k8s-master01 cloud\]# cat deploy.yaml \| grep -n image 445: image: registry.k8s.io/ingress-nginx/controller:v1.12.0 547: image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.5.0 601: image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.5.0 #########部署############# \[root@k8s-master01 cloud\]# kubectl apply -f deploy.yaml namespace/ingress-nginx created serviceaccount/ingress-nginx created serviceaccount/ingress-nginx-admission created role.rbac.authorization.k8s.io/ingress-nginx created role.rbac.authorization.k8s.io/ingress-nginx-admission created clusterrole.rbac.authorization.k8s.io/ingress-nginx created clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created rolebinding.rbac.authorization.k8s.io/ingress-nginx created rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created configmap/ingress-nginx-controller created service/ingress-nginx-controller created service/ingress-nginx-controller-admission created deployment.apps/ingress-nginx-controller created job.batch/ingress-nginx-admission-create created job.batch/ingress-nginx-admission-patch created ingressclass.networking.k8s.io/nginx created validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created \[root@k8s-master01 cloud\]# kubectl -n ingress-nginx get pod NAME READY STATUS RESTARTS AGE ingress-nginx-admission-create-sgksd 0/1 Completed 0 77s ingress-nginx-admission-patch-f4rdc 0/1 Completed 1 77s ingress-nginx-controller-565cc5ddd9-2qwnm 1/1 Running 0 77s \[root@k8s-master01 cloud\]# kubectl -n ingress-nginx get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx-controller LoadBalancer 10.10.103.132 \
80:31502/TCP,443:31020/TCP 96s ingress-nginx-controller-admission ClusterIP 10.10.227.21 \ 443/TCP 96s ##查看集群已经存在的nginx类型 \[root@k8s-master01 cloud\]# kubectl get ingressclass NAME CONTROLLER PARAMETERS AGE nginx k8s.io/ingress-nginx \ 2m53s
2.2 验证-NodePort模式
准备service和pod
创建nginx.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创建
root@k8s-master01 ingress-controller\]# kubectl apply -f nginx.yaml deployment.apps/nginx-deploy created service/nginx-svc created # 查看 \[root@k8s-master01 ingress-controller\]# kubectl get pod NAME READY STATUS RESTARTS AGE nginx-deploy-7c7b68644b-26jtl 1/1 Running 0 20s nginx-deploy-7c7b68644b-5jsmb 1/1 Running 0 20s nginx-deploy-7c7b68644b-rjc4r 1/1 Running 0 20s \[root@k8s-master01 ingress-controller\]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.10.0.1 \
443/TCP 13d nginx-svc ClusterIP 10.10.199.33 \ 80/TCP 36s
修改ingress代理模式
root@k8s-master01 ingress-controller\]# kubectl -n ingress-nginx edit svc ingress-nginx-controller 49 type: NodePort 50 status: 51 loadBalancer: {} ##查看 \[root@k8s-master01 ingress-controller\]# kubectl -n ingress-nginx get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx-controller NodePort 10.10.103.132 \
80:31502/TCP,443:31020/TCP 10m ingress-nginx-controller-admission ClusterIP 10.10.227.21 \ 443/TCP 10m
设置Http代理
创建ingress-http.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress # 创建一个类型为Ingress的资源
metadata:
name: nginx-ingress # 这个资源的名字为 nginx-ingress
spec:
ingressClassName: nginx # 使用nginx
rules:
- host: nginx.jx.com # 访问此内容的域名
http:
paths:- backend:
service:
name: nginx-svc # 对应nginx的服务名字,该规则的namespace必须与service的一致
port:
number: 80 # 访问的端口
path: / # 匹配规则
pathType: Prefix # 匹配类型,这里为前缀匹配#Exact(精确匹配):
#当 PathType 的值为 Exact 时,意味着服务的路由规则将仅在传入请求的路径与指定的路径完全相同时才会被匹配。
#例如,如果一个服务的路径配置为 /api/v1/resource 且 PathType 为 Exact,那么只有当请求的路径是 /api/v1/resource 时,该服务才会被选中处理请求,多一个字符或少一个字符都不会匹配,包括 /api/v1/resource/ 或者 /api/v1/resource?id=1 这样的请求路径都不会被该服务处理,这是一种非常严格的精确匹配规则。
#Prefix(前缀匹配):
#当 PathType 的值为 Prefix 时,服务将匹配以指定路径作为前缀的请求路径。
#例如,如果一个服务的路径配置为 /api/v1 且 PathType 为 Prefix,那么 /api/v1、/api/v1/resource、/api/v1/resource/1 等以 /api/v1 开头的请求路径都会被该服务处理,只要请求路径以 /api/v1 开头,该服务就会处理该请求,而不要求请求路径完全等于 /api/v1。创建
root@k8s-master01 \~\]# kubectl create -f ingress-http.yaml ingress.extensions/ingress-http created # 查看 \[root@k8s-master01 ingress-controller\]# kubectl get ingress nginx-ingress NAME CLASS HOSTS ADDRESS PORTS AGE nginx-ingress nginx nginx.jx.com 10.10.103.132 80 31s # 查看详情 \[root@k8s-master01 \~\]# kubectl describe ingress nginx-ingress Name: nginx-ingress Labels: \
Namespace: default Address: 10.10.26.150 Ingress Class: nginx Default backend: \ Rules: Host Path Backends ---- ---- -------- nginx.jx.com / nginx-svc:80 (172.16.69.202:80,172.16.79.74:80,172.16.79.75:80) Annotations: \ Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Sync 9m2s (x2 over 14m) nginx-ingress-controller Scheduled for sync \[root@k8s-master \~\]# kubectl -n ingress-nginx get po -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES ingress-nginx-admission-create-qmdj9 0/1 Completed 0 21m 10.244.36.89 k8s-node1 \ \ ingress-nginx-admission-patch-htkxb 0/1 Completed 0 21m 10.244.36.90 k8s-node1 \ \ ingress-nginx-controller-7d7455dcf8-5s9q5 1/1 Running 0 21m 10.244.169.157 k8s-node2 \ \ #在访问节点写入hosts解析记录,由于ingress-controller运行再node2节点,所以hosts要写成node2的节点IP地址 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.158.17 nginx.jx.com ##测试,只能使用域名访问 \[root@k8s-master01 ingress-controller\]# curl nginx.jx.com:31502 \ \ \ \ Welcome to nginx!\ \ \ \ \Welcome to nginx!\
\If you see this page, the nginx web server is successfully installed and working. Further configuration is required.\
\For online documentation and support please refer to \nginx.org\.\
\
Commercial support is available at \nginx.com\.\\Thank you for using nginx.\\
\ \
ingress service配置解析
externalTrafficPolicy: Local
含义
externalTrafficPolicy: Local 表示来自集群外部的流量只会被路由到运行有服务后端 Pod 的节点上。
工作原理
-
当外部请求到达某个节点的 NodePort 时:
-
如果该节点上有服务对应的 Pod 在运行,请求会被转发到本地的 Pod
-
如果该节点上没有服务对应的 Pod,请求会被丢弃(返回 TCP RST)
-
-
特点:
-
保留原始客户端 IP(不会做 SNAT)
-
可能导致流量分布不均(只有有 Pod 的节点才会接收流量)
-
适合需要保留客户端源 IP 的场景
-
internalTrafficPolicy: Cluster
含义
internalTrafficPolicy: Cluster 表示来自集群内部的流量会被均匀分配到所有可用的后端 Pod,无论这些 Pod 运行在哪个节点上。
工作原理
-
当集群内部的服务请求发生时:
-
请求会被均匀分配到所有健康的 Pod
-
不考虑 Pod 所在的节点位置
-
-
特点:
-
提供更好的负载均衡
-
可能导致跨节点流量(pod 在节点 A,请求来自节点 B)
-
默认行为
-
2.3 验证-LoadBalancer模式
修改ARP模式,启用严格ARP模式
执行修改操作
kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e "s/strictARP: false/strictARP: true/" | \
kubectl apply -f - -n kube-system#或者
kubectl get configmap kube-proxy -n kube-system -o yaml | sed -e "s/strictARP: false/strictARP: true/" | kubectl apply -f - -n kube-system
#查看修改结果
kubectl edit configmap -n kube-system kube-proxy
为什么要修改严格模式?
-
避免 ARP 冲突
-
在默认情况下,容器网络可能会出现一些非预期的 ARP 行为。在 Load Balancer 模式下,流量需要准确地被分发到后端的 Pod。如果不启用严格 ARP 模式,可能会出现多个 Pod 响应同一个 ARP 请求的情况。
-
例如,假设在一个集群中有多个 Pod 提供相同的服务,并且它们在同一个子网中。如果没有严格的 ARP 控制,负载均衡器可能会收到来自多个 Pod 的 ARP 响应,导致流量分发混乱,影响服务的正常运行。
-
-
确保流量正确分发
-
严格 ARP 模式可以确保只有正确的后端 Pod 响应 ARP 请求。这样,负载均衡器能够准确地将流量发送到预期的 Pod。
-
以一个 Web 应用程序为例,当外部用户通过负载均衡器访问该应用时,负载均衡器需要将请求发送到正确的 Web 服务器 Pod。通过启用严格 ARP 模式,就像是给每个 Pod 一个 "专属标签",只有拥有该标签(正确 MAC 地址)的 Pod 才会响应 ARP 请求,从而保证请求能够准确无误地到达提供服务的 Pod。
-
-
增强网络安全性和稳定性
-
限制 ARP 响应可以防止恶意的 Pod 或者受到攻击的 Pod 干扰网络通信。如果一个被入侵的 Pod 随意响应 ARP 请求,可能会导致中间人攻击或者流量劫持等安全问题。
-
严格 ARP 模式可以防止这种情况的发生,使得网络通信更加安全和稳定。例如,在一个多租户的 Kubernetes 集群环境中,不同租户的 Pod 之间通过严格的 ARP 模式来隔离网络通信,避免租户之间的相互干扰和安全威胁。
-
搭建metallb支持LoadBalancer
Metallb 在 Kubernetes 中的作用主要是为没有运行在如 AWS、GCP 等具有完善网络服务的云平台上的集群,提供网络负载均衡器的实现。
-
实现 LoadBalancer 服务类型:在 Kubernetes 中,Service 有多种类型,其中 LoadBalancer 类型通常需要外部的负载均衡器支持。Metallb 可以在缺乏原生云平台负载均衡支持的环境下,模拟实现 LoadBalancer 类型的 Service。它能够为应用提供可从集群外部访问的固定 IP 地址。
-
IP 地址分配与管理:负责在指定的 IP 地址范围(IP address pool)内,为 LoadBalancer 类型的 Service 分配 IP 地址,并确保这些 IP 地址的正确映射和管理,使外部流量能够准确地路由到相应的 Kubernetes 服务后端 Pod。
-
提供高可用的网络连接:通过实现 BGP(Border Gateway Protocol)或 Layer2 模式的负载均衡机制,确保即使在节点故障或网络波动的情况下,也能维持应用的外部网络连接的稳定性和可靠性。
#版本
metallb-0.14.8
cd /root/metallb-0.14.8/config/manifests
kubectl apply -f metallb-native.yaml
##编写地址段分配configmap
#创建IP地址池
cat > IPAddressPool.yaml<<EOF
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: planip-pool #这里与下面的L2Advertisement的ip池名称需要一样
namespace: metallb-system
spec:
addresses:
- 192.168.158.135-192.168.158.150 #自定义ip段
EOF
#关联IP地址池
cat >L2Advertisement.yaml<<EOF
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: planip-pool
namespace: metallb-system
spec:
ipAddressPools:- planip-pool #这里需要跟上面ip池的名称保持一致
EOFkubectl apply -f IPAddressPool.yaml
kubectl apply -f L2Advertisement.yamlroot@k8s-master01 manifests\]# kubectl -n metallb-system get pod NAME READY STATUS RESTARTS AGE controller-7476b58756-q7cql 1/1 Running 0 6m speaker-55l64 1/1 Running 0 6m speaker-8jjg8 1/1 Running 0 6m1s
普通的service测试
root@k8s-master01 ingress-controller\]# cat nginx.yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app: nginx-deploy1 name: nginx-deploy1 spec: replicas: 3 selector: matchLabels: app: nginx-deploy1 template: metadata: labels: app: nginx-deploy1 spec: containers: - image: nginx imagePullPolicy: IfNotPresent name: nginx1 ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: labels: app: nginx-deploy1 name: nginx-svc1 spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx-deploy1 type: LoadBalancer ###### 无所谓是什么类型 ##提交 \[root@k8s-master01 ingress-controller\]# kubectl apply -f nginx.yaml ##查看 \[root@k8s-master01 ingress-controller\]# kubectl get pod NAME READY STATUS RESTARTS AGE nginx-deploy-5f87d95c-7ph78 1/1 Running 0 50m nginx-deploy-5f87d95c-dswvq 1/1 Running 0 50m nginx-deploy-5f87d95c-vk9vg 1/1 Running 0 50m nginx-deploy1-c8d58b5c7-7dfrd 1/1 Running 0 12m nginx-deploy1-c8d58b5c7-d2hd7 1/1 Running 0 12m nginx-deploy1-c8d58b5c7-pfvhn 1/1 Running 0 12m \[root@k8s-master ingress\]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 \
443/TCP 8d nginx-svc ClusterIP 10.110.232.77 \ 80/TCP 95m nginx-svc1 LoadBalancer 10.107.207.235 192.168.158.136 80:30099/TCP 10m ##测试访问 \[root@k8s-master01 ingress-controller\]# curl 192.168.158.136 \ \ \ \ Welcome to nginx!\ \ \ \ \Welcome to nginx!\
\If you see this page, the nginx web server is successfully installed and working. Further configuration is required.\
\For online documentation and support please refer to \nginx.org\.\
\
Commercial support is available at \nginx.com\.\\Thank you for using nginx.\\
\ \ apiVersion: networking.k8s.io/v1 kind: Ingress # 创建一个类型为Ingress的资源 metadata: name: nginx-ingress # 这个资源的名字为 nginx-ingress spec: ingressClassName: nginx # 使用nginx rules: - host: nginx.jx.com # 访问此内容的域名 http: paths: - backend: service: name: nginx-svc # 对应nginx的服务名字 port: number: 80 # 访问的端口 path: / # 匹配规则 pathType: Prefix # 匹配类型,这里为前缀匹配 - host: nginx2.jx.com # 访问此内容的域名 http: paths: - backend: service: name: nginx-svc1 # 对应nginx的服务名字 port: number: 80 # 访问的端口 path: / # 匹配规则 pathType: Prefix # 匹配类型,这里为前缀匹配
修改ingress模式:
root@k8s-master01 \~\]# kubectl -n ingress-nginx edit svc ingress-nginx-controller type: LoadBalancer status: loadBalancer: {}
ingress访问测试:
使用域名直接访问即可!!!
curl nginx.jx.com
curl nginx2.jx.com