Introduction to Kubernetes Ingress (Nginx)

栏目: 服务器 · Nginx · 发布时间: 5年前

内容简介:為了能夠讓使用者能夠更直接順利的存取到這篇要來跟大家介紹另外一個相輔相成且好用的概念,也就是所謂的都能夠簡單地完成。 為了能夠順利使用

為了能夠讓使用者能夠更直接順利的存取到 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

KubernetesIngress 裡面我們可以設定一些如何轉發封包的選項,範例如下

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 不同的選項來決定該封包要怎麼轉發。以上述範例來說,我們希望達到的是

  1. 如果看到的是 note.example.com 可以送給特定的 service
  2. 如果看到的是 nginx.example.com ,則根據後面的 path (v1/v2) 來決定最後要怎麼轉發。

這邊要特別注意的是,對於 Kubernetes 來說, Ingress 物件本身只有描述的功用,實際上並不會真的把使用者所描述與敘述的功能給實現完畢,這部分需要依賴剩下的元件來補足。

接下來我們使用下列這張圖示來解釋一下一個完整 Ingress 的架構。

Introduction to Kubernetes Ingress (Nginx)

圖中標示為 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 .

將上述的設定與使用流程以順序來看

  1. 使用者透過 yaml 部署 ingress 設定到 kubernetes 裡面
  2. Ingress-Controller 偵測到 Ingress Resource 的更動,讀取該設定後產生對應的 Nginx.confIngress-Server 使用
  3. 外部使用者嘗試存取服務,該封包會先到達 Ingress-Server(Nginx) .
  4. Ingrss-Server(Nginx) 根據 nginx.conf 的設定決定將該封包轉發到後段的服務器 backend server .

從上述的概念來說,我們可以簡單歸納一下 Ingress 的架構

  1. Kubernetes 本身只提供一個統一的 Ingress 介面,本身不參與該介面的實作
  2. 服務提供者本身必須要實現 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 內找到對應的檔案。

該範例的架構圖如下

Introduction to Kubernetes Ingress (Nginx)

我們會在 Kubernetes 裡面進行下列部署

  1. 搭建一個基於 NginxIngress-Controller/Ingress-Server
  2. 透過 Deployment 部署三套不同的後端服務,分別是 Jupyter Notebook 以及兩個有者不同 Index.htmlNginx Server .
  3. 透過三個不同的 kubernetes service 將上述的 Deployment 包裝起來提供更方便的存取功能
  4. 部署對應的 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 Controllerkubernetes 叢集內,詳細的安裝方式可以參閱其 官網

首先我們要先安裝相關的資源,譬如 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-nginxkubernetes 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 進行了相關的修改, 加上了下列的資料,讓我可以透過相關的設定來存取該 NodePortNginx(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 針對三個 serviceClusterIP 去確認服務有正常起來

$ 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.confNginx 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 進行測試,結果如下圖

Introduction to Kubernetes Ingress (Nginx) Introduction to Kubernetes Ingress (Nginx)

結果如預期般,可以透過不同的 PATH 來導向不同的服務後端

接下來測試 node.example.com , 看看是否能夠針對 host 來導向不同的後端

Introduction to Kubernetes Ingress (Nginx)

的確也能夠正常運作,意味者我們的 Ingress 測試滿順利的,都能夠如預期般的運作


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

产品心经

产品心经

闫荣 / 机械工业出版社 / 2014-9-30 / 59

产品经理如何才能迅速地、全方位地提升自己的能力,从而打造出让用户尖叫并疯狂爱上的产品?有没有捷径?从成功的、有经验的产品经理的实践真知和智慧中学习是一个很好的途径!本书就是一位拥有近10年产品经验的资深产品经理的实践真知和智慧的结晶,从产品经理核心素养、产品认知、战略与规划、精益开发、需求分析与管理、用户体验、精细运营7大方面,系统梳理了能全面、迅速提升产品经理能力,从而打造出让用户尖叫的产品的5......一起来看看 《产品心经》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具