你知道K8S暴露服務的方式有哪些嗎?
Kubernetes
支持多種將外部流量引入集群的方法。 ClusterIP
、 NodePort
和 Ingress
是三種廣泛使用的資源,它們都在路由流量中發揮作用。每一個都允許您使用一組獨特的功能和折衷方案來公開服務。
背景
默認情況下, Kubernetes
上運行的服務都是在自己的Pod 里過著與世隔絕的生活,外部無法打擾他們。我們可以通過創建 Service 使容器供外部世界可見,這個“外部世界” 即可以整個集群、也可以是整個互聯網。
Service
將流量路由到 Pod
內的容器中。 Service
是一種用于在網絡上公開 Pod
的抽象機制。每個 Service
有一個類型—— ClusterIP
、 NodePort
或 LoadBalancer
。這些定義了外部流量如何到達服務。
但是光有 Service
也不行 ,有時候我們需要將不同域名和URL路徑上的流量路由到集群內部,這就需要 Ingress
幫助才行。
ClusterIP
ClusterIP 是默認的 Service
類型,不指定 Type
時默認就是 ClusterIP
類型的 Service
。 ClusterIP
在集群內提供網絡連接。它通常無法從外部訪問。我們將這些 ClusterIP Service
用于服務之間的內部網絡。
- apiVersion: v1
- kind: Service
- spec:
- metadata:
- name: my-service
- selector:
- app: my-app
- type: ClusterIP
- ports:
- - name: http
- port: 80
- targetPort: 8080
- protocol: TCP
上面的示例定義了一個 ClusterIP Service
。到 ClusterIP
上端口 80 的流量將轉發到你的 Pod
上的端口 8080 (targetPort配置項),攜帶 app: my-app
標簽的 Pod 將被添加到 Service
中作為作為服務的可用端點。
可以通過運行 kubectl get svc my-service
查看分配的 IP 地址。集群中的其他服務可以使用 10.96.0.1:80 與這個的 Service 管控的服務進行交互。
- ➜ kubectl get svc app-service
- NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
- my-service ClusterIP 10.96.0.1 <none> 8080:80/TCP 63d
可以使用 spec.clusterIp
字段手動將 ClusterIP 設置為特定 IP 地址:
- spec:
- type: ClusterIP
- clusterIp: 123.123.123.123
NodePort
NodePort
在固定端口號上公開向集群外部暴露服務,它允許從集群外部訪問該服務,在集群外部需要使用集群的 IP 地址和 NodePort
指定的端口才能訪問。創建 NodePort Service
將在集群中的每個 Node
上開放該端口。 Kubernetes
會自動將端口流量路由到它所連接的服務。下面是一個 NodePort Service
的示例:
- apiVersion: v1
- kind: Service
- spec:
- metadata:
- name: my-service
- selector:
- app: my-app
- type: NodePort
- ports:
- - name: http
- port: 80
- targetPort: 8080
- protocol: TCP
NodePort
的定義與 ClusterIP Service
具有相同的屬性。唯一的區別是把類型設置成了:"NodePort"。 targetPort
字段仍然是必需的,因為 NodePort
由 ClusterIP
提供支持。
創建 NodePort Service
的同時還會自動創建一個 ClusterIP
類型的 Service
, NodePort
會將端口上的流量路由給 ClusterIP
類型的 Service。
這也就是為什么下面我們查看 NodePort Service
時發現他也是有 ClusterIP 的原因:
- ➜ kubectl get svc my-service
- NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
- my-service NodePort 10.96.44.244 <none> 8080:30176/TCP 56d
使用上述例子創建 NodePort Service
, Kubernetes
將會從30000-32767這個范圍隨機分配一個端口作為 NodePort
端口,不過我們可以通過設置 ports.nodePort
字段來手動指定端口:
- spec:
- ports:
- - name: http
- port: 80
- targetPort: 8080
- nodePort: 32000
- protocol: TCP
這個會將 32000 端口上的流量通過 Service
最終路由給 Pod
里容器的 8080 端口。
您可以使用 NodePort
快速設置用于開發環境的服務或在其上公開 TCP
或 UDP
服務,但是對于公開 HTTP
服務來說 NodePort
不是一個的理想選擇,因為其使用的都是非 HTTP
標準的端口,我們需要使用其他替代方案。
Ingress
Ingress
實際上是與 Service
完全不同的資源,算是 Service
上面的一層代理,通常在 Service
前使用 Ingress
來提供 HTTP
路由配置。它讓我們可以設置外部 URL、基于域名的虛擬主機、SSL 和負載均衡。
給 Service
前面加 Ingress
,你的集群中需要有 Ingress-Controller
才行。有多種控制器可供選擇。大多數主要的云提供商都有自己的 Ingress-Controller
,與他們的負載平衡基礎設施相集成。如果是自建K8S集群,通常使用 nginx-ingress
作為控制器,它使用 NGINX
服務器作為反向代理來把流量路由給后面的 Service
。
關于控制器Nginx-Ingress的安裝部署參考:https://kubernetes.github.io/ingress-nginx/deploy/ 后面介紹 Ingress
實踐的文章也會再細說。
可以使用 Ingress
資源類型創建 Ingress
。kubernetes.io/ingress.class 注釋可讓你指明正在創建的 Ingress
分類。如果集群里安裝了多個 Ingress-Controller
這將很有用,也可以將不同的 Service
分別掛在不同分類的 Ingress
下面,增加一些高可用性。
- apiVersion: networking.k8s.io/v1beta1
- kind: Ingress
- metadata:
- name: my-ingress
- annotations:
- kubernetes.io/ingress.class: nginx
- spec:
- rules:
- - host: example.com
- http:
- paths:
- - path: /
- backend:
- serviceName: my-service
- servicePort: 80
- - host: another-example.com
- http:
- paths:
- - path: /
- backend:
- serviceName: second-service
- servicePort: 80
上面定義了兩個 Ingress
端點。第一個主機規則將 example.com 流量路由到 my-service
服務上的端口 80。第二條規則將 another-example.com 流量路由到 second-service
。
如果想使用 HTTPs
訪問服務,可以通過在 Ingress
規范中設置 tls
字段來配置 SSL
:
- spec:
- tls:
- - hosts:
- - example.com
- - secretName: my-secret
不過前提是在集群中需要通過 Secret
對象配置這些域名的證書信息。
當需要處理來自多個域名 和 URL 路徑的流量時,應該使用 Ingress
。它讓我們可以使用聲明性語句配置路由和 Service
。 Ingress
控制器將提供你的路由并將它們映射到服務。
總結
ClusterIP
、 NodePort
、 Ingress
將流量路由到集群中的服務。每一個都是為不同的用例設計的。 ClusterIP
更多是為集群內服務的通信而設計,某些向集群外部暴露的 TCP
和 UDP
服務適合使用 NodePort
。而如果向外暴露的是 HTTP
服務,且需要提供域名和 URL
路徑路由能力時則需要在 Service
上面再加一層 Ingress
做反向代理才行。
可能你對 Ingress
, Ingress-Controller
還是有一點模糊,后面我在寫一篇 Ingress
的實踐文章,給大家掃掃盲。