1. Mở Đầu.
Trong phần này, chúng ta sẽ tìm hiểu về cách sử dụng HAProxy làm server trung gian (reverse proxy) và cân bằng tải (load balancer) trong môi trường Docker. HAProxy là một giải pháp mạnh mẽ cho việc điều hướng các yêu cầu và phân phối tải đối với các dịch vụ và máy chủ khác nhau. Chúng ta sẽ khám phá cách cấu hình frontend và backend trong HAProxy để quản lý các request và cân bằng tải giữa các server Docker.
2. Giới thiệu về HAProxy.
HAProxy (High Availability Proxy) là một reverse proxy và load balancer có hiệu suất cao, hỗ trợ nhiều giao thức bao gồm TCP và HTTP(S). Nó là một giải pháp phổ biến được sử dụng để tăng khả năng hoạt động và cân bằng tải cho các ứng dụng web và dịch vụ.
Chúng ta sẽ tìm hiểu cách cài đặt và cấu hình HAProxy trong môi trường máy ảo hoặc máy chủ bình thường.
Cài Đặt trên CentOS 7/RHEL 7.
Cập nhật hệ thống và cài đặt HAProxy.
yum -y update
yum -y install haproxy
Khởi động HAProxy và cài đặt tự động chạy cùng hệ thống:
systemctl start haproxy
systemctl enable haproxy
File cấu hình của HAProxy có thể được tìm thấy tại /etc/haproxy/haproxy.cfg
. Bạn có thể chỉnh sửa các thiết lập trong file này, và sau mỗi lần chỉnh sửa, bạn cần khởi động lại HAProxy để áp dụng các thay đổi:
systemctl restart haproxy
Cài Đặt trên Ubuntu.
Cập nhật hệ thống và cài đặt HAProxy.
sudo apt-get -y update
sudo apt-get -y install haproxy
Sau khi cài đặt xong, bạn có thể tìm file cấu hình của HAProxy tại /etc/haproxy/haproxy.cfg
và chỉnh sửa các thiết lập theo nhu cầu. Để áp dụng các thay đổi, bạn cũng cần khởi động lại HAProxy:
sudo systemctl restart haproxy
Lưu Ý: Các lệnh và đường dẫn file cấu hình có thể thay đổi tùy theo phiên bản cụ thể của HAProxy và hệ điều hành bạn đang sử dụng.
Cấu Hình HAProxy.
Trong HAProxy, bạn cấu hình cách hoạt động của nó bằng cách chỉnh sửa file cấu hình /etc/haproxy/haproxy.cfg
. Cơ bản, bạn định nghĩa các khối để xử lý các yêu cầu (Request) gửi đến HAProxy.
- Xử lý Backend trong HAProxy
- Backend là nơi xử lý các yêu cầu sau khi chúng đã được frontend nhận và phân tích.
- Bạn có thể định nghĩa nhiều backend khác nhau, mỗi backend có một tên để frontend biết nó cần sử dụng backend nào.
- Trong khối backend, bạn cần chỉ ra các thông tin sau:
- Thuật toán cân bằng tải (balance): Thuật toán quyết định cách phân phối các yêu cầu đến các máy chủ. Các ví dụ phổ biến bao gồm:
roundrobin
: Chọn máy chủ theo chu kỳ (mỗi yêu cầu đi đến máy chủ khác nhau theo lượt).leastconn
: Chọn máy chủ có ít kết nối nhất.source
: Chọn máy chủ dựa trên địa chỉ IP của người dùng.
- Chế độ hoạt động (mode): Xác định giao thức sử dụng (HTTP hoặc TCP).
- Danh sách các máy chủ (server) nhận yêu cầu. Mỗi máy chủ được chỉ ra bằng địa chỉ IP hoặc tên miền và cổng.
- Tùy chọn
check
ở cuối để HAProxy kiểm tra liên tục trạng thái của máy chủ (xem máy chủ có phản hồi không) để đảm bảo rằng chỉ các máy chủ còn sống mới nhận yêu cầu.
- Thuật toán cân bằng tải (balance): Thuật toán quyết định cách phân phối các yêu cầu đến các máy chủ. Các ví dụ phổ biến bao gồm:
backend my-backend
balance roundrobin
mode http
server server1 192.168.13.10:80 check
server server2 192.168.13.11:80 check
Trong ví dụ trên, backend có tên là my-backend
sử dụng thuật toán cân bằng tải roundrobin
và chế độ http
. Có hai máy chủ, server1
và server2
, được chỉ ra bằng địa chỉ IP và cổng, và HAProxy sẽ kiểm tra trạng thái của cả hai máy chủ.
- Xử lý Frontend trong HAProxy.
- Trong HAProxy, khối frontend chịu trách nhiệm nhận và phân tích các yêu cầu (Request) được gửi đến nó, sau đó chuyển chúng đến backend thích hợp dựa trên các điều kiện đã định nghĩa. Dưới đây là một số thông tin cơ bản về cách cấu hình các khối frontend:
- Tên Frontend: Bạn có thể đặt tên cho khối frontend để dễ dàng quản lý và tham chiếu đến nó.
- Bind: Thông qua từ khóa
bind
, bạn chỉ định cổng và IP (hoặc giao diện mạng) mà frontend sẽ lắng nghe để nhận các yêu cầu đến. - Access Control List (ACL): ACLs là danh sách điều kiện dựa trên các thông tin trong yêu cầu như địa chỉ IP, domain, cổng, v.v. Bạn có thể định nghĩa ACL để kiểm tra yêu cầu và xác định điều kiện để chuyển đến các backend tương ứng.
- Sử dụng Backend: Bằng cách sử dụng từ khóa
use_backend
, bạn chỉ định rằng nếu một ACL cụ thể (đã định nghĩa ở bước trước) thỏa mãn, yêu cầu sẽ được chuyển đến backend tương ứng. - Backend Mặc Định: Bạn cũng có thể định nghĩa backend mặc định bằng từ khóa
default_backend
. Điều này đảm bảo rằng nếu yêu cầu không thỏa mãn bất kỳ điều kiện ACL nào, nó sẽ được chuyển đến backend mặc định.
frontend my-frontend
bind *:80
acl acl1 hdr_dom(host) -i haproxy1.com
acl acl2 hdr_dom(host) -i haproxy2.com
use_backend name-backend if acl1
use_backend other-backend if acl2
default_backend default-backend
Trong ví dụ này, khối frontend có tên là my-frontend
lắng nghe trên cổng 80 và kiểm tra các điều kiện ACL acl1
và acl2
. Nếu acl1
thỏa mãn, yêu cầu sẽ được chuyển đến backend name-backend
. Nếu acl2
thỏa mãn, yêu cầu sẽ được chuyển đến backend other-backend
. Nếu cả hai điều kiện không thỏa mãn, yêu cầu sẽ được chuyển đến backend default-backend
.
Cấu hình HAProxy như vậy cho phép bạn định hướng các yêu cầu đến các backend khác nhau dựa trên các tiêu chí mà bạn đã định nghĩa trong các điều kiện ACL.
Cơ bản cấu hình HAProxy là bạn viết ra các khối frontend, backend phù hợp với yêu cầu của mình. Sau đây là một ví dụ đơn giản chạy HAProxy trên Docker để bạn có thể thực hành kiểm tra nó một cách nhanh chóng!
3. HAProxy với Docker.
Image Docker của HAproxy được cung cấp với tên haproxy
(bản cuối haproxy:latest
).
Để đảm bảo chạy được container HAProxy cần có file config haproxy.cfg
khi tạo thì copy hoặc ánh xạ vào thư mục /usr/local/etc/haproxy/haproxy.cfg
của container. Có thể chạy docker run
với tham số -v
để ánh xạ file. Tuy nhiên ở đây chúng ta sẽ nâng cao hơn là dùng kỹ thuật với Dockerfile
và docker-compose
để thực hiện chạy một container HAProxy
.
Trước tiên cần đưa ra một yêu cầu đơn giản là tạo 3 Webserver
container sử dụng 3 Container Nginx
, sau đó sử dụng HAProxy
để tiến hành cân bằng tải 3 Webserver
này.
Giờ ta sẽ từng bước thực hiện yêu cầu trên. Đầy tiên hãy hãy tạo ra một thư mục làm việc đặt tên là haproxy
để lưu các file.
cd /home/
mkdir -p haproxy
cd haproxy/
Đầu tiên trong thư mục đó tạo ra file haproxy.cfg
với nội dung:
cat > /home/haproxy/haproxy.cfg << 'OEF'
frontend http_frontend
bind *:80
mode tcp
option tcplog
default_backend http_backend
backend http_backend
mode tcp
balance roundrobin
server web1 web1:80 check
server web2 web2:80 check
server web3 web3:80 check
OEF
Tạo file Dockerfile
trong thư mục haproxy
ở trên, với nội dung.
cat > /home/haproxy/Dockerfile << 'OEF'
FROM haproxy:latest
COPY ./haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg
OEF
Tạo config cho webserver.
cat > /home/haproxy/nginx.conf << 'OEF'
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web1;
}
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web2;
}
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web3;
}
}
OEF
Tạo nội dung cho webserver.
cat > /home/haproxy/index1.html << 'OEF'
<!DOCTYPE html>
<html>
<head>
<title>Welcome to my website server 1</title>
</head>
<body>
<h1>This is the custom content of website server 1</h1>
</body>
</html>
OEF
cat > /home/haproxy/index2.html << 'OEF'
<!DOCTYPE html>
<html>
<head>
<title>Welcome to my website server 2</title>
</head>
<body>
<h1>This is the custom content of website server 2</h1>
</body>
</html>
OEF
cat > /home/haproxy/index3.html << 'OEF'
<!DOCTYPE html>
<html>
<head>
<title>Welcome to my website server 3</title>
</head>
<body>
<h1>This is the custom content of website server 3</h1>
</body>
</html>
OEF
Tạo file docker-compose.yml
trong thư mục haproxy
và nội dung nhập vào như sau.
cat > /home/haproxy/docker-compose.yml << 'OEF'
version: "3"
services:
haproxy:
build:
context: .
container_name: haproxy
restart: always
hostname: haproxy
ports:
- "80:80"
web1:
image: nginx:latest
container_name: web1
volumes:
- ./index1.html:/usr/share/nginx/html/index.html:ro
command: ["nginx", "-g", "daemon off;"]
web2:
image: nginx:latest
container_name: web2
volumes:
- ./index2.html:/usr/share/nginx/html/index.html:ro
command: ["nginx", "-g", "daemon off;"]
web3:
image: nginx:latest
container_name: web3
volumes:
- ./index3.html:/usr/share/nginx/html/index.html:ro
command: ["nginx", "-g", "daemon off;"]
OEF
Và đây là thư mục và file của mình sau khi chuẩn bị xong.
../haproxy/
├── Dockerfile
├── docker-compose.yml
├── haproxy.cfg
├── index1.html
├── index2.html
├── index3.html
└── nginx.conf
Như vậy mọi thứ đã đủ, giờ hãy chạy thử bằng cách vào thư mục haproxy
tạo ở trên và gõ.
docker-compose up -d
Tham khảo output của docker-compose up -d
.
$ docker-compose up -d
[+] Running 10/10
⠿ web2 Pulled 15.2s
⠿ web3 Pulled 15.2s
⠿ web1 Pulled 15.2s
⠿ a803e7c4b030 Pull complete 8.1s
⠿ 8b625c47d697 Pull complete 9.4s
⠿ 4d3239651a63 Pull complete 9.5s
⠿ 0f816efa513d Pull complete 9.5s
⠿ 01d159b8db2f Pull complete 9.6s
⠿ 5fb9a81470f3 Pull complete 9.7s
⠿ 9b1e1e7164db Pull complete 9.7s
[+] Building 3.0s (7/7) FINISHED
=> [internal] load .dockerignore 0.1s
=> => transferring context: 2B 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 111B 0.0s
=> [internal] load metadata for docker.io/library/haproxy:latest 1.2s
=> [internal] load build context 0.0s
=> => transferring context: 289B 0.0s
=> CACHED [1/2] FROM docker.io/library/haproxy:latest@sha256:d533c21b446c45e47dc5b89933df1e256ec09976dc5e83a4c1bea209c2baeeaa 0.0s
=> [2/2] COPY ./haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg 1.4s
=> exporting to image 0.1s
=> => exporting layers 0.1s
=> => writing image sha256:2f6d17101cd9265f1abf319bff56841e8b56d0c02f05d24c7653f6b69d2000e2 0.0s
=> => naming to docker.io/library/haproxy_haproxy 0.0s
[+] Running 5/5
⠿ Network haproxy_default Created 0.1s
⠿ Container web3 Started 1.1s
⠿ Container haproxy Started 1.3s
⠿ Container web1 Started 1.0s
⠿ Container web2 Started 1.2
Vậy là đã có container đang chạy, giờ tại trình duyệt bạn vào địa chỉ http://<ip_address>
bạn nhận được kết quả của container web1 trả về.
Nếu bạn tải lại hoặc mở một tab khác, khả năng bạn sẽ nhận được một kết quả khác của một container khác trả về, ví dụ của mình hiện tại đang là web3.
4. Kết Luận.
Với HAProxy, bạn có thể tạo một môi trường Docker mạnh mẽ, cân bằng tải hiệu quả và bảo mật bằng cách sử dụng reverse proxy. HAProxy là một công cụ mạnh mẽ được sử dụng rộng rãi trong ngành công nghiệp để quản lý và phân phối tải đối với các ứng dụng và dịch vụ web.