Skip to document
pieroot log
Markdown Preview

HAProxy를 활용한 Ceph 클러스터의 통합 리버스 프록시 설정 및 Grafana 연동 가이드

Frontmatter

HAProxy를 이용해 Ceph 클러스터의 Dashboard, Grafana, RADOS Gateway 등 여러 웹 서비스를 도메인 기반 SNI 라우팅과 SSL 종료로 단일 진입점(443)에서 제공하고, 각 서비스별 backend를 라운드로빈 로드밸런싱으로 구성한다. 또한 Ceph Dashboard와 Grafana 연동을 위해 Grafana의 iframe 허용 및 익명 인증 설정, API URL 및 프론트엔드 URL 지정, 필요 시 SSL 검증 비활성화 등을 수행한다. 설정 파일 검증·HAProxy 재시작·서비스 접근 테스트·트러블슈팅 절차도 포함한다.

HAProxy를 활용한 Ceph 클러스터의 통합 리버스 프록시 설정 및 Grafana 연동 가이드
Ceph 클러스터를 운영하다 보면 Dashboard, Grafana, RADOS Gateway 등 다양한 웹 서비스들이 각자의 포트에서 돌아가게 됩니다.
문제는 이 서비스들을 외부에 깔끔하게 노출하려면 단일 진입점이 필요하다는 거죠.
매번 https://172.30.2.101:8443이나 https://172.30.2.101:3000 같은 IP+포트 조합을 기억하는 건 솔직히 고문에 가깝습니다.
그래서 HAProxy를 사용하여 도메인 기반 reverse proxy를 구성하고, Ceph Dashboard에서 Grafana 연동까지 한 번에 정리해보겠습니다.

🤔 왜 HAProxy인가?

HAProxy(High Availability Proxy)는 TCP/HTTP 기반의 오픈소스 로드 밸런서이자 프록시 서버입니다. 높은 성능과 안정성으로 인해 GitHub, Reddit, Twitter 등 대규모 서비스에서도 사용되고 있습니다.
우리 환경에서 HAProxy를 선택한 이유는 다음과 같습니다:
  • SNI 기반 라우팅: 하나의 IP에서 도메인 이름만으로 여러 backend 서비스를 분리할 수 있음
  • SSL 종료(SSL Termination): HAProxy에서 SSL을 한 번에 처리하여 backend 서버의 부담을 줄임
  • 로드 밸런싱: Ceph 노드 3대에 대한 트래픽 분산 및 헬스 체크 지원
  • 설정이 직관적: Nginx에 비해 프록시 전용 설정이 깔끔하게 정리됨
💡
Nginx도 reverse proxy로 많이 사용되지만, HAProxy는 프록시와 로드 밸런싱에 특화되어 있어 복잡한 라우팅 규칙을 더 명확하게 표현할 수 있습니다. 특히 SNI 기반 라우팅이나 TCP 레벨 프록시가 필요한 경우 HAProxy가 더 적합합니다.

🏗️ 아키텍처 개요

전체 구성을 간단히 정리하면 이렇습니다:
도메인
서비스
Backend 포트
설명
Ceph Dashboard
8443 (HTTPS)
Ceph 클러스터 관리 대시보드
Grafana (Ceph 전용)
3000 (HTTPS)
Ceph Dashboard에 임베딩되는 Grafana
Grafana (일반)
3000
독립적으로 접근하는 Grafana
RADOS Gateway
80 (HTTP)
S3 호환 오브젝트 스토리지
모든 트래픽은 HAProxy가 443 포트(HTTPS)에서 수신하고, SNI(Server Name Indication)를 기반으로 적절한 backend로 라우팅합니다. HTTP(80)로 들어오는 요청은 자동으로 HTTPS로 리다이렉트됩니다.
HAProxy SNI 라우팅과 SSL Termination 흐름
HAProxy SNI 라우팅과 SSL Termination 흐름
🧭
요청 흐름을 한 번에 보면
  1. 사용자는 https://ceph.dmslab.re.kr처럼 도메인으로 접속한다
  1. TLS 핸드셰이크 단계에서 클라이언트가 SNI 값으로 접속 도메인을 HAProxy에 전달한다
  1. HAProxy는 /etc/haproxy/ssl/의 인증서를 선택하고 SSL Termination을 수행한다
  1. 복호화된 HTTP 요청을 SNI 조건에 맞는 backend로 전달한다
  1. backend 응답은 다시 HAProxy를 거쳐 사용자에게 HTTPS로 반환된다

⚙️ HAProxy 설정

Frontend 설정

HAProxy의 frontend는 모든 들어오는(incoming) 트래픽을 받아서 적절한 backend로 보내주는 관문 역할을 합니다.
bash
frontend dmslab_frontend
    mode http
    bind *:80
    bind *:443 ssl crt /etc/haproxy/ssl/
    http-request set-header X-Forwarded-Port %[dst_port]
    http-request set-header X-Forwarded-Proto https if { ssl_fc }
    http-request set-header X-Forwarded-For %[src]
    http-request set-header X-Forwarded-Ssl on if { ssl_fc }
    option forwardfor
    
    timeout client 30m
    redirect scheme https code 301 if !{ ssl_fc }
    
    # Ceph 관련 backend 라우팅
    use_backend ceph_backend if { ssl_fc_sni ceph.dmslab.re.kr }
    use_backend ceph_dashboard_backend if { ssl_fc_sni gf.ceph.dmslab.re.kr }
    use_backend grafana_backend if { ssl_fc_sni gf.dmslab.re.kr }
    use_backend rgw_backend if { ssl_fc_sni -i -m reg ^(([a-z0-9-]+\.)?s3\.dmslab\.re\.kr)$ }
    
    # 기타 서비스들...
    default_backend gitlab_backend
여기서 핵심 설정을 하나씩 살펴보겠습니다:

bind *:443 ssl crt /etc/haproxy/ssl/

HAProxy에서 SSL 종료(SSL Termination)를 수행합니다. /etc/haproxy/ssl/ 디렉토리에 있는 인증서 파일(.pem)을 자동으로 로드하여 각 도메인에 맞는 인증서를 매칭합니다.
📝
HAProxy의 SSL 인증서는 PEM 형식이어야 하며, 하나의 .pem 파일에 인증서 체인 + 개인키가 모두 포함되어야 합니다. Let's Encrypt를 사용하는 경우 fullchain.pem과 privkey.pem을 합쳐서 사용하면 됩니다:
cat fullchain.pem privkey.pem > /etc/haproxy/ssl/dmslab.re.kr.pem

X-Forwarded 헤더 설정

bash
http-request set-header X-Forwarded-Port %[dst_port]
http-request set-header X-Forwarded-Proto https if { ssl_fc }
http-request set-header X-Forwarded-For %[src]
http-request set-header X-Forwarded-Ssl on if { ssl_fc }
reverse proxy를 거치면 backend 서버 입장에서는 원래 클라이언트의 정보를 알 수 없게 됩니다. 이 헤더들은 원본 요청의 정보(클라이언트 IP, 프로토콜, 포트 등)를 backend에 전달해주는 역할을 합니다.
이게 없으면 Ceph Dashboard 로그에 모든 접속이 HAProxy 서버 IP에서 온 것으로 기록되어 디버깅이 상당히 곤란해집니다. (누가 접속한 건지 알 수가 없어요 😭)

SNI 기반 라우팅

bash
use_backend ceph_backend if { ssl_fc_sni ceph.dmslab.re.kr }
use_backend rgw_backend if { ssl_fc_sni -i -m reg ^(([a-z0-9-]+\.)?s3\.dmslab\.re\.kr)$ }
ssl_fc_sni는 TLS 핸드셰이크 과정에서 클라이언트가 전달하는 SNI(Server Name Indication) 값을 기반으로 라우팅합니다. 즉, 같은 IP:443으로 들어와도 도메인 이름이 다르면 다른 backend로 보낼 수 있습니다.
특히 RADOS Gateway의 경우, s3.dmslab.re.kr뿐만 아니라 bucket-name.s3.dmslab.re.kr 형태의 서브도메인도 처리해야 하므로 정규식 매칭(-m reg)을 사용했습니다.

Backend 설정

이제 각 서비스별 backend 설정을 살펴보겠습니다.
🩺
Backend에서 특히 중요한 설정
  • balance roundrobin: 정상 상태의 backend 서버로 요청을 순차 분산한다
  • check: HAProxy가 backend 상태를 주기적으로 확인한다
  • ssl verify none: backend가 self-signed 인증서를 사용할 때 TLS 검증 실패를 피한다
  • option httpchk GET /: HTTP 헬스 체크 경로를 지정해 장애 노드를 자동으로 제외한다

Ceph Dashboard Backend (포트 8443)

bash
backend ceph_backend
    mode http
    option httpchk GET /
    balance roundrobin
    server ceph1 172.30.2.101:8443 ssl verify none check
    server ceph2 172.30.2.102:8443 ssl verify none check
    server ceph3 172.30.2.103:8443 ssl verify none check
Ceph Dashboard는 기본적으로 8443 포트에서 HTTPS로 동작합니다. backend 서버에 ssl verify none을 지정하여 self-signed 인증서를 사용하는 Ceph Manager에 연결할 수 있도록 합니다.
⚠️
주의: Ceph Dashboard는 활성 Manager(active mgr)에서만 제대로 응답합니다. standby Manager에 접속하면 기본적으로 active Manager로 HTTP 303 리다이렉트가 발생합니다. HAProxy 뒤에 있을 때는 이 리다이렉트가 내부 IP를 반환하여 문제가 될 수 있으므로, standby 동작을 에러로 변경하는 것을 권장합니다:
ceph config set mgr mgr/dashboard/standby_behaviour "error"
이렇게 하면 HAProxy의 헬스 체크가 standby 노드를 자동으로 제외하게 됩니다.

Grafana Backend (포트 3000)

bash
backend ceph_dashboard_backend
    mode http
    option httpchk GET /
    balance roundrobin
    server ceph1 172.30.2.101:3000 ssl verify none check
    server ceph2 172.30.2.102:3000 ssl verify none check
    server ceph3 172.30.2.103:3000 ssl verify none check
Ceph에서 cephadm으로 배포된 Grafana는 각 Manager 노드의 3000번 포트에서 실행됩니다. Ceph Dashboard Backend와 동일하게 3개 노드에 대해 roundrobin 로드 밸런싱을 적용합니다.

RADOS Gateway Backend (포트 80)

bash
backend rgw_backend
    mode http
    balance roundrobin
    server ceph1 172.30.2.101:80 check
    server ceph2 172.30.2.102:80 check
    server ceph3 172.30.2.103:80 check
RADOS Gateway는 S3 호환 오브젝트 스토리지 서비스입니다. 기본적으로 HTTP(80)로 동작하며, SSL은 HAProxy에서 종료합니다.

HAProxy 적용

1. 설정 파일 편집

bash
sudo vi /etc/haproxy/haproxy.cfg
위의 frontend와 backend 설정을 추가합니다.

2. 설정 검증

설정 파일에 문법 오류가 없는지 반드시 검증합니다:
bash
sudo haproxy -c -f /etc/haproxy/haproxy.cfg
✅
Configuration file is valid 메시지가 나오면 정상입니다. 이 단계를 건너뛰고 바로 재시작했다가 설정 오류로 HAProxy가 죽으면... 모든 서비스가 한 번에 접근 불가능해집니다. 꼭 검증하세요! 🙏

3. HAProxy 재시작

bash
sudo systemctl restart haproxy
sudo systemctl status haproxy

🔗 Ceph Dashboard에 Grafana 연동

HAProxy까지 세팅했으면 이제 핵심인 Ceph Dashboard ↔ Grafana 연동을 진행합니다.
Ceph Dashboard는 Grafana 차트를 iframe으로 임베딩하여 클러스터 모니터링 정보를 시각적으로 표시합니다. 이 연동이 정상적으로 작동하려면 두 가지 연결이 모두 필요합니다:
  1. Backend 연결 (grafana-api-url): Ceph Manager가 Grafana 대시보드의 존재 여부를 확인하는 용도
  1. Frontend 연결 (grafana-frontend-api-url): 사용자의 브라우저가 실제로 Grafana에 접근하는 용도
💡
왜 URL이 두 개나 필요할까요? 🤔
Ceph Manager(backend)는 내부 네트워크에서 Grafana에 직접 접근할 수 있지만, 사용자의 브라우저(frontend)는 외부 네트워크에 있을 수 있습니다. HAProxy를 통해 접근하는 환경에서는 두 URL이 다를 수 있기 때문에, Ceph는 이를 분리하여 설정할 수 있도록 제공합니다.
mermaid
flowchart LR
    Browser["User Browser"] --> Dashboard["Ceph Dashboard<br>ceph.dmslab.re.kr"]
    Dashboard --> Iframe["Grafana iframe"]
    Iframe -->|grafana-frontend-api-url| HAProxy["HAProxy<br>:443"]
    HAProxy --> Grafana["Grafana<br>gf.ceph.dmslab.re.kr:3000"]

    CephMgr["Ceph Manager<br>backend"] -->|grafana-api-url| HAProxy
    HAProxy --> Grafana
🧩
Grafana 연동에서 헷갈리기 쉬운 지점
  • grafana-api-url: Ceph Manager가 Grafana API를 확인하는 서버 측 경로
  • grafana-frontend-api-url: 사용자의 브라우저가 iframe으로 Grafana를 불러오는 클라이언트 측 경로
  • HAProxy 뒤에 있을 때는 두 경로가 같은 도메인을 바라볼 수도 있지만, 내부망/외부망이 분리된 환경에서는 다르게 설정될 수 있다

Grafana 사전 설정

Ceph Dashboard에서 Grafana를 iframe으로 임베딩하려면, Grafana 쪽에서도 몇 가지 설정이 필요합니다.

allow_embedding 활성화

Grafana 6.2.0 이상에서는 보안상의 이유로 iframe 임베딩이 기본적으로 차단되어 있습니다. Ceph Dashboard에서 Grafana 차트를 표시하려면 이 설정을 반드시 활성화해야 합니다.
Grafana 설정 파일(/etc/grafana/grafana.ini 또는 cephadm 환경에서는 커스텀 설정)에서:
bash
[security]
allow_embedding = true

익명 접근 허용

Ceph Dashboard의 iframe에서 Grafana에 접근할 때 별도의 로그인 없이 차트를 볼 수 있도록 익명 접근을 설정합니다:
bash
[auth.anonymous]
enabled = true
org_name = Main Org.
org_role = Viewer
(이 설정을 안 하면 Grafana 로그인 창이 iframe 안에서 뜨는 아름다운 광경을 볼 수 있습니다)

Grafana URL 설정

현재 설정 확인

먼저 현재 Grafana 설정 상태를 확인합니다:
bash
ceph dashboard get-grafana-api-url
ceph dashboard get-grafana-frontend-api-url

Backend API URL 설정

Ceph Manager가 Grafana의 존재를 확인할 때 사용하는 URL입니다. 내부 네트워크에서 접근 가능한 주소를 지정합니다:
bash
ceph dashboard set-grafana-api-url https://gf.ceph.dmslab.re.kr

Frontend API URL 설정

사용자의 브라우저가 Grafana에 접근할 때 사용하는 URL입니다. HAProxy를 통해 접근하는 외부 도메인을 지정합니다:
bash
ceph dashboard set-grafana-frontend-api-url https://gf.ceph.dmslab.re.kr
우리 환경에서는 HAProxy가 모든 트래픽을 중계하므로 두 URL이 동일하지만, 내부/외부 네트워크가 분리된 환경에서는 다른 값을 사용할 수 있습니다.
📝
grafana-frontend-api-url을 설정하지 않으면 grafana-api-url 값이 자동으로 사용됩니다. 하지만 명시적으로 설정해두는 것을 권장합니다. grafana-api-url은 cephadm에 의해 자동으로 변경될 수 있기 때문입니다.

SSL 인증서 검증 비활성화 (self-signed 인증서 사용 시)

self-signed 인증서를 사용하는 경우, Ceph Manager가 Grafana에 접근할 때 SSL 검증 오류가 발생할 수 있습니다:
bash
ceph dashboard set-grafana-api-ssl-verify False

추가 Grafana 설정 (선택사항)

필요한 경우 Grafana 접근 계정도 설정할 수 있습니다:
bash
# Grafana API 사용자 설정
ceph dashboard set-grafana-api-username admin

# Grafana API 비밀번호 설정
ceph dashboard set-grafana-api-password <password>

설정 확인

변경된 모든 설정을 한 번에 확인합니다:
bash
ceph dashboard get-grafana-api-url
ceph dashboard get-grafana-frontend-api-url
ceph dashboard get-grafana-api-ssl-verify

✅ 검증

모든 설정을 완료했으면 실제로 잘 동작하는지 확인해봐야겠죠.

서비스 접근 테스트

각 도메인으로 접속이 되는지 확인합니다:
서비스
URL
확인 사항
Ceph Dashboard
로그인 페이지 표시
Grafana (Ceph)
Grafana 대시보드 표시
Grafana (일반)
Grafana 대시보드 표시
RADOS Gateway
S3 API 응답

Ceph Dashboard에서 Grafana 임베딩 확인

  1. Ceph Dashboard(https://ceph.dmslab.re.kr)에 로그인
  1. Cluster → Hosts 또는 Performance 메뉴로 이동
  1. Grafana 차트가 iframe 내에 정상적으로 표시되는지 확인
Grafana 차트가 보이지 않는다면 브라우저 개발자 도구(F12)의 Console 탭에서 에러 메시지를 확인하세요. 대부분 mixed content 문제이거나 X-Frame-Options 관련 이슈입니다.

HAProxy 상태 확인

bash
# HAProxy 프로세스 상태
sudo systemctl status haproxy

# Backend 서버 상태 확인 (HAProxy stats socket 사용)
echo "show stat" | sudo socat stdio /var/run/haproxy.sock

🔧 트러블슈팅

Grafana 차트가 표시되지 않는 경우

이건 정말 다양한 원인이 있을 수 있습니다. 순서대로 확인해보세요:
  1. Grafana allow_embedding 설정 확인 — 이게 false면 iframe이 아예 차단됩니다
  1. anonymous auth 설정 확인 — 로그인 창이 iframe 안에 뜨는 경우
  1. grafana-frontend-api-url 확인 — 브라우저에서 접근 가능한 URL이어야 합니다
  1. SSL 인증서 확인 — 브라우저가 self-signed 인증서를 차단할 수 있습니다
bash
# Grafana URL 직접 접근 테스트 (브라우저에서)
# https://gf.ceph.dmslab.re.kr 에 직접 접속하여 인증서를 수락합니다

# Ceph Dashboard 설정 전체 확인
ceph dashboard get-grafana-api-url
ceph dashboard get-grafana-frontend-api-url
ceph dashboard get-grafana-api-ssl-verify
💡
self-signed 인증서를 사용하는 경우, Grafana URL을 브라우저에서 직접 한 번 접속하여 보안 예외를 수락해야 합니다. 그래야 Ceph Dashboard 내의 iframe에서도 정상적으로 로드됩니다.

SSL 인증서 문제

SSL 관련 오류가 발생하는 경우:
bash
# 인증서 파일 확인
sudo ls -la /etc/haproxy/ssl/

# 특정 도메인의 인증서 유효성 검사
openssl s_client -connect gf.ceph.dmslab.re.kr:443 -servername gf.ceph.dmslab.re.kr

Backend 연결 실패

HAProxy에서 backend 서버로 연결이 안 되는 경우:
bash
# HAProxy 로그 확인
sudo tail -f /var/log/haproxy.log

# 직접 연결 테스트
curl -k https://172.30.2.101:3000    # Grafana
curl -k https://172.30.2.101:8443    # Ceph Dashboard

# 방화벽 확인
sudo iptables -L -n | grep -E '3000|8443'

Ceph Manager 로그 확인

Grafana 연동에 문제가 있을 때 Ceph Manager 로그를 확인하면 원인을 빠르게 찾을 수 있습니다:
bash
# Ceph Manager 로그 확인
ceph log last ceph-mgr

# Dashboard 모듈 재시작 (설정 적용이 안 될 때)
ceph mgr module disable dashboard
ceph mgr module enable dashboard

정리

이 문서에서는 HAProxy를 사용하여 Ceph 클러스터의 여러 서비스에 대한 reverse proxy를 구성하고, Ceph Dashboard에서 Grafana를 연동하는 전체 과정을 다루었습니다.
처음에는 단순히 HAProxy 설정만 하면 될 줄 알았는데, Grafana의 allow_embedding 설정, frontend-api-url과 api-url의 차이, standby Manager의 리다이렉트 문제 등 생각보다 신경 쓸 부분이 많았습니다.

핵심 정리

✅ HAProxy Frontend: SNI 기반 라우팅으로 도메인별 서비스 분리 및 SSL 종료
✅ Backend 설정: Ceph 3개 노드에 roundrobin 로드 밸런싱 + 헬스 체크
✅ standby 동작 변경: standby_behaviour를 error로 설정하여 HAProxy와의 호환성 확보
✅ Grafana 임베딩: allow_embedding = true 및 anonymous auth 설정 필수
✅ URL 이중 설정: grafana-api-url(backend용)과 grafana-frontend-api-url(브라우저용) 분리
✅ SSL 검증: self-signed 인증서 사용 시 set-grafana-api-ssl-verify False 설정

참고 자료