k8s可以通過三種方式將叢集內服務暴露到外網,分別是NodePort、LoadBalancer、Ingress,其中NodePort作為基礎通訊形式我們在《k8s網路模型與叢集通訊》中進行了介紹,這裡我們主要關注LoadBalancer和Ingress
LoadBalancer
loadbalancer是服務暴露到因特網的標準形式,和nodeport一樣我們只需在建立service是指定type為loadbalancer即可,接著Service 的通過status.loadBalancer
欄位將需要建立的負載均衡器資訊釋出供負載均衡服務建立。不過loadbalancer是雲服務商”專屬“,像騰訊雲CLB、阿里雲SLB,這樣在建立service時會自動幫我們建立一個負載均衡器。
大多數雲上負載均衡也是基於nodeport,他們的結構如下:
如果要在本地建立一個負載均衡器如何實現呢?
MetalLB,一個CNCF沙箱專案,使用標準路由協議(ARP/BGP),實現裸機K8s叢集的負載均衡器。
安裝方式可參考官方文件:installation
L2(子網)模式的結構,圖源
安裝後我們獲得如下兩個元件:
metallb-system/controller
deployment。用於處理IP分配的控制器。metallb-system/speaker
daemonset。叢集中每個節點啟動一個協議服務守護程式。
接著新增一個configmap配置metallb IP池。
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: |
address-pools:
- name: default
protocol: layer2
addresses:
- 192.168.1.240-192.168.1.250
這樣當我們建立一個loadbalancer型別的service時,EXTERNAL-IP將會從地址池中獲取一個用於外部訪問的IP 192.168.1.243 當外部流量進入時,ARP將我們的請求地址廣播獲取所屬的service,接著k8s內部 通過iptables
規則和 kube-proxy
,將流量從服務端點引導到後端。
#nginx_deployment_service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: metallb-system
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- name: http
containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
namespace: metallb-system
name: nginx
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
type: LoadBalancer
檢視service kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx LoadBalancer 10.96.243.159 192.168.1.243 80:31052/TCP 40h
測試訪問:curl 192.168.1.243
# curl 192.168.1.243
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
負載均衡可以建立在 OSI 網路模型的不同級別上,主要是在 L4(傳輸層,例如 TCP/UDP)和 L7(應用層,例如 HTTP)上。在 Kubernetes 中,Services
是 L4 的抽象,LoadBalancer型別負載均衡依然有侷限性,同時我們看到每建立一個service對應的負載均衡器都會消耗一個靜態IP,這並不合理。當然k8s中的另一種資源物件ingress可工作在 L7 層實現應用程式協議(HTTP/HTTPS)的負載均衡。
Ingress
Ingress 公開了從叢集外部到叢集內服務的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 資源上定義的規則控制。我們可以將 Ingress 配置為服務提供外部可訪問的 URL、負載均衡流量、終止 SSL/TLS,以及提供基於名稱的虛擬主機等能力。
我們所說的Ingress包含兩個部分:
- ingress k8s資源物件:流量路由規則的控制
- ingress-controller控制器:控制器的實現有非常多,可參考官方文件中列表Ingress 控制器,這裡我們使用k8s官方維護的控制器NGINX Ingress Controller
外部流量進入叢集時先經過ingress-controller,然後根據ingress配置的路由規則將請求轉發到後端service。
ingress-controller
ingress-controller其實就是守護程式加一個反向代理的應用,守護程式不斷監聽叢集中資源的變化,將ingress中的配置資訊生成反向代理配置。在nginx-ingress controller中即生成nginx.conf
的配置檔案。
在本文中因為我們上面已經配置好了loadbalancer的服務,這樣我們建立一個type為LoadBalancer的service關聯這組pod,再把域名解析指向該地址,就實現了叢集服務的對外暴露。當然你也可以使用NodePort
、Hostnetwork
的方式,感興趣的小夥伴可以進行測試。
ingress-controller不是k8s內部元件,可以通過helm或資源清單方式安裝,可檢視ingress-nginx deploy
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.0/deploy/static/provider/cloud/deploy.yaml
然後我們編輯service
kubectl edit service/ingress-nginx-controller -n ingress-nginx
修改spec.type為LoadBalancer即可。
這樣我們建立好了nginx-ingress controller,下一步就要配置ingress路由規則。
ingress規則
host:k8s.com
基於url的路由:
- /api/v1
- /api/v2
這兩個url分別路由到不同的service中
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test
namespace: training
annotations:
ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: k8s.com
http:
paths:
- path: /api/v1
backend:
serviceName: service-apiv1
servicePort: 80
- path: /api/v2
backend:
serviceName: service-apiv2
servicePort: 80
ingress.kubernetes.io/rewrite-target
是nginx-ingress controller的一個註解,當後端服務中暴露的 URL 與 Ingress 規則中指定的路徑不同時可以通過此重定向。
檢視svc可以看到此時控制器已經獲得了一個EXTERNAL-IP
#kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.96.87.23 192.168.1.245 80:32603/TCP,443:31906/TCP 621d
ingress-nginx-controller-admission ClusterIP 10.96.109.70 <none> 443/TCP 621d
現在nginx-ingress controller和ingress路由規則都有了。
我們可以進入到nginx-ingress controller pod中檢視nginx.conf可以看到此時我們的ingress配置已經被生成為路由規則。
接下來就是指定我們的backend,即上面的server-apiv1/2
我們新增兩個用於暴露的service和deployment,和loadbalancer中測試清單一樣,我們稍稍修改一下名稱即可。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-apiv1
namespace: training
spec:
selector:
matchLabels:
app: nginx-apiv1
template:
metadata:
labels:
app: nginx-apiv1
spec:
containers:
- name: nginx-apiv1
image: nginx:latest
ports:
- name: http
containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
namespace: training
name: service-apiv1
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx-apiv1
type: NodePort
將nginx-apiv1換成nginx-apiv2建立出另一個service和deployment。
最後修改hosts解析k8s.com
192.168.1.245 k8s.com
使用curl命令測試url路由(記得在pod中新增測試檔案,否則雖然url進行了路由但會出現404)。
# curl k8s.com/api/v1/index.html
api v1
# curl k8s.com/api/v2/index.html
api v2
這樣我們對ingress有了初步瞭解,ingress的路由規則可自定項較多也比較繁雜,可通過官方文件進一步學習。
希望小作文對你有些許幫助,如果內容有誤請指正。
您可以隨意轉載、修改、釋出本文,無需經過本人同意。