Kubernetes 服務概述
了解不同類型的 Kubernetes 服務和 Ingress 控制器
在 Kubernetes 環境中,您可以擁有數百個甚至數千個臨時 Pod。無論是因為節點縮減、pod 副本縮減,還是 pod 被重新排程到新節點,pod 的 IP 位址永遠無法保證相同。
Pod 的 IP 位址是在它被排程到特定節點之後并且在它被引導之前配置設定的。鑒于我們處于雲原生環境中,我們希望能夠水準擴充 pod。是以,跟蹤我們所有應用程式的所有 IP 位址将是一項非常困難的任務。
Kubernetes 有一種資源類型可以解決這個不斷變化的 pod IP 的問題,稱為服務。
Kubernetes 服務允許您建立一個單一的常量 IP 位址,其中包含一組包含相同服務的 Pod 的 IP 位址。這非常有用,因為服務 IP 保持靜态,而 Pod 的 IP 可以不斷變化。您永遠不必擔心沒有正确的 IP 位址。
服務如何運作
要想了解服務如何運作?首先配置一個service開始。
讓我們首先建立一個包含三個 nginx pod 執行個體的部署。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
應用部署清單後,我們可以看到我們有三個使用 IP 運作的 nginx 執行個體10.244.242.66, 10.244.242.67, 10.244.230,199。另外,請注意我們為這些 pod 配置設定的标簽,app=nginx這對于服務如何監控這些 pod 至關重要。
~ kubectl get pods -owide - show-labels
NAME READY STATUS RESTARTS AGE IP NODE LABELS
nginx-8f458dc5b-6vcxt 1/1 Running 0 2m27s 10.244.242.66 nodepool-a-95e9c8e86208 app=nginx,pod-template-hash=8f458dc5b
nginx-8f458dc5b-ktvtf 1/1 Running 0 2m27s 10.244.242.67 nodepool-a-95e9c8e86208 app=nginx,pod-template-hash=8f458dc5b
nginx-8f458dc5b-mlkwd 1/1 Running 0 2m27s 10.244.230.199 nodepool-a-11aa1dc199fa app=nginx,pod-template-hash=8f458dc5b
現在,讓我們定義我們的服務清單,它在下面定義,并對定義的内容進行細分。
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
selector:
app: nginx
type: ClusterIP
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
當我們開始分解這個清單時,我們注意到類型是Service. 接下來,中繼資料部分應該很熟悉,因為它與其他 Kubernetes 資源上的中繼資料字段相同。規範部分是我們定義我們的服務将如何互動以及與之互動的地方。字段selector 您可以在該字段中定義希望該服務監控哪些 pod。這是通過标簽比對完成的。
你會注意到這selector有一個定義app: nginx。如果您還記得這些是我們在部署清單中為我們的 pod 定義的标簽。通過這個選擇器定義,我們聲明任何帶有标簽的 pod 都app=nginx将成為該服務的一部分。
接下來,我們有type字段。這定義了我們将成為該服務的一部分希望它成為什麼樣的服務。稍後我們将更深入地研究服務類型,但現在我們将其定義為ClusterIP.
最後,我們有ports字段。在這裡,我們定義流量将如何以及在何處流經服務。請注意,此字段接受一個數組,是以您可以定義多個條目。讓我們細分端口中的每個字段:
- name:您可以為給定的端口條目。配置設定一個特定的名稱。
- port:這是服務将偵聽的端口。
- targetPort:這是服務将請求轉發到的端口。這應該與 pod 正在偵聽的端口相比對。
- protocol:您希望服務監聽和互動的特定協定。
現在我們對服務清單的作用以及它如何與 pod 互動有了基本的了解,我們部署清單并檢查服務。
~ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 90m
nginx ClusterIP 10.108.176.62 <none> 80/TCP 18m
☁ ~ kubectl describe svc nginx
Name: nginx
Namespace: default
Labels: app=nginx
Annotations: <none>
Selector: app=nginx
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.108.176.62
IPs: 10.108.176.62
Port: 80-80 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.230.199:80,10.244.242.66:80,10.244.242.67:80
Session Affinity: None
Events: <none>
describe 指令中的所有内容都應與清單定義一緻,除了兩個字段“IP”和“Endpoints”。
該IP字段定義服務 IP 位址。這是可用于通路服務後面的 pod 的靜态 IP。
該Endpoints字段定義目前配置設定給此服務的 pod IP。您注意到這些 IP 是來自我們的 nginx 部署的 IP。
在我們繼續其他服務類型之前,讓我們展示縮減 nginx 部署并檢視該服務将如何處理此更改。
kubectl scale deployment/nginx --replicas 1
deployment.apps/nginx scaled
☁ kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-8f458dc5b-mlkwd 1/1 Running 0 43m 10.244.230.199 nodepool-a-11aa1dc199fa <none> <none>
☁ kubectl describe service nginx | grep Endpoints
Endpoints: 10.244.230.199:80
☁ kubectl scale deployment/nginx --replicas 5
deployment.apps/nginx scaled
☁ kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-8f458dc5b-9pmhb 1/1 Running 0 108s 10.244.242.69 nodepool-a-95e9c8e86208 <none> <none>
nginx-8f458dc5b-mlkwd 1/1 Running 0 47m 10.244.230.199 nodepool-a-11aa1dc199fa <none> <none>
nginx-8f458dc5b-r2pcp 1/1 Running 0 108s 10.244.242.70 nodepool-a-95e9c8e86208 <none> <none>
nginx-8f458dc5b-vgwv6 1/1 Running 0 108s 10.244.242.68 nodepool-a-95e9c8e86208 <none> <none>
nginx-8f458dc5b-x6thl 1/1 Running 0 108s 10.244.230.200 nodepool-a-11aa1dc199fa <none> <none>
☁ kubectl describe service nginx | grep Endpoints
Endpoints: 10.244.230.199:80,10.244.230.200:80,10.244.242.68:80 + 2 more...
您可以看到向上和向下擴充 pod 會立即反映在允許單個靜态 IP 通路 pod 的服務中。
服務種類
在服務資源中,存在三種不同的類型。它們如下:
- 叢集IP
- 節點端口
- 負載均衡器
這些都有自己的行為和特定的用例,是以知道何時使用它們很重要。在接下來的部分中,我們将對其中的每一個進行更深入的探讨。
叢集IP
ClusterIP 是最“基本”的服務類型。它将建立一個靜态 IP 位址,該位址位于與 pod IP 範圍不同的子網上,并将通過标簽選擇器監視一組 pod。
ClusterIP 允許 pod 輕松地互相通信,因為 pod 可以将請求發送到靜态 IP 或使用 Kubernetes DNS 将請求發送到{service-name}.{namespace}. 在前面的示例中,我們部署的 DNS 應該是nginx.default. 使用 ClusterIP 有一些限制。最大的一個是沒有辦法向外界公開這項服務。這是服務類型nodePort和loadBalancer應該使用的地方。
節點端口
該NodePort服務建立在類型之上ClusterIP。它ClusterIP通過在工作節點上打開一個端口來轉發流量來向外界公開。這意味着,如果您有 50 個工作節點,即使 pod 不在該工作節點上,每個工作節點也會偵聽配置設定的端口。
要建立NodePort服務,唯一的差別是定義Type為NodePort.
kind: Service
metadata:
labels:
app: nginx
name: nginx
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
# nodePort: 30001
selector:
app: nginx
type: NodePort
您可能會注意到 被nodePort注釋掉了,這是因為如果您沒有nodePort在該ports部分中定義,Kubernetes 會自動從 range 中配置設定一個随機端口30000–32767。如果你想定義一個特定的端口,它必須從這個範圍内完成。部署 NodePort 服務清單并讓我們檢查它。
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 135m
nginx NodePort 10.98.246.253 <none> 80:30828/TCP 5s
☁ kubectl describe svc nginx
Name: nginx
Namespace: default
Labels: app=nginx
Annotations: <none>
Selector: app=nginx
Type: NodePort
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.98.246.253
IPs: 10.98.246.253
Port: 80-80 80/TCP
TargetPort: 80/TCP
NodePort: 80-80 30828/TCP
Endpoints: 10.244.230.199:80,10.244.230.200:80,10.244.242.68:80 + 2 more...
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
在這裡,我們看到一個名為的新字段NodePort,其值為30828/TCP。這是配置設定給該服務的端口和協定。現在,如果我們要向具有該端口的任何工作節點 IP 位址發送請求,請求将被發送到服務,然後服務被發送到我們的 pod。
☁ kubectl get nodes -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
nodepool-a-11aa1dc199fa Ready <none> 140m v1.24.4 10.1.96.5 45.77.152.173 Debian GNU/Linux 10 (buster) 4.19.0-22-amd64 containerd://1.6.8
nodepool-a-95e9c8e86208 Ready <none> 140m v1.24.4 10.1.96.4 140.82.44.105 Debian GNU/Linux 10 (buster) 4.19.0-22-amd64 containerd://1.6.8
☁ curl 140.82.44.105:30828
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
☁ curl 45.77.152.173:30828
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
雖然這是向外界公開我們的服務的一種有用方式,但它的擴充性并不好。在高度自動擴充的 Kubernetes 叢集中,工作節點可能是短暫的,因為它們可能會不斷地上下旋轉。這給我們留下了一個與 pod 類似的問題,我們可以在 pod 中找到 IP 是什麼,但這并不意味着它們将永遠存在。如果您的服務需要靜态外部 IP 位址,則LoadBalancer服務類型将滿足該需求。
負載均衡器
NodePort與建構于 之上的方式類似ClusterIP,該LoadBalancer服務建構于 之上NodePort。通過該LoadBalancer服務,每個工作節點繼續擁有配置設定給特定服務的唯一端口。但是,現在部署了 L4 并将其配置為路由到特定的工作節點和端口。進階請求流程如下:一個請求被發送到負載均衡器,它被轉發到特定的工作節點nodeport,然後被傳遞到特定的服務,最後被發送到一個 pod。注意:部署的負載均衡器取決于您運作 Kubernetes 的雲提供商。
如果需要,配置LoadBalancer服務會涉及更多。一個非常簡單的配置可以如下所示,隻需将type字段更改為LoadBalancer.
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx
name: nginx
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
type: LoadBalancer
例如,如果您希望更改您的負載均衡器以強制 SSL 重定向、配置防火牆規則、使用 HTTPS 而不是 HTTP,或者使用不同的平衡算法,那麼這将需要在您的服務上進行定義Annotations。這是一個LoadBalancer使用 Vultrs Load Balancer 內建的示例清單。
apiVersion: v1
kind: Service
metadata:
annotations:
service.beta.kubernetes.io/vultr-loadbalancer-protocol: "http"
service.beta.kubernetes.io/vultr-loadbalancer-https-ports: "443"
# You will need to have created a TLS Secret and pass in the name as the value
service.beta.kubernetes.io/vultr-loadbalancer-ssl: "ssl-secret"
service.beta.kubernetes.io/vultr-loadbalancer-algorithm: "least_connections"
service.beta.kubernetes.io/vultr-loadbalancer-ssl-redirect: "true"
service.beta.kubernetes.io/vultr-loadbalancer-firewall-rules: "0.0.0.0/80;0.0.0.0/443"
labels:
app: nginx
name: nginx
spec:
ports:
- port: 80
name: "http"
- port: 443
name: "https"
selector:
app: nginx
type: LoadBalancer
可在此處找到可與 Vultr 負載均衡器一起使用的所有可用注釋的清單。請檢查您的特定雲提供商以擷取配置選項。首次部署LoadBalancer服務時,您會看到該EXTERNAL-IP部分是pending
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 150m
nginx LoadBalancer 10.103.252.120 <pending> 80:30092/TCP 4s
☁ kubectl describe service nginx
Name: nginx
Namespace: default
Labels: app=nginx
Annotations: <none>
Selector: app=nginx
Type: LoadBalancer
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.103.252.120
IPs: 10.103.252.120
Port: 80-80 80/TCP
TargetPort: 80/TCP
NodePort: 80-80 30092/TCP
Endpoints: 10.244.230.199:80,10.244.230.200:80,10.244.242.68:80 + 2 more...
Session Affinity: None
External Traffic Policy: Cluster
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal EnsuringLoadBalancer 8s (x4 over 44s) service-controller Ensuring load balancer
Warning SyncLoadBalancerFailed 8s (x4 over 44s) service-controller Error syncing load balancer: failed to ensure load balancer: load-balancer is not yet active - current status: pending
您會注意到 Kubernetes 在這裡部署了一個負載均衡器,并且不斷進行通信以檢查負載均衡器是否已配置并配置設定了 IP。一旦 Load Balancer 已配置并準備好進行流量,您将在該EXTERNAL-IP字段中看到一個配置設定的 IP 位址,并且 LB 已被“確定”。這意味着 Kubernetes 現在可以控制相應地監控和更新負載均衡器。另外,請注意nodeport配置設定了唯一性。
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 154m
nginx LoadBalancer 10.103.252.120 45.63.15.140 80:30092/TCP 4m9s
☁ kubectl describe service nginx
Name: nginx
Namespace: default
Labels: app=nginx
Annotations: <none>
Selector: app=nginx
Type: LoadBalancer
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.103.252.120
IPs: 10.103.252.120
LoadBalancer Ingress: 45.63.15.140
Port: 80-80 80/TCP
TargetPort: 80/TCP
NodePort: 80-80 30092/TCP
Endpoints: 10.244.230.199:80,10.244.230.200:80,10.244.242.68:80 + 2 more...
Session Affinity: None
External Traffic Policy: Cluster
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning SyncLoadBalancerFailed 2m21s (x5 over 3m37s) service-controller Error syncing load balancer: failed to ensure load balancer: load-balancer is not yet active - current status: pending
Normal EnsuringLoadBalancer 61s (x6 over 3m37s) service-controller Ensuring load balancer
Normal EnsuredLoadBalancer 60s service-controller Ensured load balancer
EXTERNAL-IP為了驗證我們的負載均衡器是否正常工作,我們可以向負載均衡器的公共 IP 位址發送請求。
curl 45.63.15.140
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
您可以将LoadBalancer服務類型視為一個絕妙的解決方案。但是,它們有一個缺點;您不能定義任何類型的 URL 路徑,它不允許靈活性或将其路由到多個服務。該LoadBalancer服務與單個服務相關聯,是以如果您想從叢集中公開另一個應用程式,您将部署另一個負載均衡器,如果您有多個應用程式,它會快速增加成本。
這個問題的解決方案不是另一種服務類型,而是一種不同的 Kubernetes 資源,稱為ingress.
請求入口
ingress 資源是一種更靈活的方式來定義您的服務以供外界通路。這裡最大的賣點之一是您可以定義單個入口資源,并在您定義的子域、端口或 URL 路徑下使用此路由到您的所有服務。它們還提供了大量其他功能,例如速率限制、身份驗證、自動 TLS、權重路由等等。所有這些都可以通過單個負載均衡器完成,因為Ingress資源與服務類型一起工作,LoadBalancer唯一的差別是部署負載均衡器充當代理,将所有流量發送到“Ingress”資源,該資源充當 L7 負載均衡器簇。
入口控制器這裡唯一需要注意的是 Kubernetes 沒有自帶入口控制器。
社群有各種入口控制器,都具有不同類型的功能。
最終,在決定安裝哪個入口控制器之前,這取決于您的需求和場景。