Consul Template 能夠根據 Consul 服務註冊資訊動態生成 HAProxy 組態,實作服務的自動發現和負載平衡。本文詳細解析了 haproxy.ctmpl 範本檔案,以及如何使用 Consul Template 生成 HAProxy 組態檔案 books-ms.service.cfg。同時,也說明瞭如何將生成的組態檔案與 HAProxy 原始組態檔案合併,並複製到 Proxy 節點。最後,透過 curl 命令和日誌檢查驗證 HAProxy 組態的正確性。除了 HAProxy,文章還比較了 nginx、Apache 和 lighttpd 等其他 Proxy 工具,並分析了它們各自的特性和適用場景。
自動化組態HAProxy與Proxy工具比較
在前面的章節中,我們探討瞭如何使用Consul Template自動組態HAProxy來實作服務代理與負載平衡。現在,我們將進一步探討HAProxy的組態細節,並與其他Proxy工具進行比較。
使用Consul Template自動組態HAProxy
首先,我們需要下載haproxy.ctmpl範本檔案,該檔案定義了HAProxy的前端和後端組態。
wget http://raw.githubusercontent.com/vfarcic/books-ms/master/haproxy.ctmpl -O haproxy.ctmpl
haproxy.ctmpl內容解密:
frontend books-ms-fe
bind *:80
option http-server-close
acl url_books-ms path_beg /api/v1/books
use_backend books-ms-be if url_books-ms
backend books-ms-be
{{range service "books-ms" "any"}}
server {{.Node}}_{{.Port}} {{.Address}}:{{.Port}} check
{{end}}
frontend books-ms-fe定義了一個名為books-ms-fe的前端,監聽80埠。acl url_books-ms path_beg /api/v1/books定義了一個ACL規則,當請求路徑以/api/v1/books開頭時,使用books-ms-be後端。backend books-ms-be定義了一個名為books-ms-be的後端,使用Consul Template的範本語法動態生成伺服器列表。
接下來,我們使用Consul Template生成HAProxy的組態檔案。
sudo consul-template \
-consul proxy:8500 \
-template "haproxy.ctmpl:books-ms.service.cfg" \
-once
生成的books-ms.service.cfg內容解密:
backend books-ms-be
server node1_8080 10.100.193.200:8080 check
server node2_8080 10.100.193.201:8080 check
- Consul Template根據Consul中的服務註冊資訊,動態生成了後端伺服器列表。
最後,我們將生成的組態檔案與HAProxy的原始組態檔案合併,並複製到Proxy節點。
cat /vagrant/ansible/roles/haproxy/files/haproxy.cfg.orig \
*.service.cfg | tee haproxy.cfg
scp haproxy.cfg proxy:/data/haproxy/config/haproxy.cfg
驗證HAProxy組態
為了驗證HAProxy的組態是否正確,我們可以查詢服務並檢查日誌。
curl http://proxy/api/v1/books | jq '.'
docker logs haproxy
驗證結果解密:
- 如果HAProxy組態正確,請求應該能夠正常傳回服務資料。
- 透過檢查日誌,可以確認HAProxy是否正常工作。
Proxy工具比較
除了HAProxy之外,還有許多其他的Proxy工具可供選擇,例如nginx、Apache、lighttpd等。
- nginx:一個高效能的HTTP和反向代理伺服器,具有豐富的功能和靈活的組態。
- Apache:一個成熟的HTTP伺服器,具有豐富的功能和模組。
- lighttpd:一個輕量級的HTTP伺服器,具有高效能和低記憶體佔用的特點。
在選擇Proxy工具時,需要根據具體的需求和場景進行評估和選擇。
代理服務的選擇與佈署流程的最後階段
在眾多的代理服務專案中,選擇一個合適的解決方案並非易事。nginx 和 HAProxy 是目前最為出色的兩個選擇,它們都具備出色的效能和廣泛的社群支援。
代理服務的比較
多個專案都提供了代理服務的功能,但大多數都存在某些缺陷。例如,Apache 的效能在大流量面前表現不佳,且資源使用率容易飆升。Lighttpd 曾經是一個有前途的選擇,但由於記憶體洩漏和 CPU 使用率高等問題,部分使用者轉向了其他替代方案。node-http-proxy 雖然效能不錯,但其可程式化的組態對於不斷變化的代理設定並不友好。VulcanD 是一個值得關注的專案,但目前尚未達到生產就緒狀態。
nginx 與 HAProxy 的對比
nginx 和 HAProxy 都是經過戰鬥考驗的優秀解決方案,擁有大量的使用者和成功的應用案例。兩者都有各自的優缺點,但最終的選擇取決於特定的使用場景。nginx 在 Docker 容器中的表現更好,支援組態過載、記錄到 stdout 和包含組態檔案等功能。HAProxy 則由於效能問題而放棄了這些功能。然而,HAProxy 在重新載入組態時可能會丟棄流量,這對於採用微服務架構和持續佈署的團隊來說是一個重大問題。
選擇 nginx 作為代理服務
綜合考慮,nginx 成為我們的首選代理服務。它支援無停機過載組態,這對於頻繁佈署和藍綠佈署的團隊來說至關重要。
銷毀虛擬機器並完成佈署流程
完成代理服務的選擇後,我們需要銷毀之前使用的虛擬機器,並完成佈署流程的最後階段。
1 exit
2
3 vagrant destroy -f
完成佈署流程
我們已經完成了佈署流程的前幾個步驟,包括簽出程式碼、執行預佈署測試、編譯和封裝程式碼、構建容器、推播容器到登入檔和佈署容器到生產伺服器。現在,我們需要完成剩下的三個步驟:整合容器、執行後佈署測試和推播測試容器到登入檔。
步驟1:啟動節點
首先,我們需要啟動用於佈署流程的兩個節點。
1 vagrant up cd prod
步驟2:使用 Ansible playbook 組態節點
我們將使用 prod2.yml Ansible playbook 來組態 prod 節點,該 playbook 包含了服務發現和代理角色。
# prod2.yml 的部分內容
- name: Configure prod node
hosts: prod
become: yes
roles:
- service-discovery
- proxy
#### 內容解密:
此 playbook 組態了 prod 節點,啟用了服務發現和代理功能。其中 service-discovery 角色負責設定服務發現機制,而 proxy 角色則負責設定代理服務。這樣可以確保我們的容器可以被外部存取,並且具備負載平衡和高用性。
圖示:Docker 佈署流程的中間階段
此圖示展示了 Docker 佈署流程的中間階段。
#### 內容解密:
此圖示展示了 Docker 佈署流程的中間階段,包括從簽出程式碼到推播測試容器到登入檔的整個過程。其中每個步驟都是佈署流程中的關鍵環節,確保了程式碼從開發到生產的平滑過渡。
佈署流程的最後階段實作:整合服務與驗證
在前面的章節中,我們已經完成了佈署流程的前幾個階段,包括程式碼簽出、預佈署測試、編譯和封裝、建置容器、推播容器到註冊中心以及佈署到生產伺服器。現在,我們將繼續完成最後的階段:執行後佈署測試和推播測試容器到註冊中心。
設定生產節點
首先,我們需要設定生產節點(prod node),使其執行 Consul、Registrator、Consul Template 和 nginx。這些工具將允許我們將請求代理到目標服務。
- hosts: prod
remote_user: vagrant
serial: 1
sudo: yes
roles:
- common
- docker
- docker-compose
- consul
- registrator
- consul-template
- nginx
內容解密:
hosts: prod指定了 Ansible 要操作的目標主機群組為 prod。remote_user: vagrant表示 Ansible 將使用 vagrant 使用者進行遠端操作。serial: 1表示 Ansible 將一次操作一個主機。sudo: yes表示 Ansible 需要使用 sudo 許可權執行命令。roles列出了要套用到目標主機的角色,包括安裝 Docker、Consul、Registrator、Consul Template 和 nginx。
啟動容器
在執行整合測試之前,我們需要啟動容器。
wget https://raw.githubusercontent.com/vfarcic/books-ms/master/docker-compose.yml
export DOCKER_HOST=tcp://prod:2375
docker-compose up -d app
內容解密:
wget命令下載了docker-compose.yml檔案,用於定義服務的組態。export DOCKER_HOST=tcp://prod:2375設定了 Docker 主機的位址。docker-compose up -d app命令在後台啟動了應用服務。
驗證服務註冊
Consul UI 可以用來驗證服務是否已正確註冊。
curl prod:8500/v1/catalog/services | jq '.'
curl prod:8500/v1/catalog/service/books-ms | jq '.'
內容解密:
- 第一個
curl命令列出了所有在 Consul 中註冊的服務。 - 第二個
curl命令取得了books-ms服務的詳細資訊。
整合服務
為了讓 nginx 能夠代理請求到 books-ms 服務,我們需要更新 nginx 的組態。
vagrant ssh prod
wget https://raw.githubusercontent.com/vfarcic/books-ms/master/nginx-includes.conf -O /data/nginx/includes/books-ms.conf
wget https://raw.githubusercontent.com/vfarcic/books-ms/master/nginx-upstreams.ctmpl -O /data/nginx/upstreams/books-ms.ctmpl
consul-template -consul localhost:8500 -template "/data/nginx/upstreams/books-ms.ctmpl:/data/nginx/upstreams/books-ms.conf:docker kill -s HUP nginx" -once
內容解密:
wget命令下載了 nginx 的組態檔案和範本檔案。consul-template命令根據 Consul 中的資料生成了 nginx 的 upstream 組態檔案,並重新載入了 nginx。
執行後佈署測試
為了驗證服務是否正確佈署,我們需要執行後佈署測試。
git clone https://github.com/vfarcic/books-ms.git
cd books-ms
docker-compose -f docker-compose-dev.yml run --rm -e DOMAIN=http://10.100.198.201 integ
內容解密:
git clone命令下載了測試程式碼。docker-compose命令執行了整合測試。
推播測試容器到註冊中心
最後,我們需要將測試容器推播到註冊中心。
docker push 10.100.198.200:5000/books-ms-tests
內容解密:
docker push命令將測試容器推播到了註冊中心。
自動化佈署流程的實作:後期階段
現在,我們已經準備就緒,能夠手動執行佈署流程。下一步是自動化所有命令,並從頭到尾自動執行Pipeline。我們將銷毀已使用的節點,以便重新開始並確認自動化程式的確有效。
銷毀節點
vagrant destroy -f
自動化佈署流程的實作
既然我們已經能夠手動執行佈署流程,接下來就可以開始建立全自動化的版本。畢竟,我們的目標不是僱傭一群操作員坐在電腦前不斷執行佈署命令。在繼續之前,讓我們快速回顧一下流程。
佈署流程步驟
- 簽出程式碼
- 執行佈署前測試,編譯和封裝程式碼
- 構建容器
- 將容器推播到登入檔
- 將容器佈署到生產伺服器
- 整合容器
- 執行佈署後測試
- 將測試容器推播到登入檔
圖示:佈署流程
此圖示展示了佈署流程的各個階段。
為了盡量減少Pipeline對業務的影響,我們盡可能在生產伺服器以外執行盡可能多的任務。唯一需要在生產節點執行的兩個步驟是佈署本身和整合(目前僅與代理服務整合)。所有其他步驟都在 cd 伺服器內完成。
圖示:CD 和生產節點之間的任務分佈
此圖示展示了 CD 和生產節點之間的任務分佈。 我們已經選擇了 Ansible 作為伺服器組態的工具,並在多個場合使用它來安裝軟體包、設定組態等。到目前為止,所有這些用法都是為了提供佈署容器所需的所有條件。我們將擴充套件 Ansible playbook 的用法,並將佈署Pipeline新增到其中。
圖示:使用 Ansible 的自動化佈署Pipeline
此圖示展示了使用 Ansible 的自動化佈署Pipeline。
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title HAProxy自動化組態與Proxy工具比較
package "網路架構" {
package "應用層" {
component [HTTP/HTTPS] as http
component [WebSocket] as ws
component [gRPC] as grpc
}
package "傳輸層" {
component [TCP] as tcp
component [UDP] as udp
component [TLS/SSL] as tls
}
package "網路層" {
component [IP] as ip
component [ICMP] as icmp
component [路由協議] as routing
}
package "鏈路層" {
component [Ethernet] as eth
component [WiFi] as wifi
component [ARP] as arp
}
}
http --> tcp
ws --> tcp
grpc --> tcp
tcp --> tls : 加密
tls --> ip
udp --> ip
ip --> routing
routing --> eth
routing --> wifi
eth --> arp
@enduml
在所有涉及的步驟中,我們將只保留其中一個在自動化範圍之外。我們不會使用 Ansible 簽出程式碼。背後的原因不是 Ansible 無法克隆 Git 儲存函式庫,而是 Ansible 不是設計用於持續執行和監視程式碼儲存函式庫的工具。
Playbook 和 Role
讓我們看一下 service.yml playbook。
- hosts: prod
remote_user: vagrant
serial: 1
sudo: yes
roles:
- common
- docker
- docker-compose
- consul
- registrator
- consul-template
- nginx
- service
service role 將包含與佈署直接相關的任務,而在其之前的其他 role 是我們的服務正確工作所需的依賴項。
內容解密:
hosts: prod指定了該 playbook 將執行的主機群組。remote_user: vagrant指定了用於連線到遠端主機的使用者。serial: 1表示該 playbook 將一次處理一個主機。sudo: yes允許該 playbook 以 sudo 許可權執行命令。roles列出了將要應用的 role。
服務 Role 中的任務
- include: pre-deployment.yml
- include: deployment.yml
- include: post-deployment.yml
內容解密:
- 該
servicerole 被分成三個邏輯組:佈署前、佈署和佈署後。 - 每個組被包含在
main.yml檔案中,以提高可讀性。
佈署前任務
首先,我們應該構建測試容器。我們已經使用了以下命令(請不要執行它)。
程式碼範例:
docker-compose build tests
內容解密:
- 這裡使用了
docker-compose命令來構建測試容器。 - 這是佈署前任務的一部分,用於確保測試環境已經準備就緒。