1.1 Ingress介绍
-
Kubernetes 集群中,服务(Service)是一种抽象,它定义了一种访问 Pod 的方式,无论这些 Pod 如何变化,服务都保持不变。服务可以被映射到一个静态的 IP 地址(ClusterIP)、一个 NodePort(在集群的每个节点上的特定端口)、一个 LoadBalancer(通过云服务提供商的负载均衡器)或一个外部 IP。
-
Service的两种服务暴露方式,NodePort 和 LoadBalancer,确存在一些局限性:
-
NodePort:当一个服务被配置为 NodePort 类型时,它会在集群的所有节点上的一个静态端口上暴露服务。这种方式的缺点是,如果集群中有大量的服务,那么就需要占用大量的端口,而这些端口资源是有限的。
-
LoadBalancer:这种方式通过云服务提供商的负载均衡器来暴露服务。虽然它解决了 NodePort 方式中端口资源有限的问题,但是每个服务都需要一个单独的负载均衡器,这不仅增加了成本,而且管理起来也相对复杂。
-
-
为了解决这些问题,Kubernetes 引入了 Ingress 资源对象:
-
Ingress 是一种 API 对象,它管理外部访问到集群内服务的 HTTP 和 HTTPS 路由。它提供了一种规则,允许你将外部 HTTP/HTTPS 路由到集群内的多个服务。
-
Ingress 可以提供单一的 IP 地址,通过不同的 URL 路径或不同的端口来路由到不同的服务。
-
它只需要一个 NodePort 或者一个 LoadBalancer,就可以将多个服务暴露给外部网络,这样做既节省了资源,又简化了配置。
-
Ingress 还支持 SSL/TLS 终止,可以为不同的服务配置 SSL 证书。
-
它允许更复杂的路由规则,比如基于路径、主机名或 HTTP 头部的路由。
-
-
实际上,Ingress相当于一个7层的负载均衡器,是kubernetes对反向代理的一个抽象,它的工作原理类似于Nginx,可以理解成在Ingress里建立诸多映射规则,Ingress Controller通过监听这些配置规则并转化成Nginx的反向代理配置 , 然后对外部提供服务。在这里有两个核心概念:
-
ingress:kubernetes中的一个对象,作用是定义请求如何转发到service的规则
-
ingress controller:具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,根据配置的规则来实现请求转发,实现方式有很多,比如Nginx, Contour, Haproxy等等
-
-
Ingress(以Nginx为例)的工作原理:
-
定义路由规则:用户通过 Kubernetes API 创建 Ingress 规则,指定域名与集群内服务的映射关系。
-
感知规则变化:Ingress 控制器(如基于 Nginx)实时监控 Kubernetes API,以便发现 Ingress 规则的更新。
-
生成配置:一旦检测到变化,Ingress 控制器自动生成相应的 Nginx 配置,以实现定义的路由规则。
-
更新 Nginx 配置:新生成的 Nginx 配置被应用到运行中的 Nginx 实例,无需重启服务即可动态更新路由规则。
-
流量转发:Nginx 作为反向代理,根据更新的配置,将外部请求转发到集群内正确的服务。
-
SSL/TLS 终止(可选):如果配置了 SSL/TLS,Nginx 还可以在转发前终止加密连接,提高安全性和效率。
-
1.2 Ingress安装部署
-
GitHub地址:GitHub - kubernetes/ingress-nginx: Ingress-NGINX Controller for Kubernetes
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.1.6 | 1.29, 1.28, 1.27, 1.26, 1.25 | 3.19.0 | 1.21.6 | 4.1.1* |
🔄 | v1.1.5 | 1.28, 1.27, 1.26, 1.25 | 3.18.4 | 1.21.6 | 4.1.0* |
🔄 | v1.1.4 | 1.28, 1.27, 1.26, 1.25 | 3.18.4 | 1.21.6 | 4.8.3 |
🔄 | v1.1.3 | 1.28, 1.27, 1.26, 1.25 | 3.18.4 | 1.21.6 | 4.8.* |
🔄 | v1.1.1 | 1.28, 1.27, 1.26, 1.25 | 3.18.4 | 1.21.6 | 4.8.* |
🔄 | v1.1.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 |
[root@K8s-master-01 ~]# wget -c https://gitee.com/kong-xiangyuxcz/svn/releases/download/ingress-nginx-controller-v1.10.1/deploy.yaml [root@k8s-master-01 ~]# sed -i 's#registry.k8s.io/ingress-nginx/controller:v1.10.1.*#registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.10.1#' deploy.yaml [root@k8s-master-01 ~]# sed -i 's#registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.4.1.*#registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.4.1#g' deploy.yaml [root@k8s-master-01 ~]# sed -i '345 a \ annotations: \ lb.kubesphere.io/v1alpha1: openelb \ protocol.openelb.kubesphere.io/v1alpha1: layer2 \ eip.openelb.kubesphere.io/v1alpha2: eip-pool' deploy.yaml [root@k8s-master-01 ~]# vim deploy.yaml 372 apiVersion: v1 #匹配到第二个Service,添加HTTP 373 kind: Service 374 metadata: 375 labels: 376 app.kubernetes.io/component: controller 377 app.kubernetes.io/instance: ingress-nginx 378 app.kubernetes.io/name: ingress-nginx 379 app.kubernetes.io/part-of: ingress-nginx 380 app.kubernetes.io/version: 1.10.1 381 name: ingress-nginx-controller-admission 382 namespace: ingress-nginx 383 spec: 384 ports: - appProtocol: http name: http port: 80 protocol: TCP targetPort: http 390 - appProtocol: https 391 name: https-webhook 392 port: 443 [root@k8s-master-01 ~]# sed -i 's/ClusterIP/NodePort/' deploy.yaml # 设置暴露端口
-
部署
# 手动把镜像拉下来,自己拉可能会失败 $ docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.10.1 $ docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.4.1 [root@K8s-master-01 ~]# kubectl apply -f deploy.yaml [root@k8s-master-01 ~]# kubectl get svc,pod -n ingress-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/ingress-nginx-controller LoadBalancer 10.109.90.36 192.168.110.200 80:30397/TCP,443:32205/TCP 86s service/ingress-nginx-controller-admission NodePort 10.111.97.151 <none> 80:31410/TCP,443:32380/TCP 86s NAME READY STATUS RESTARTS AGE pod/ingress-nginx-admission-create-2bvsj 0/1 Completed 0 86s pod/ingress-nginx-admission-patch-66khb 0/1 Completed 0 86s pod/ingress-nginx-controller-676c7b59c4-wsvfc 1/1 Running 0 86s # 注意eip-pool必须提前配好,OpenELB提前要有,具体配置见8.4.6.2
1.3 Ingress暴露服务的方式
1.3.1 Deployment + LoadBalancer 模式的 Service
-
适用场景:适用于公有云环境,尤其是那些支持自动创建负载均衡器并绑定公网地址的云平台。
-
工作原理:使用 Deployment 部署 Ingress Controller,并创建一个类型为 LoadBalancer 的 Service 关联这些 Pods。大部分公有云平台会自动为 LoadBalancer 类型的 Service 创建一个负载均衡器,并绑定公网地址。
-
优势:简单易用,只需配置 DNS 讲解析指向负载均衡器的地址即可实现服务的对外暴露。
-
参考资料:OpenELB 配置示例。见service详解
1.3.1.1 配置Deployment + LoadBalancer 模式的 Service
-
环境
[root@k8s-master-01 ~]# kubectl get svc -n test # 准备好一个LoadBalancer类型的service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE svc-lb LoadBalancer 10.101.43.178 192.168.110.201 80:31545/TCP 27m
-
创建Ingress
[root@k8s-master-01 ~]# vim ingress-dep_lb.yaml --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx-ingress namespace: test spec: ingressClassName: nginx rules: - host: www.kxyctl.com http: paths: - path: / pathType: Prefix backend: service: name: svc-lb port: number: 80 [root@k8s-master-01 ~]# kubectl apply -f ingress-dep_lb.yaml ingress.networking.k8s.io/nginx-ingress created [root@k8s-master-01 ~]# kubectl get ingress -n test NAME CLASS HOSTS ADDRESS PORTS AGE nginx-ingress nginx www.kxyctl.com 192.168.110.200 80 86s
-
测试
[root@k8s-master-01 ~]# echo '192.168.110.200 www.kxyctl.com' >> /etc/hosts [root@k8s-master-01 ~]# for ((i=0;i<=6;i++)) do curl www.kxyctl.com; done 10.244.44.197 web-03 10.244.154.198 web-01 10.244.44.197 web-03 10.244.44.197 web-03 10.244.154.197 web-02 10.244.154.197 web-02 10.244.154.198 web-01
1.3.2 DaemonSet + HostNetwork + NodeSelector
-
适用场景:适用于需要高性能和低延迟的场景,例如大并发生产环境。
-
工作原理:使用 DaemonSet 和 NodeSelector 将 Ingress Controller 部署到特定的节点上,然后使用 HostNetwork 功能直接将 Pod 与宿主机的网络打通,直接使用宿主机的 80/443 端口访问服务。
-
优势:整个请求链路最简单,性能相对 NodePort 模式更好。缺点是由于直接利用宿主机节点的网络和端口,一个节点只能部署一个 Ingress Controller Pod。
-
适用场景:比较适合大并发的生产环境使用。
-
使用 DaemonSet 结合 nodeselector 来部署 ingress-controller 到特定的 node 上,然后使用 HostNetwork 直接把该 pod 与宿主机 node 的网络打通,直接使用宿主机的 80/443 端口就能访问服务,这种方式确实有其独特的优点和缺点。
特性 | 描述 |
---|---|
请求链路简单 | 直接使用宿主机的网络和端口,请求链路直观且简单,无额外跳板。 |
性能优越 | 相比 NodePort 模式,减少网络跳转次数和处理开销,性能更佳。 |
单一节点限制 | 一个 node 只能部署一个 ingress-controller pod,扩展服务需要增加节点。 |
灵活性降低 | 难以实现跨多个节点的负载均衡和故障转移策略。 |
适用场景 | 高性能和低延迟需求的大并发生产环境,希望最大限度利用宿主机资源减少网络开销。 |
-
这种部署方式通过直接利用宿主机的网络和端口,将 ingress-controller 的部署变得更加简单和高效,同时也带来了性能上的提升。然而,由于这种方式的单一节点限制和灵活性降低,可能并不适合所有场景,特别是那些需要高度可扩展性和弹性的场景。
1、指定nginx-ingress-controller运行在node2节点 [root@k8s-master-01 ~]# kubectl label node k8s-node-01 ingress=true node/k8s-node-01 labeled 2、修改Deployment为DaemonSet,指定节点运行,并开启 hostNetwork [root@k8s-master-01 ~]# kubectl delete -f deploy.yaml [root@k8s-master-01 ~]# cp deploy.yaml deploy_daemonset.yaml [root@k8s-master-01 ~]# sed -i 's/Deployment/DaemonSet/' deploy_daemonset.yaml # Deployment改为DaemonSet [root@k8s-master-01 ~]# vim deploy.yaml # Daemonset下修改 419 # strategy: 420 # rollingUpdate: 421 # maxUnavailable: 1 422 # type: RollingUpdate 473 ports: 474 - containerPort: 80 475 name: http 476 protocol: TCP 477 hostPort: 80 478 - containerPort: 443 479 name: https 480 protocol: TCP 481 hostPort: 443 516 nodeSelector: 517 #kubernetes.io/os: linux 518 ingress: "true" 519 hostNetwork: true 3、部署 [root@k8s-master-01 ~]# kubectl apply -f deploy.yaml [root@k8s-master-01 ~]# kubectl get pod -n ingress-nginx -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES ingress-nginx-admission-create-wb4s7 0/1 Completed 0 29s 10.244.154.195 k8s-node-01 <none> <none> ingress-nginx-admission-patch-55282 0/1 Completed 0 29s 10.244.154.196 k8s-node-01 <none> <none> ingress-nginx-controller-lsnz9 1/1 Running 0 29s 10.244.154.197 k8s-node-01 <none> <none> # 这里如果是pending那就是443端口被占用了,换个节点试就行
-
Ingress配置
[root@k8s-master-01 ~]# vim ingress-dep_ds.yaml --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx-ingress namespace: test spec: ingressClassName: nginx rules: - host: www.kxyctl.com http: paths: - path: / pathType: Prefix backend: service: name: svc-lb port: number: 80 [root@k8s-master-01 ~]# kubectl get svc,ing,pod -n test NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/svc-lb LoadBalancer 10.104.99.81 192.168.110.201 80:31468/TCP 43m service/svc-nodeport NodePort 10.96.103.97 <none> 80:32522/TCP 42m NAME CLASS HOSTS ADDRESS PORTS AGE nginx-ingress nginx www.kxyctl.com 192.168.110.200 80 86s NAME READY STATUS RESTARTS AGE pod/pc-deployment-5cb65f68db-kj4qf 1/1 Running 0 40m pod/pc-deployment-5cb65f68db-ph7rz 1/1 Running 0 40m pod/pc-deployment-5cb65f68db-thwb6 1/1 Running 0 40m
-
测试
[root@k8s-master-01 ~]# for ((i=0;i<=6;i++)) do curl www.kxyctl.com; done 10.244.44.199 DaemonSet + HostNetwork + NodeSelector-03 10.244.44.198 DaemonSet + HostNetwork + NodeSelector-02 10.244.44.199 DaemonSet + HostNetwork + NodeSelector-01 10.244.44.198 DaemonSet + HostNetwork + NodeSelector-01 10.244.154.199 DaemonSet + HostNetwork + NodeSelector-02 10.244.154.199 DaemonSet + HostNetwork + NodeSelector-03 10.244.44.199 DaemonSet + HostNetwork + NodeSelector-01
1.3.3 Deployment + NodePort 模式的 Service
-
适用场景:适用于宿主机 IP 地址相对固定,不太可能频繁变动的环境。
-
工作原理:使用 Deployment 部署 Ingress Controller,并创建一个类型为 NodePort 的 Service。这样,Ingress 就会暴露在集群节点 IP 的特定端口上。
-
优势:简单方便,NodePort 暴露的端口是随机的,但可以通过负载均衡器转发请求。
-
缺点:NodePort 多了一层 NAT,在请求量级很大的时候可能对性能会有一定影响。
1.3.3.1 Deployment + NodePort 模式的 Service配置
-
环境
[root@k8s-master-01 ~]# kubectl get svc -n test | grep NodePort # 准备好一个nodeport类型的Service svc-nodeport NodePort 10.97.216.108 <none> 80:32522/TCP 17s
-
Ingress配置
[root@k8s-master-01 ~]# vim ingress-dep_np.yaml --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx-ingress namespace: test spec: ingressClassName: nginx rules: - host: www.kxyctl.cn http: paths: - path: / pathType: Prefix backend: service: name: svc-nodeport port: number: 80 [root@k8s-master-01 ~]# sed -i 's/www.kxyctl.com/www.kxyctl.cn/' /etc/hosts [root@k8s-master-01 ~]# kubectl apply -f ingress-dep_np.yaml ingress.networking.k8s.io/nginx-ingress created [root@k8s-master-01 ~]# kubectl get ingress -n test NAME CLASS HOSTS ADDRESS PORTS AGE nginx-ingress nginx www.kxyctl.cn 192.168.110.200 80 38s
-
测试
[root@k8s-master-01 ~]# for ((i=0;i<=6;i++)) do curl www.kxyctl.cn; done 10.244.44.199 Deployment + NodePort-03 10.244.44.198 Deployment + NodePort-02 10.244.44.199 Deployment + NodePort-03 10.244.44.198 Deployment + NodePort-02 10.244.154.199 Deployment + NodePort-01 10.244.154.199 Deployment + NodePort-01 10.244.44.199 Deployment + NodePort-03
1.4 Ingress应用
1.4.1 Ingress的HTTP代理
-
准备service和pod为了后面的实验比较方便,创建如下图所示的模型
-
创建tomcat-nginx.yaml
[root@k8s-master-01 ~]# vim tomcat-nginx.yaml --- apiVersion: apps/v1 kind: Deployment metadata: name: tomcat-deployment namespace: test spec: replicas: 3 selector: matchLabels: app: tomcat-pod template: metadata: labels: app: tomcat-pod spec: containers: - name: tomcat image: tomcat:8.5-jre10-slim ports: - containerPort: 8080 --- apiVersion: v1 kind: Service metadata: name: tomcat-service namespace: test annotations: lb.kubesphere.io/v1alpha1: openelb protocol.openelb.kubesphere.io/v1alpha1: layer2 eip.openelb.kubesphere.io/v1alpha2: eip-pool spec: selector: app: tomcat-pod type: LoadBalancer ports: - port: 80 targetPort: 8080 [root@k8s-master-01 ~]# kubectl apply -f tomcat-nginx.yaml deployment.apps/tomcat-deployment unchanged service/tomcat-service created [root@k8s-master-01 ~]# kubectl get service -n test NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE svc-lb LoadBalancer 10.104.99.81 192.168.110.201 80:31468/TCP 57m svc-nodeport NodePort 10.96.103.97 <none> 80:32522/TCP 56m tomcat-service LoadBalancer 10.103.51.78 192.168.110.202 8080:31609/TCP 54s [root@k8s-master-01 ~]# kubectl get pod -n test NAME READY STATUS RESTARTS AGE pc-deployment-5cb65f68db-kj4qf 1/1 Running 0 65m pc-deployment-5cb65f68db-ph7rz 1/1 Running 0 65m pc-deployment-5cb65f68db-thwb6 1/1 Running 0 65m tomcat-deployment-7ff7bd5bcd-9q8gk 1/1 Running 0 15m tomcat-deployment-7ff7bd5bcd-ghvzm 1/1 Running 0 15m tomcat-deployment-7ff7bd5bcd-s6hrb 1/1 Running 0 15m
-
Ingress配置
[root@k8s-master-01 ~]# vim ingress-dep_lb.yaml --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx-ingress namespace: test spec: ingressClassName: nginx rules: - host: www.kxyctl.com http: paths: - path: / pathType: Prefix backend: service: name: svc-lb port: number: 80 - host: tomcat.kxyctl.com http: paths: - path: / pathType: Prefix backend: service: name: tomcat-service port: number: 80 [root@k8s-master-01 ~]# kubectl apply -f ingress-dep_lb.yaml ingress.networking.k8s.io/nginx-ingress created [root@k8s-master-01 ~]# kubectl get service,ingress -n test NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/svc-lb LoadBalancer 10.104.99.81 192.168.110.201 80:31468/TCP 63m service/svc-nodeport NodePort 10.96.103.97 <none> 80:32522/TCP 62m service/tomcat-service LoadBalancer 10.103.51.78 192.168.110.202 8080:31609/TCP 6m45s NAME CLASS HOSTS ADDRESS PORTS AGE ingress.networking.k8s.io/nginx-ingress nginx www.kxyctl.com,tomcat.kxyctl.com 192.168.110.200 80 62s # Windows添加Hosts解析,192.168.110.202 tomcat.kxyctl.com 访问:http://tomcat.kxyctl.com/
1.4.2 Ingress的HTTPS代理
-
创建证书和密钥
[root@k8s-master-01 ~]# 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=itopenlab.com" Generating a 2048 bit RSA private key ..+++ ......................................+++ writing new private key to 'tls.key' ----- [root@k8s-master-01 ~]# kubectl create secret tls tls-secret --key tls.key --cert tls.crt secret/tls-secret created
-
创建ingress-https.yaml
[root@k8s-master-01 ~]# vim ingress-https.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-https namespace: test spec: tls: - hosts: - nginx.kxyctl.com - tomcat.kxyctl.com secretName: tls-secret # 指定秘钥 rules: - host: nginx.kxyctl.com http: paths: - path: / pathType: Prefix backend: service: name: nginx-service port: number: 80 - host: tomcat.kxyctl.com http: paths: - path: / pathType: Prefix backend: service: name: tomcat-service port: number: 8080 [root@k8s-master-01 ~]# kubectl apply -f ingress-https.yaml ingress.networking.k8s.io/ingress-https created [root@k8s-master-01 ~]# kubectl get ing ingress-https -n test NAME CLASS HOSTS ADDRESS PORTS AGE ingress-https <none> nginx.itopenlab.com,tomcat.itopenlab.com 80, 443 9s [root@k8s-master-01 ~]# kubectl describe ing ingress-https -n test Name: ingress-https Labels: <none> Namespace: test Address: Ingress Class: <none> Default backend: <default> TLS: tls-secret terminates nginx.kxyctl.com,tomcat.kxyctl.com Rules: Host Path Backends ---- ---- -------- nginx.kxyctl.com / nginx-service:80 (<error: endpoints "nginx-service" not found>) tomcat.kxyctl.com / tomcat-service:8080 (10.244.154.206:8080,10.244.44.215:8080,10.244.44.216:8080) Annotations: <none> Events: <none>