返回文章列表

HAProxy自動化組態與Proxy工具比較

本文探討如何使用 Consul Template 自動組態 HAProxy,實作服務代理與負載平衡,並比較 HAProxy 與 nginx、Apache、lighttpd 等其他 Proxy 工具的優缺點,最後選擇 nginx 作為代理服務,完成佈署流程。

Web 開發 系統設計

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

自動化佈署流程的實作

既然我們已經能夠手動執行佈署流程,接下來就可以開始建立全自動化的版本。畢竟,我們的目標不是僱傭一群操作員坐在電腦前不斷執行佈署命令。在繼續之前,讓我們快速回顧一下流程。

佈署流程步驟

  1. 簽出程式碼
  2. 執行佈署前測試,編譯和封裝程式碼
  3. 構建容器
  4. 將容器推播到登入檔
  5. 將容器佈署到生產伺服器
  6. 整合容器
  7. 執行佈署後測試
  8. 將測試容器推播到登入檔

圖示:佈署流程

此圖示展示了佈署流程的各個階段。 為了盡量減少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

內容解密:

  • service role 被分成三個邏輯組:佈署前、佈署和佈署後。
  • 每個組被包含在 main.yml 檔案中,以提高可讀性。

佈署前任務

首先,我們應該構建測試容器。我們已經使用了以下命令(請不要執行它)。

程式碼範例:

docker-compose build tests

內容解密:

  • 這裡使用了 docker-compose 命令來構建測試容器。
  • 這是佈署前任務的一部分,用於確保測試環境已經準備就緒。