跳转到内容
开源

顯示維護與錯誤頁面

讓網域在維護期間顯示 503 頁面,並為服務的 502、503 與 504 回應設定 HTML。

在服務 網路 的網域列,開啟 維護與錯誤頁面,打開 維護模式,加入變更後檢查並套用。該網域的訪客會看到維護頁面與 HTTP 503,原本的服務仍繼續執行。完成維護後,從同一處關閉,流量就會回到原本的後端。

  • 服務有公開網域。Ingress 和 HTTPRoute 提供的網域都能開維護模式。
  • 有權修改路由。專案還沒有頁面伺服器時,也要有權建立 Deployment、Service、ConfigMap 和 NetworkPolicy。
  • 自訂錯誤頁面需要 Traefik 提供的 Ingress。HTTPRoute 和其他 Ingress controller 的網域可以開維護模式,但面板裡沒有 顯示錯誤頁面。

維護模式只改這一個網域的轉送目標,服務本身繼續執行。同一個服務的其他網域、私有位址和對外連接埠照樣連得到應用程式,排程工作也照常執行。

進入服務 網路,在目標網域那一列按 app.example.com 的維護與錯誤頁面。

開啟 維護模式。保留預設 HTML,或在 要編輯的頁面 選 維護,修改 HTML。

每個頁面要小於 64 KiB。專案的每個網域都用同一組頁面,所以在這裡改了維護頁面,專案裡其他進入維護的網域也會顯示新內容。

專案還沒有頁面伺服器時,面板上方會寫 這個專案還沒有頁面伺服器。照常往下做,檢查變更時會一併把 Zeabur Catalog 的 Error pages 範本部署到專案,並寫入維護、502、503、504 四份預設頁面。只改維護頁面時,其他三份保留預設內容。

在側邊面板按 加入變更,網域列會標上 已修改。再從頁面下方按 檢查變更,確認目標網域和 HTML,然後套用。要部署頁面伺服器時,清單裡也會列出它的 Deployment、Service、ConfigMap 和 NetworkPolicy。

這個網域底下的所有路徑都會轉到維護頁面,同一個 Ingress 的其他網域不受影響。Ingress 的網域會多一份名稱以 -maintenance 結尾的 Ingress,Traefik 優先用它,原本的 Ingress 不動。HTTPRoute 的網域會把原本後端的權重改成 0,再加上頁面伺服器。HTTPRoute 的維護作用在整條路由,同一條 HTTPRoute 還有其他網域時,這個網域會先移到自己的路由。

開啟目標網域的首頁及一個原本可用的子路徑,確認都出現維護頁面。也可以在自己的終端機檢查回應:

curl -i https://app.example.com/

把 app.example.com 換成自己的網域。回應的狀態碼是 503,內容是維護頁面的 HTML。回到服務 網路,網域列會標上 維護中,服務的副本仍在執行。

Ingress 的網域設了轉址或密碼時,維護期間兩者都不生效,訪客不用輸入密碼就會直接看到維護頁。維護頁只有你寫的 HTML,不會經過應用程式。HTTPRoute 的網域正在轉址時不能開維護模式,要在目標網域開,或先取消轉址。

  1. 確認應用程式已準備好接收流量,所需的環境變數與磁碟區都正確。
  2. 回到同一網域的 維護與錯誤頁面,關閉 維護模式。
  3. 在面板按 加入變更,從頁面下方按 檢查變更,確認網域會轉回原本的服務,再套用。
  4. 重新開啟網域與子路徑,確認應用程式正常回應,網域列不再顯示 維護中。

關閉時,Ingress 的網域會刪掉那份 -maintenance Ingress,HTTPRoute 的網域會拿掉頁面伺服器,把權重 0 的後端改回 1。原本的規則一直留在物件上,維護期間改過規則也照樣還原。刪掉原本的 Ingress 時,Kubernetes 會連同它的維護 Ingress 一起刪除。

在 Traefik Ingress 網域的 維護與錯誤頁面 開啟 顯示錯誤頁面,再分別選擇以下頁面修改 HTML:

頁面提供內容的檔案
502 閘道錯誤502.html
503 服務無法使用503.html
504 閘道逾時504.html

按面板中的 加入變更,再從頁面下方檢查並套用。之後服務回應 502、503 或 504 時,Traefik 會改送專案的錯誤頁面。要看實際效果,可以拿一個會回這些狀態碼的測試服務試,不必停掉正式服務。

這個開關作用在整個 Ingress 上,面板會列出一起受影響的其他網域。頁面 HTML 則是整個專案共用。從 app.example.com 改了 502 頁面,其他開啟錯誤頁面的網域也會顯示新內容。

同一個 Ingress 有網域在維護時,其他網域照樣顯示自訂的 502、503 和 504 頁面。

HTML 存在 ConfigMap 裡,頁面伺服器每次請求都從掛載的檔案讀取。改完 HTML 後,等 kubelet 下一次同步、更新掛載檔案後就會生效,不用重新啟動。

維護頁和錯誤頁面由專案裡的頁面伺服器提供,它來自 Zeabur Catalog 的 Error pages 範本:一個小型 nginx,HTML 放在 ConfigMap error-pages。Zeabur 不看名稱,而是依標籤 zeabur.com/page-server: "true" 找到它:

物件需要的內容
Service帶這個標籤,連接埠 pages 依檔名提供頁面,連接埠 maintenance 對每個請求回維護頁和 503
ConfigMap帶這個標籤,鍵為 502.html、503.html、504.html 和 maintenance.html

一個專案只能有一個帶這個標籤的 Service。也可以自己用 kubectl 部署這個範本,或改用符合上表的其他伺服器,Zeabur 一樣認得。這些都是一般的 Kubernetes 物件,不用 Zeabur 也照常運作。

維護模式和錯誤頁面只用到 Ingress、HTTPRoute、Traefik Middleware 和頁面伺服器,移除 Zeabur 之後照樣運作。以下以專案 demo、Ingress web-app-example-com、網域 app.example.com 為例,假設專案已經有頁面伺服器 error-pages。

新增一個 Ingress,名稱是 <服務>-<網域,點換成破折號>-maintenance,同一個網域的所有路徑都轉到頁面伺服器的 maintenance 連接埠。router.priority 要比這個網域其他路由都高,Traefik 才會優先用它。ownerReferences 指向原本的 Ingress,Zeabur 靠它認出這是維護用的 Ingress,所以先查原本 Ingress 的 uid:

kubectl -n demo get ingress web-app-example-com -o jsonpath='{.metadata.uid}'

把查到的值填進 uid:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-app-example-com-maintenance
namespace: demo
annotations:
traefik.ingress.kubernetes.io/router.priority: "1000"
ownerReferences:
- apiVersion: networking.k8s.io/v1
kind: Ingress
name: web-app-example-com
uid: 0b8f9a52-5d6e-4c1a-9f3e-2a7b1c4d5e6f
spec:
ingressClassName: traefik
tls:
- hosts: [app.example.com]
secretName: web-app-example-com-tls
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: error-pages
port:
name: maintenance

Zeabur 寫的版本還會:

  • 把 router.priority 設成這個網域現有路由的最高優先權加 1。Traefik 沒有指定優先權時,用規則的長度當優先權,所以這個數字通常不大。上面的 1000 只要高過原本的路由就好。
  • 複製原本 Ingress 的 traefik.ingress.kubernetes.io/router.* annotation(router.middlewares 和 router.priority 除外)、ingressClassName 和這個網域的 tls。

有了 ownerReferences,刪掉原本的 Ingress 時,Kubernetes 會一起刪掉維護用的 Ingress。

關閉維護模式就是刪掉這個 Ingress:

kubectl -n demo delete ingress web-app-example-com-maintenance

HTTPRoute 沒有另一份物件。Zeabur 把每條規則原本後端的 weight 改成 0,再加上頁面伺服器的 maintenance 連接埠,權重 1。用 kubectl edit httproute <名稱> 照這樣改,例如:

rules:
- backendRefs:
- name: web
port: 8080
weight: 0
- name: error-pages
port: 8081
weight: 1

8081 換成頁面伺服器 Service 上 maintenance 連接埠的號碼。恢復時把 web 的權重改回 1,並拿掉 error-pages 那一項。

錯誤頁面是 Middleware <Ingress 名稱>-error-pages,ownerReferences 指向 Ingress。Traefik 遇到 502 到 504 的回應時,改向頁面伺服器的 pages 連接埠要 /<狀態碼>.html:

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: web-app-example-com-error-pages
namespace: demo
spec:
errors:
status: ["502-504"]
service:
name: error-pages
port: 8080
query: /{status}.html

8080 換成頁面伺服器 Service 上 pages 連接埠的號碼。再把它加進 Ingress 的 traefik.ingress.kubernetes.io/router.middlewares,寫成 demo-web-app-example-com-error-pages@kubernetescrd。已有其他 Middleware 時,用 kubectl edit 加在清單裡,轉址仍要排第一個。

要改頁面內容,直接改 ConfigMap error-pages:

kubectl -n demo edit configmap error-pages

在服務 網路,維護中的網域列會標上 維護中。面板裡 維護模式 和 顯示錯誤頁面 的開關會反映叢集裡的設定,用 kubectl 開啟的也一樣。

用 kubectl 確認物件,再從叢集外看回應:

kubectl -n demo get ingress
kubectl -n demo get middleware.traefik.io
kubectl -n demo get svc,configmap -l zeabur.com/page-server=true
curl -sI https://app.example.com/

維護中時,kubectl get ingress 會多一個 -maintenance 結尾的 Ingress,curl 的狀態碼是 503。關閉後這個 Ingress 消失,curl 回到服務原本的回應。

畫面或結果接著處理
維護與錯誤頁面按鈕無法按確認你有修改路由的權限,以及路由沒有標示由其他工具管理。
套用後仍看到應用程式確認開啟的網址就是切到維護的網域,並看前面有沒有 CDN 或代理快取。回到 網路 看網域列有沒有 維護中。
維護頁面本身打不開查看專案裡 error-pages 的副本和事件,並確認 NetworkPolicy error-pages 允許叢集的 Ingress controller 連線。
檢查變更說專案有多個頁面伺服器只留一個 Service 帶 zeabur.com/page-server 標籤,其他的拿掉標籤。
頁面還是舊的 HTML等掛載檔案更新後再重新整理。
HTTPRoute 的網域無法開維護模式,說路由依權重分流路由的後端權重不全是 1。用 kubectl 把流量切到頁面伺服器,或先把權重改回 1。
沒有 顯示錯誤頁面網域不是由 Traefik 提供,要用該 Ingress controller 自己的錯誤頁面設定。

關閉 維護模式 會讓網域轉回原本的服務。關閉 顯示錯誤頁面 會拿掉該 Ingress 的錯誤頁面規則。頁面伺服器和 HTML 都會留著,之後可以直接再用。

整個專案都不再需要這些頁面時,先關掉每個網域的維護模式和錯誤頁面,確認流量都恢復了,再到專案 物件 刪除 error-pages 的 Deployment、Service 和 NetworkPolicy,以及 ConfigMap error-pages 和 error-pages-nginx。每個物件在 YAML 按 刪除,檢查後套用。