iT邦幫忙

2021 iThome 鐵人賽

DAY 10
2
DevOps

k8s 入門學習 30天系列 第 10

IT 鐵人賽 k8s 入門30天 -- day10 K8s Ingress explained

前言

今天將會講解 Ingress 這個元件

包括用途, 用法還有實際案例

什麼是 Ingress

假設我們佈署了一個 my-app 的 Pod

當想要透過瀏覽器去存去這個 my-app

有一個作法是建立一個 my-app 的外部 Service

這樣一來就可以透過 Service 的外部 IP 加上對外開放服務的 Port 來存取 my-app

但這種作法其實很不方便 因為必須去找到 Service 的外部 IP

這時候就會需要 Ingress 這個元件來提供域名服務

讓使用者透過域名來存取 my-app 如下圖:

External Service vs Ingress 設定檔

External Service

apiVersion: v1
kind: Service
metadata:
  name: myapp-external-service
spec:
 selector:
   app: myapp
 type: LoadBalancer
 ports:
   - protocol: TCP
     port: 8080
     targetPort: 8080
     nodePort: 35010

External Service 的類型是 LoadBalancer
代表會給予一個對外的 IP

指定的 nodePort 是給外部存取 Service 的接口

Ingress

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: myapp-ingress
spec:
  rules:
  - host: myapp.com
    http:
      paths:
      - backend:
         serviceName: myapp-internal-service
         servicePort: 8080

Ingress 的類型是 Ingress

spec 的 rules 是設定路由規則

以這邊的例子規則是所有域名是 myapp.com 的封包都 forward 到 myapp-internal-service:8080

paths 這邊就是設定 url

注意的是, 這裡的 http 指的是 myapp-internal-service 所服務的 protocol 而不是外部的 protocol

而對應的 Internal Service 如下:

apiVersion: v1
kind: Service
metadata:
  name: myapp-internal-service
spec:
  selector:
    app: myapp
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8080

host 需要是一個合法的域名

host 用來把外部域名, 對應到 Node IP Address

Ingress Controller

除了剛剛設定之外

Ingress 發佈需要一個 Ingress 實作實體, 也就是所謂 Ingress Controller

Ingress Controller 是實際在執行路由的實體, 會根據 Ingress 的 rules 來直接封包路由

架構圖如下:

Ingress Controller 的實作有很多第三方套件可以用

k8s 官方提供可用的 Ingress Controller 選項

而實際佈署要選用哪種 Ingress Controller 要根據 k8s 叢集建制環境來決定

假設是建立在雲服務商上面的話

可能就有雲服務商提供的選項, 所謂 cloud load balancer

而使用雲服務商提供的 cloud load balancer, 舉例來說: AWS 的 ELB

好處就是不必自行去實現負載平衡的功能

架構如下:

但如果是沒有用雲服務商, 而是像是使用 minikube 這類 local run 的叢集的話

就要自行架設 load balancer, 可以是在叢集之內或是之外的伺服器

安全一點的作法一台伺服器當 proxy 轉發封包到 Ingress Controller

這樣對外的接口就只有那台 proxy server, 而 k8s cluster 就不需有對外的接口

架構圖如下:

在 minikube 安裝 Ingress Controller

minikube addons enable ingress

這個設定是自動啟用了 k8s Nginx 的 Ingress Controller

這個設定也可以用在 production 環境

當 ingress 被 enabled 之後可以查詢 namespace 是 ingress-nginx 的 Pod

把 kubernetes-dashboard 改用 ingress 方式呈獻

執行以下指令

minikube dashboard

之後就可以透過 localhsot 察看 minikube 的 status

會發現多了一個 namespace 叫作 kubernete-dashboard

查詢這個 namespace 下面的 Pod

會發現 kubernetes-dashboard 這個 Service 沒有對外開放

所以需要使用 Ingress 建立路由才存取

目標建立 hostname 為 dashboard.com 來存取 kuberenetes-dashboard 這個 Service 內容

建立 dashboard-ingress.yaml 如下:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: dashboard-ingress
  namespace: kubernetes-dashboard
spec:
  rules:
  - host: dashboard.com
    http:
      paths:
      - pathType: ImplementationSpecific
        backend:
          service:
            name: kubernetes-dashboard
            port:
              number: 80

語法參考自k8s 官方文件

關鍵點:

1 設定 host 為 dashboard.com(你想要設定域名)

2 設定 service 的 name 還有 port 到要連結的 Service

舉例來說: 這邊的 name 設定是 kubernetes-dashboard, port 是 80

因為前面 kubectl get pod -n kuberenetes-dashboard 結果

3 設定 metadata 內, 對應的 namespace 為 kuberenetes-dashboard

因為這是屬於 kuberenetes-dashboard 類別所有放在這個 namespace

另外因為這樣放 可以讓 service 的 name url 的比較簡單, 如果放在不同 namespace 則必須要指定 kuberenetes-dashboard Service 的 namespace

4 kind 是 Ingress 類別

5 pathType 是 ImplementationSpecific, 這裡類別有三種 Exact, Prefix, ImplementationSpecific. Exact 代表 path 要完全一樣才進入路由, Prefix 代表只要前置有包換就進入路由, ImplementationSpecific 代表根據 IngressClass 來決定

6 Ingress Class 是由 Ingress Controller 所提供的選項

每個 Ingress Controller 會實作自己的比對模式並對應到一種 Ingress Class

所以這邊的 Ingress Class 要去查詢 Ingress Controller 所提供的類別

使用以下指令, 發佈 Ingress

kubectl apply -f dashboard-ingress.yaml

檢查 ingress

這時候如果直接 到瀏覽器

http://dashboard.com 輸入

就會發現

原因是因為我們只設定好路由

但是沒做域名轉換

因此在本機電腦這邊需要 在 /etc/hosts 內 加入下面一行

192.168.49.2 dashboard.com

注意的是 這邊前面的 192.168.49.2 是從

kubectl get ingress -n kubernetes-dashboard 

拿到的 IP 隨著每個人電腦不同會有不同的結果

修改完 /etc/hosts 存檔之後

重新再瀏覽器輸入 http://dashboard.com

dashboard default-backend

透過以下指令

kubectl describe ingress dashboard-ingress -n kubernetes-dashboard

會發現有一個 Default backend 的欄位

而這個是 Ingress 用來處理沒被原本 Service 定義路由的 request

但這邊可以看到還沒有給予任何 Service 來處理

所以再處理 request 時 假設遇到沒有被 forward 過去的 Service 處理到的路由

就會跳出一些 404 網頁找不到 等等預設錯誤

而不是客製化的錯誤頁面

想要建立一個客製化頁面

來處理此問題的方式就是建立一個 Internal Service 對應到這個 default-http-backend

在這個 Internal Service去實作客製化的頁面

建立 default-http-backend.yaml 如下

apiVersion: v1
kind: Service
metadata:
  name: default-http-backend
spec:
  selector:
    app: default-response-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

由於處理方式很多, 在此就不做更深入實作

多個路由路徑的 Ingress

除了剛剛那個直接對應的 Service 的路由

Ingress 也支援多個路由對應的方式

舉例如下:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: simple-fanout-example
spec:
  rules:
  - host: myapp.com
    http:
      paths:
      - path: "/analytics"
        path: Prefix
        backend:
          service:
            name: analytics-service
            port:
              number: 3000
      - path: "/shopping"
        pathType: Exact
        backend:
          service:
            name: shopping-service
            port:
              number: 8080

就可以做到以下的路由

多個子域名的 Ingress

Ingress 也支援多個子域名對應的方式

舉例如下:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: name-virtual-host-ingress-no-third-host
spec:
  rules:
  - host: analytics.myapp.com
    http:
      paths:
      - path: "/"
        path: Prefix
        backend:
          service:
            name: analytics-service
            port:
              number: 3000
  - host: shopping.myapp.com
    http:
      - path: "/"
        pathType: Exact
        backend:
          service:
            name: shopping-service
            port:
              number: 8080

就可以做到以下的路由

TLS 設定

要建立 TLS 必須要先建立 certificate 跟 key pair

然後把 certificate 跟 private 放在 Secret 內

建立 sample-tls-secret.yaml 如下:

apiVersion: v1
kind: Secret
metadata:
  name: testsecret-tls
  namespace: default
data:
  tls.crt: base64 encoded cert
  tls.key: base64 encoded key
type: kubernetes.io/tls

然後在 Ingress 設定內取用這個 Secret 在 tls 設定的部份

建立 tls-example-ingress.yaml 如下

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-example-ingress
spec:
  tls:
  - hosts:
      - https-example.foo.com
    secretName: testsecret-tls
  rules:
  - host: https-example.foo.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              number: 80

關鍵點:

1 tls 設定的 hosts 一定要跟 rules 內指令的 host 一樣

2 這個範例是根據nginx的規則所寫, 不同的 Ingress Controller 可能會有不同的 tls 設定

3 secretName 對應到剛剛 TLS 建立的 Secret 名稱

4 Secret 與 Ingress 必須建立在同一個 Namespace


上一篇
IT 鐵人賽 k8s 入門30天 -- day9 Organizing your components with K8s Namespaces
下一篇
IT 鐵人賽 k8s 入門30天 -- day11 Helm - Package Manager
系列文
k8s 入門學習 30天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言