假設有如下三個節點的?K8S?集群:
?
k8s31master 是控制節點
k8s31node1、k8s31node2?是工作節點
容器運行時是 containerd
一、理論介紹
1)什么是 Ingress
- 定義:Ingress 是 Kubernetes 中的一種資源對象,它定義了外部訪問集群內服務的規則。可以將其理解為一個智能的 “流量路由器”,根據接收到的 HTTP/HTTPS 請求的不同規則,將流量轉發到集群內不同的服務上。
- 作用
- 統一入口:為集群內的多個服務提供一個統一的外部入口點,使得外部用戶可以通過一個固定的 IP 地址或域名來訪問不同的服務,而不需要為每個服務都暴露獨立的 IP 和端口。
- 規則定義:支持基于域名、URL 路徑等條件來定義路由規則。例如,可以配置讓域名 www.example.com 的請求被路由到服務 A,而 api.example.com 的請求被路由到服務 B。還能根據 URL 路徑進行更精細的路由,如?/app1/* 路徑的請求轉發到服務 C,/app2/* 路徑的請求轉發到服務 D。
2)什么是?IngressController
- 定義:Ingress Controller 是實際負責執行 Ingress 資源中定義的路由規則的組件。它是一個運行在 Kubernetes 集群中的服務,通常以 Pod 的形式存在,不斷監聽 Ingress 資源的變化,并根據最新的規則來配置和更新負載均衡器或代理服務器。
- 作用
- 流量轉發:根據 Ingress 規則,將接收到的外部流量準確地轉發到對應的后端服務。它會與底層的網絡基礎設施進行交互,實現數據包的正確路由。
- 負載均衡:在將流量轉發到后端服務時,Ingress Controller 可以實現負載均衡功能,將請求均勻地分配到多個后端 Pod 上,以提高服務的可用性和性能。常見的負載均衡算法有輪詢、加權輪詢、最少連接數等。
- 安全防護:許多 Ingress Controller 還支持 TLS/SSL 加密功能,用于對傳輸中的數據進行加密,確保通信安全。同時,它也可以進行一些基本的安全防護,如防止常見的網絡攻擊。
- 常見類型
- Nginx Ingress Controller:基于 Nginx 服務器的 Ingress Controller,具有高性能、豐富的功能和良好的穩定性,廣泛應用于 Kubernetes 集群中。
- Traefik Ingress Controller:專注于提供自動化的服務發現和動態配置功能,能夠根據 Kubernetes 集群中的服務和端點的變化自動更新路由規則。
- HAProxy Ingress Controller:基于 HAProxy 負載均衡器,具有出色的性能和可靠性,適用于大規模流量的場景。
3)局限性
4)總結
簡單點說,Ingress 類似于 nginx 的配置文件,它里面定義了路由規則。
IngressController 類似于?nginx,它不斷監聽 Ingress 資源的變化,并根據最新的規則來配置和更新它所包裝的負載均衡器或代理服務器。
二、安裝?Ingress Nginx Controller
Ingress-Nginx GitHub:https://github.com/kubernetes/ingress-nginx
裸金屬部署yml:https://github.com/kubernetes/ingress-nginx/blob/release-1.12/deploy/static/provider/baremetal/deploy.yaml
-
版本兼容性
因為我的 K8S 是 1.31,所以?Ingress-Nginx 可以選擇 1.12.2、1.12.1、1.12.0。
-
?裸金屬
baremetal:
適用于 裸金屬(Bare Metal)或本地環境(如物理服務器、本地 Kubernetes 集群、無云廠商集成的環境)。通常需要手動管理外部訪問(如 NodePort、HostNetwork 或外部負載均衡器)。依賴 Kubernetes 的 NodePort 或 LoadBalancer 類型 Service,但需要自行配置外部負載均衡(如 MetalLB、HAProxy 等)。
-
?鏡像準備
整個部署只依賴兩個鏡像:
registry.k8s.io/ingress-nginx/controller:v1.12.2
registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.5.3
找個國內的鏡像站,提前下載好鏡像。
[root@k8s31node1 ~]# ctr -n=k8s.io images pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/registry.k8s.io/ingress-nginx/controller:v1.12.2
[root@k8s31node1 ~]# ctr -n=k8s.io images tag swr.cn-north-4.myhuaweicloud.com/ddn-k8s/registry.k8s.io/ingress-nginx/controller:v1.12.2 registry.k8s.io/ingress-nginx/controller:v1.12.2
# 查看導入情況
[root@k8s31node1 ~]# crictl images ls|grep ingress
[root@k8s31node1 ~]# ctr -n=k8s.io images pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.5.3
[root@k8s31node1 ~]# ctr -n=k8s.io images tag swr.cn-north-4.myhuaweicloud.com/ddn-k8s/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.5.3 registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.5.3
# 查看導入情況
[root@k8s31node1 ~]# crictl images ls|grep webhook[root@k8s31node2 ~]# ctr -n=k8s.io images pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/registry.k8s.io/ingress-nginx/controller:v1.12.2
[root@k8s31node2 ~]# ctr -n=k8s.io images tag swr.cn-north-4.myhuaweicloud.com/ddn-k8s/registry.k8s.io/ingress-nginx/controller:v1.12.2 registry.k8s.io/ingress-nginx/controller:v1.12.2
# 查看導入情況
[root@k8s31node2 ~]# crictl images ls|grep ingress
[root@k8s31node2 ~]# ctr -n=k8s.io images pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.5.3
[root@k8s31node2 ~]# ctr -n=k8s.io images tag swr.cn-north-4.myhuaweicloud.com/ddn-k8s/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.5.3 registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.5.3
# 查看導入情況
[root@k8s31node2 ~]# crictl images ls|grep webhook
-
?修改 deploy.yml
- 修改鏡像名稱與拉取策略
image: registry.k8s.io/ingress-nginx/controller:v1.12.2 # 優先拉取本地鏡像 imagePullPolicy: IfNotPresent image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.5.3 # 優先拉取本地鏡像 imagePullPolicy: IfNotPresent
- 修改 Deployment 副本數
根據工作節點個數,修改副本數。
- 增加 Pod 反親和性
affinity:podAntiAffinity:preferredDuringSchedulingIgnoredDuringExecution:- weight: 100podAffinityTerm:labelSelector:matchLabels:app.kubernetes.io/name: ingress-nginxtopologyKey: kubernetes.io/hostname
使用主機名作為 邏輯拓撲鍵,通過 Pod 反親和性,讓多個 Pod 部署在不同的節點上。
- 使用主機網絡
hostNetwork: true dnsPolicy: ClusterFirstWithHostNet
hostNetwork 作用:hostNetwork 是 Pod 規范中的一個配置選項,它控制 Pod 如何使用網絡命名空間。當設置為 true 時,Pod 將直接使用宿主機(Node)的網絡棧,而不是創建獨立的網絡命名空間。
當你設置 hostNetwork: true 時,Pod 將與宿主機共享這些網絡資源,這意味著:
????????Pod 內的應用程序將使用宿主機的 IP 地址
????????Pod 內的服務監聽的端口將直接暴露在宿主機上
????????Pod 可以直接訪問宿主機上的網絡設備和網絡配置
ClusterFirstWithHostNet 作用:當 Pod 使用主機網絡(即 hostNetwork: true)時,此策略強制 Pod 使用集群 DNS 服務(CoreDNS)進行解析,而不是繼承 Node 節點的 DNS 配置。 適用場景:適用于使用主機網絡但仍需要訪問集群內部服務的 Pod。
- 最后配置如下
-
?查看 ingress-nginx-controller Pod
kubectl get pod -n=ingress-nginx -owide
兩個 ingress-nginx-controller pod 分別部署在 node1、node2,且它們的 IP 共享節點 IP。
-
?查看?ingressClass
kubectl get ingressClass -owide
在 Kubernetes 中,IngressClass 是一個用于管理和配置 Ingress 資源的重要概念。它允許集群管理員定義和區分不同的 Ingress 實現,使得多個 Ingress Controller 可以在同一個集群中共存,并為不同的 Ingress 資源指定特定的控制器。
IngressClass 是一個集群級別的資源,用于定義和配置 Ingress Controller。
它主要包含兩個核心字段:
- controller:指定負責處理該類 Ingress 的控制器名稱(例如 k8s.io/ingress-nginx)。
- parameters(可選):指向一個參數資源,用于配置特定控制器的行為。
三、使用 HTTP 訪問
1)部署后端服務
apiVersion: apps/v1
kind: Deployment
metadata:name: tomcat-deploy
spec:replicas: 2selector:matchLabels:app: tomcattemplate:metadata:labels:app: tomcatspec:containers:- name: tomcatimage: tomcat:8.5-jre8-alpineimagePullPolicy: IfNotPresentports:- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:name: tomcat-svc
spec:type: ClusterIPselector:app: tomcatports:- port: 8080protocol: TCPtargetPort: 8080
使用?Deployment 控制器,部署了兩個 tomcat Pod 并新建了一個?ClusterIP 類型的 Service 代理了這兩個 Pod。
2)編寫 Ingress
# ing ingress 的縮寫
kubectl explain ing
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:name: nginx-ingress
spec:ingressClassName: nginx # 指定使用上面看到的 "nginx" IngressClassrules: # 路由規則- host: tomcat-app.comhttp:paths:- path: /pathType: Prefixbackend:service:name: tomcat-svcport:number: 8080
- ingressClassName: 指定負責處理此 Ingress 的控制器類別(這里是nginx)。
- 路由規則(Rules):
主機規則(Host) host: tomcat-app.com 當外部請求的 HTTP Host 頭為 tomcat-app.com 時,
此規則生效。host? 是網絡主機的完全限定域名。 host 不可以 1、不允許使用 IP 地址。 2、不識別 : 分隔符,因為不允許使用端口。
目前 Ingress 的端口默認為 http 使用 :80,https 使用 :443。
這些在未來可能會改變。host 可以是 "精確" 主機名(例如 "foo.bar.com") "通配符" 主機名:帶單個通配符標簽的域名(例如 ".foo.com")。
通配符字符 * 必須單獨作為第一個 DNS 標簽出現,并且只匹配單個標簽。不能單獨使用通配符標簽(例如 Host == "")。路徑規則(Paths) path: / 匹配所有以/開頭的 URL 路徑(即所有請求)。 pathType: Prefix:? 指定路徑匹配類型為前綴匹配,
即任何以/開頭的路徑都會被匹配(例如/api、/static/js/main.js等)。后端服務(Backend) service.name: tomcat-svc 將匹配的請求轉發到名為 tomcat-svc 的
Kubernetes Service。service.port.number: 8080? 轉發到 Service 的 8080 端口
(與 tomcat-svc.spec.ports.port 相對應)。
- ?整體功能
這個 Ingress 配置的作用是:
- 接收外部請求:當用戶訪問 http://tomcat-app.com 時,請求會首先到達 Nginx Ingress Controller。
- 路由到內部服務:控制器根據規則將請求轉發到名為 tomcat-svc 的 Service 的 8080 端口。
- 負載均衡:Service 會將請求進一步負載均衡到后端的 Tomcat Pod 實例上。
3)修改 Windows hosts 文件
C:\Windows\System32\drivers\etc\hosts
# 192.168.40.20 是節點 k8s31node1 IP
# 這里也可以是 192.168.40.30
192.168.40.20 tomcat-app.com
?4)瀏覽器訪問
http://tomcat-app.com/
?整個請求的過程如圖:
四、使用 HTTPS 訪問
1)準備證書
- 生成私鑰
openssl genrsa -out tls.key 2048
- openssl:它屬于一個功能豐富的加密工具包,能夠支持像密鑰生成、證書簽署等眾多密碼學操作。
- genrsa:此為 openssl 的子命令,專門用于生成 RSA 私鑰。
- -out tls.key:該參數的作用是將生成的私鑰保存到名為 tls.key 的文件中。你可以根據自身需求,把 tls.key 替換成其他文件名。
- 2048:這里的數字代表私鑰的位數。2048 位的私鑰在當前屬于比較安全的配置,能夠有效平衡安全性和性能。
- ?生成自簽名 SSL/TLS 證書
openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=Fujian/L=Xiamen/O=Study/CN=https-tomcat-app.com
- openssl req openssl 的子命令,用于創建和處理證書簽名請求(CSR)。
- -new 生成一個新的證書請求(通常用于向 CA 機構申請證書)。
- -x509 直接生成自簽名證書,而非僅生成 CSR。自簽名證書無需 CA 機構簽名,但瀏覽器會顯示 “不安全” 警告(適用于測試環境)。
- -key tls.key 指定私鑰文件(需提前用 genrsa 命令生成,如之前的 tls.key)。私鑰用于對證書簽名,需妥善保管。
- -out tls.crt 指定輸出的證書文件名(.crt 或 .pem 格式)。
- -subj?/C=CN/ST=Fujian/L=Xiamen/O=Study/CN=https-tomcat-app.com
- 證書的主題信息(Distinguished Name),
- 格式為:
- /C=CN:國家(Country)代碼,如 CN(中國)。
- /ST=Fujian:州 / 省份(State/Province)。
- /L=Xiamen:城市 / 地區(Locality)。
- /O=Study:組織(Organization)。
- /CN=https-tomcat-app.com:域名(Common Name),必須與網站訪問的域名完全一致(否則瀏覽器會報錯)。
2)創建 Secret
- 命令幫助
# 需要創建一個 tls 類型的 Secret
# tls Transport Layer Security
kubectl create secret tls --help
- ?創建 Secret
# 創建 TLS 類型 Secret
kubectl create secret tls nginx-ingress-secret --cert=tls.crt --key=tls.key
# 查看是否創建成功
kubectl get secret
# 查看詳情
kubectl describe secret nginx-ingress-secret
3)編寫 Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:name: tls-nginx-ingress
spec:ingressClassName: nginxtls:- hosts: ["https-tomcat-app.com"]secretName: nginx-ingress-secretrules:- host: https-tomcat-app.comhttp:paths:- path: /pathType: Prefixbackend:service:name: tomcat-svcport:number: 8080
kubectl apply -f tls-ingress.yaml
kubectl get ing
4)修改 Windows hosts 文件
# 192.168.40.30 是節點 k8s31node2 IP
192.168.40.30 https-tomcat-app.com
5)瀏覽器訪問
https://https-tomcat-app.com/
?
五、使用 keepalived + nginx 實現 Ingress 高可用
使用主機網絡 hostNetwork 存在一個問題,那就是客戶端持有的是節點的 IP,倘若節點掛掉之后,客戶端就找不到整個集群的入口了,服務的調用更是無從談起。所以有必要對?Ingress 進行高可用設計。具體方案如下:
- 部署方式
ingress-nginx-controller 根據 Deployment+nodeSelector+Pod 反親和性方式 部署在 k8s 工作節點(前面已實現),ingress-nginx-controller 這些 Pod 共享宿主機IP(hostNetwork ),然后通過 keepalived+nginx 實現 ingress-nginx-controller 高可用。
- 入口
keepalived 幫我們虛擬出 VIP:192.168.40.80 作為入口,域名或主機名解析到這個 VIP
?1)部署?keepalived + nginx
可以看這篇博文。
?2)修改 nginx.conf
配置的路徑基于 yum 安裝的 nginx 目錄:
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;events {worker_connections 1024;
}http {include /etc/nginx/mime.types;default_type application/octet-stream;log_format main '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';access_log /var/log/nginx/access.log main;sendfile on;keepalive_timeout 65;# 定義 ingress-nginx-controller 的 upstream(負載均衡)upstream ingress_backend {# 替換為你的 Kubernetes Node IP + NodePortserver 192.168.40.20:30927; # Node1server 192.168.40.30:30927; # Node2}# HTTP 服務器(80端口 → 強制跳轉 HTTPS)server {listen 80;server_name https-tomcat-app.com;return 301 https://$host$request_uri; }# HTTPS 服務器(443端口 → 代理到 ingress_backend)server {listen 443 ssl;server_name https-tomcat-app.com;# SSL 證書配置(替換為你的證書路徑)ssl_certificate /etc/nginx/ssl/tls.crt;ssl_certificate_key /etc/nginx/ssl/tls.key;# 推薦的安全配置ssl_protocols TLSv1.2 TLSv1.3;ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';ssl_prefer_server_ciphers on;ssl_session_cache shared:SSL:10m;ssl_session_timeout 10m;# 代理到 ingress_backend(負載均衡)location / {proxy_pass https://ingress_backend; # 使用 upstreamproxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";# 可調整緩沖區、超時等proxy_buffer_size 16k;proxy_buffers 4 32k;proxy_connect_timeout 90s;proxy_send_timeout 90s;proxy_read_timeout 90s;}# 錯誤頁面error_page 500 502 503 504 /50x.html;location = /50x.html {root /usr/share/nginx/html;}}
}
- ingress-nginx-controller 443 的 NodePort 是 30927
- 將 4.1 生成的 私鑰跟證書上傳到 nginx1、nginx2 的?/etc/nginx/ssl
3)修改 Windows hosts 文件
# 主機名指向 VIP
192.168.40.80 https-tomcat-app.com
?4)瀏覽器訪問
https://https-tomcat-app.com/
5)云之展望
上面是本地部署的高可用方案,云上的部署其實也是類似。
把本地DNS換成云解析,keepalived + nginx 換成云服務商 LB。