内容简介:為了能夠讓使用者能夠更直接順利的存取到這篇要來跟大家介紹另外一個相輔相成且好用的概念,也就是所謂的都能夠簡單地完成。 為了能夠順利使用
為了能夠讓使用者能夠更直接順利的存取到 kubernetes 眾多運行的 Pods , kubernetes 花了很大把的精力在網路架構與使用這方面,之前已經詳細介紹過 Kubernetes Service 的 用法以及原理
這篇要來跟大家介紹另外一個相輔相成且好用的概念,也就是所謂的 Ingress . 透過 Ingress 我們能夠提供一些更方便的伺服器存取,不論是基於 URL 的存取導向,亦或是簡化整個 SSL 憑證部署的方式
都能夠簡單地完成。 為了能夠順利使用 SSL 憑證,我們也可以搭配Cert-Manager 來進行憑證的處理,並且將其與 Ingress 給整合。
本文主要會從 Ingress 的基本概念出發,介紹其基本架構並且從最常用的 Ingress Nginx 作為一個使用範例,來介紹實際上整個 Kubernetes 集群內是如何運作的
Introduction
Kubernetes 有一個非常有趣且迷人的地方,就是大量的抽象化,部分的功能則是公開其介面,依賴第三方廠商自行實現該介面來提供此功能。
譬如以前有提過的 Network Policy 就是這樣的一種概念,不同的 網路解決方案提供者 可以針對自己的應用特性來實現對應的 Network Policy 進而提供多一層的網路保護。
而 Ingress 也是一個類似的架構,接下來會仔細介紹一下其架構以及如何使用。最後則是會使用 Nginx Ingress Controller 當作一個範例來解釋整個運作
Architecture
Kubernetes 的 Ingress 裡面我們可以設定一些如何轉發封包的選項,範例如下
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
name: nginx-demo
namespace: default
spec:
rules:
- host: nginx.example.com
http:
paths:
- path: /v1
backend:
serviceName: nginx
servicePort: http
- path: /v2
backend:
serviceName: nginx-v2
servicePort: http
- host: note.example.com
http:
paths:
- path: /
backend:
serviceName: jupyter
servicePort: http
Ingress 內我們可以針對 Host 或是 Path 不同的選項來決定該封包要怎麼轉發。以上述範例來說,我們希望達到的是
- 如果看到的是
note.example.com可以送給特定的service - 如果看到的是
nginx.example.com,則根據後面的path (v1/v2)來決定最後要怎麼轉發。
這邊要特別注意的是,對於 Kubernetes 來說, Ingress 物件本身只有描述的功用,實際上並不會真的把使用者所描述與敘述的功能給實現完畢,這部分需要依賴剩下的元件來補足。
接下來我們使用下列這張圖示來解釋一下一個完整 Ingress 的架構。
圖中標示為 Ingress Resource 的元件就是使用者們透過 Ingress Yaml 去描述預期行為的設定檔,也就是上圖的部分。
綠色的 Backend server 則是後端不同類型的服務器,使用者會預期 Ingress 可以根據 Host/Path 等不同的規則將對應的封包轉發到後端真正服務的 Backend Server .
接下來真正重要的就是 Ingress-Controller 以及 Ingress-Server .
Ingress-Server 普遍上來說,就是一個能夠接受 HTTP/HTTPS 連線的網路伺服器,以本篇文章來說就是 Nginx .
過往的使用經驗上,我們的確可以透過 nginx.conf 的方式來設定 nginx server . 來達到根據不同的情況來決定不同的封包轉發等行為。
但是在 kubernetes ingress 的架構下,使用者並不一定熟悉 nginx.conf 的格式與撰寫,而熟悉的只有 Kubernetes Ingress 的格式。
在此條件下,我們需要一個轉換者,該轉換者能夠將 Ingress Resource 的設定轉換成 Ingress-Server (Nginx) 所能夠處理的格式。
這個角色也就是所謂的 Ingress-Controller .
將上述的設定與使用流程以順序來看
- 使用者透過
yaml部署ingress設定到kubernetes裡面 -
Ingress-Controller偵測到Ingress Resource的更動,讀取該設定後產生對應的Nginx.conf供Ingress-Server使用 - 外部使用者嘗試存取服務,該封包會先到達
Ingress-Server(Nginx). -
Ingrss-Server(Nginx)根據nginx.conf的設定決定將該封包轉發到後段的服務器backend server.
從上述的概念來說,我們可以簡單歸納一下 Ingress 的架構
-
Kubernetes本身只提供一個統一的Ingress介面,本身不參與該介面的實作 - 服務提供者本身必須要實現
Ingress-Server以及Ingress-Controller這兩個元件將使用者描述的抽象概念轉換成實際上可以運作的設定
所以可以看到目前現實上有非常多的 Ingress 實作,不論是 Traefik , Kong , Nginx 甚至是各個公有雲(GKE/AKS/EKS)都有跟自行架構更加整合的實現。
關於 Ingress 更多的概念可以參考 官方文件
Annotation
有實際上使用過 Ingress 的玩家會發現在 Yaml 內有各式各樣的 annotation 要使用,譬如
annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/rewrite-target: /
首先,根據上述的架構概念,我們可以知道 Ingress-Controller 會去讀取 Ingress 的設定,然後來進行後續的動作。
假想一個情況,系統內同時有多個 Ingress-Controller 的實現,使用者要如何指派該 Ingress 要使用哪一個 Ingress-Controller 來使用?
再者個情況下,我們可以透過 annotations 的方式來加註一些額外的資訊,當然這些資訊不是標準的,反而是各個 Ingress-Controller 自行決定看到什麼樣的資訊來進行什麼處理。
此外,不同的 Ingress-Server 提供的功能與使用方式都不同,基本上 Ingress Resource 很難有一個完美的介面來滿足所有的實現,因此大部分的情況下,不同的 Ingress-Controller/Ingress-Server 都會要求使用者在 Annotation 的部分使用特定的字眼來描述額外的功能,譬如
nginx.ingress.kubernetes.io/rewrite-target: /
所以在選擇 Ingess 的使用上,遇到任何問題的時候,如果是 Ingress Resource 的介面問題,則可以尋求 Kubernetes 官方文件的幫助,如果是更細緻的需求,則該查詢 Ingress-Controller 的說明文件,看看自己的需求與相對應的設定是否有辦法完成。
Compare
跟 Kubernetes Service 比較起來,兩者都在提供便捷的 網路存取 服務
Server 針對的單位主要是 Pod(Container) , 提供一個更方便的方式讓用戶端可以不用在意後端 Pod(Container) 的真實 IP 地址。
而 Ingress 目前的使用上更偏向是 HTTP/HTTPS 的應用,在上述的 Service 上搭建一層更方便的服務,可以根據 Host(NameBasd Virtaul Hosting) 或是 Path(Fanout) 來決定後續真正轉發的對象,而該對象則是不同後端服務所搭建起來的 Service .
因此在使用上,這兩者並沒有誰取代誰的問題,反而是根據需求來使用,大部分情況下都是互相整合來提供更方便與好用的功能。
Example
上述已經介紹完關於 Ingress 的基本概念,接下來要使用 Nginx 作為 Ingress-Server 來實際搭建一個 Ingress 的範例。
接下來的所有範例文件都可以在 KubeDemo 內找到對應的檔案。
該範例的架構圖如下
我們會在 Kubernetes 裡面進行下列部署
- 搭建一個基於
Nginx的Ingress-Controller/Ingress-Server, - 透過
Deployment部署三套不同的後端服務,分別是Jupyter Notebook以及兩個有者不同Index.html的Nginx Server. - 透過三個不同的
kubernetes service將上述的Deployment包裝起來提供更方便的存取功能 - 部署對應的
Ingress, 希望可以完成- 存取
note.example.com會存取到jupyter notebook - 存取
nginx.example.com/v1會存取到nginx - 存取
nginx.example.com/v2會存取到nginx-v2
- 存取
接下來我們就要依據上述的概念進行相關檔案的部署。
我的測試環境是基於 MAC 上透過 Vagrant 創建一個 UbuntuOS 並且使用 Kubeadm 實現的一個小型 Kubernetes 叢集。
Nginx Controller
首先我們要先部署 Nginx Controller 到 kubernetes 叢集內,詳細的安裝方式可以參閱其 官網
首先我們要先安裝相關的資源,譬如 RBAC 以及相關的 Deployment .
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml
接下來為了讓外界的服務可以存取到該 Nginx Server (Ingress-Server) ,這邊會根據你的機器環境而有所不同。
以我 Baremetal 的環境,我需要部署下列的資源,透過 Kubernetes Service NodePort 的方式讓我的 Nginx Server 可以被外界存取
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/baremetal/service-nodeport.yaml
上述的部屬都會安裝到 ingress-nginx 的 kubernetes namespace 上,所以透過下列的指令觀察安裝的情形
$ kubectl -n ingress-nginx get all NAME READY STATUS RESTARTS AGE pod/nginx-ingress-controller-d88dbf49c-9b6td 1/1 Running 0 23h NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/ingress-nginx NodePort 10.111.134.97 <none> 80:32663/TCP,443:31309/TCP 1d NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE deployment.apps/nginx-ingress-controller 1 1 1 1 1d NAME DESIRED CURRENT READY AGE replicaset.apps/nginx-ingress-controller-d88dbf49c 1 1 1 1d
Outside Internet Access
為了從外部 MAC 的瀏覽器進行測試,我對機器上的 /etc/hosts 進行了相關的修改, 加上了下列的資料,讓我可以透過相關的設定來存取該 NodePort 的 Nginx(Ingress-Server) .
172.17.8.101 nginx.example.com note.example.com
172.17.8.101 是我 VM(Ubuntu) 的 Virtaul IP address .
Backend Servers
Jupyter
基本上需要的就是 Deployment 配上一個對應的 Service 即可
詳細的請參閱 KubeDemo
kubectl apply -f https://raw.githubusercontent.com/hwchiu/kubeDemo/master/ingress/jupyter.yml
Nginx
類似上述 Jupyter 的安裝流程,但是為了客製化 index.html 的內容,會額外部署一個 configMap 來產生不同的內容
kubectl apply -f https://raw.githubusercontent.com/hwchiu/kubeDemo/master/ingress/nginx.yaml kubectl apply -f https://raw.githubusercontent.com/hwchiu/kubeDemo/master/ingress/nginx2.yaml
這些應用程式都會部署到 default 這個 namespace ,所以可以用下列指令確保部署正確
kubectl -n default get all NAME READY STATUS RESTARTS AGE pod/jupyter 1/1 Running 0 15h pod/nginx-7dd9f89db4-tvfkk 1/1 Running 0 15h pod/nginx-v2-5c45597f57-746p8 1/1 Running 0 15h NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/jupyter LoadBalancer 10.106.190.88 <pending> 80:32444/TCP 15h service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 89d service/nginx ClusterIP 10.110.237.87 <none> 80/TCP 15h service/nginx-v2 ClusterIP 10.103.43.44 <none> 80/TCP 15h NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE deployment.apps/nginx 1 1 1 1 15h deployment.apps/nginx-v2 1 1 1 1 15h NAME DESIRED CURRENT READY AGE replicaset.apps/nginx-7dd9f89db4 1 1 1 15h replicaset.apps/nginx-v2-5c45597f57 1 1 1 15h
上述服務完畢後,先用 curl 針對三個 service 的 ClusterIP 去確認服務有正常起來
$ curl 10.110.237.87 Nginx V1 $ curl 10.103.43.44 Nginx V2 $ curl 10.106.190.88/tree ....
Deploy Ingress
上述相關的服務都部署完畢後,接下來就要部署 Ingress 物件進去,我們期望的行為是 Nginx Controller 能夠讀取這個 Ingress 的物件並且產生對應的 nginx.conf 供 Nginx Server(Ingress-Server) 使用.
所以先來看一下對應的 Ingress Resource
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
name: nginx-demo
namespace: default
spec:
rules:
- host: nginx.example.com
http:
paths:
- path: /v1
backend:
serviceName: nginx
servicePort: http
- path: /v2
backend:
serviceName: nginx-v2
servicePort: http
- host: note.example.com
http:
paths:
- path: /
backend:
serviceName: jupyter
servicePort: http
該物件部署完畢後,透過下列指令觀察部署結果
$ kubectl get ingress NAME HOSTS ADDRESS PORTS AGE nginx-demo nginx.example.com,note.example.com 80 15h
Check Nginx
接下來我們將直接進入到 Nginx Controller 去觀察一下是否有對應的 nginx.conf 被產生
$ kubectl -n ingress-nginx exec -it $(kubectl -n ingress-nginx get pods -l app.kubernetes.io/name=ingress-nginx -o jsonpath="{.items[0].metadata.name}") bash
[email protected]:/etc/nginx$
[email protected]:/etc/nginx$ grep "example.com" nginx.conf
## start server nginx.example.com
server_name nginx.example.com ;
## end server nginx.example.com
## start server note.example.com
server_name note.example.com ;
## end server note.example.com
[email protected]:/etc/nginx$ grep "v1" nginx.conf
ssl_protocols TLSv1.2;
location ~* "^/v1\/?(?<baseuri>.*)" {
set $location_path "/v1";
rewrite "(?i)/v1/(.*)" /$1 break;
rewrite "(?i)/v1$" / break;
[email protected]:/etc/nginx$ grep "v2" nginx.conf
location ~* "^/v2\/?(?<baseuri>.*)" {
set $service_name "nginx-v2";
set $location_path "/v2";
set $proxy_upstream_name "default-nginx-v2-http";
rewrite "(?i)/v2/(.*)" /$1 break;
rewrite "(?i)/v2$" / break;
到這邊為止,基本上的一切都順利設定完畢了,接下來就可以開啟瀏覽器嘗試去瀏覽看看.
Access the Nginx Server
因為我們的 Nginx Server 是基於 NorePort 的方式來供對外存取,所以我們要先確認一下開啟的 NodePort 資訊是什麼
$ kubectl -n ingress-nginx get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx NodePort 10.111.134.97 <none> 80:32663/TCP,443:31309/TCP 1d
在我的範例環境中,預設 HTTP 所使用的的連接埠是 32663 , 因此等下需要使用這個資訊來進行測試連線
首先,我們先針對 nginx.example.com 進行測試,結果如下圖
結果如預期般,可以透過不同的 PATH 來導向不同的服務後端
接下來測試 node.example.com , 看看是否能夠針對 host 來導向不同的後端
的確也能夠正常運作,意味者我們的 Ingress 測試滿順利的,都能夠如預期般的運作
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。