HAProxy+DockerでCustomHeaderを追加するサンプルと設定
Aug 25, 2024 16:40 · 1457 words · 3 minute read
Dockerで動かしているWebアプリの前段にHAProxyを使っている事例を見かけました。 HAProxyを使って下記の2つを実現しています。
- Webアプリを制御するCustom Headerを追加
- HAProxyをHTTPSの終端にして、HTTPS対応が少し面倒な背後のWebアプリにHTTPリクエストを流す
HAProxyを初めて知ったので、サンプルコードを書いて動かしてみました。
目次
HAProxyの公式ドキュメント
HAProxy - The Reliable, High Perf. TCP/HTTP Load Balancer
各バージョンのドキュメントの一覧です。
HAProxy Documentation Converter
最新のLTS版、HAProxy 3.0 (LTS)のドキュメントトップはこちら。 基本機能の解説だけでなく、設定ファイルの解説や運用のガイドもあります。
- HAProxy version 3.0.3-28 - Starter Guide
- HAProxy version 3.0.3-28 - Configuration Manual
- HAProxy version 3.0.3-28 - Management Guide
HAProxyでできること
Starter Guideで紹介されている使い方の中から、便利そうだなと思った機能を一部抜粋します。
HAProxy version 3.0.3-28 - Starter Guide
- 負荷分散
- HTTP2対応
- SSLの終端
- 統計情報の収集
- アクセス元のIPアドレスを取得し、DDoS対策をする、みたいな使い方もできるらしい
- キャッシュプロキシ
- FastCGIのゲートウェイ
- HTTPヘッダの追加や編集のような文字列のフォーマット
- Luaスクリプトでちょっとした機能を追加する
- 値をチェックし、完全にリクエストのみをWebアプリに渡す
- ヘルスチェック
とても便利そう、かつ多機能ですね。
サンプルコード
HAProxyを動かすサンプルを作ってみました。 Docker ContainerでFastAPIとHAProxyを動かし、FastAPIの前段にHAProxyを配置しています。
GitHub - kapiecii/haproxy-sample
haproxy.cfg定の概要です。
- 80番ポートのHAProxyでリクエストを受け取り、8000番ポートで動作するFastAPIにリクエストをForwardしています。
- 「X-Custom-Header」というカスタムヘッダをRequest Headerに追加しています。
- 8404番ポートでHAProxyの統計情報ページにアクセスできます。
- 統計情報ページに認証機能を追加しています。認証情報は環境変数で指定し、.envファイルで設定しています。
global
log stdout format raw local0
defaults
log global
mode http
option httplog
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend http_front
bind *:80
default_backend http_back
backend http_back
http-request set-header X-Custom-Header MyValue
server fastapi_app 127.0.0.1:8000
# Enable HAProxy stats
listen stats
bind *:8404
mode http
stats enable
stats uri /stats
stats refresh 10s
stats auth "$HAPROXY_STATS_USER":"$HAPROXY_STATS_PASSWORD"
FastAPIのコードです。 HAProxyで追加したCustom Headerをログに出力する処理を追加しています。
from fastapi import FastAPI, Request
import logging
app = FastAPI()
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
@app.middleware("http")
async def log_custom_header(request: Request, call_next):
# Extract the custom header value
custom_header_value = request.headers.get("X-Custom-Header", "Not Found")
logger.info(f"X-Custom-Header: {custom_header_value}")
response = await call_next(request)
return response
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}
動かした様子
下記のコマンドでDocker Containerを起動し、curlとWebブラウザからアクセスした様子です。
sh start-docker.sh
#!/bin/bash
# Build the Docker image
docker build -t haproxy-sample .
# Run the Docker container with environment variables
docker container run -it --name haproxy-sample --rm --env-file .env -p 80:80 -p 8404:8404 haproxy-sample
curlでアクセスします。
curl http://localhost/
こんな内容がログに出力されます。 X-Custom-Header: MyValueが追加されてますね。
INFO:fastapi-app:X-Custom-Header: MyValue
INFO: 127.0.0.1:40024 - "GET / HTTP/1.1" 200 OK
172.17.0.1:54762 [24/Aug/2024:08:50:17.585] http_front http_back/fastapi_app 0/0/0/2/2 200 146 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
ブラウザからアクセスするとこんな感じ。
統計情報の画面では下記の情報を確認できます。
統計情報をjsonでexportできます。
最後に
HAProxyを初めて動かしてみました。 独自のヘッダを追加したり、スクリプトでちょっとした処理を実装することもできるので、とても便利そうです。
負荷分散や環境のヘルスチェックもできるらしいので、それらの機能も試してみたいですね。