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 재시작·서비스 접근 테스트·트러블슈팅 절차도 포함한다.
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로 리다이렉트됩니다.
요청 흐름을 한 번에 보면
- 사용자는
https://ceph.dmslab.re.kr처럼 도메인으로 접속한다
- TLS 핸드셰이크 단계에서 클라이언트가 SNI 값으로 접속 도메인을 HAProxy에 전달한다
- HAProxy는
/etc/haproxy/ssl/의 인증서를 선택하고 SSL Termination을 수행한다
- 복호화된 HTTP 요청을 SNI 조건에 맞는 backend로 전달한다
- backend 응답은 다시 HAProxy를 거쳐 사용자에게 HTTPS로 반환된다
⚙️ HAProxy 설정
Frontend 설정
HAProxy의 frontend는 모든 들어오는(incoming) 트래픽을 받아서 적절한 backend로 보내주는 관문 역할을 합니다.
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을 합쳐서 사용하면 됩니다:X-Forwarded 헤더 설정
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 기반 라우팅
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)
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 checkCeph 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)
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 checkCeph에서 cephadm으로 배포된 Grafana는 각 Manager 노드의 3000번 포트에서 실행됩니다. Ceph Dashboard Backend와 동일하게 3개 노드에 대해 roundrobin 로드 밸런싱을 적용합니다.
RADOS Gateway Backend (포트 80)
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 checkRADOS Gateway는 S3 호환 오브젝트 스토리지 서비스입니다. 기본적으로 HTTP(80)로 동작하며, SSL은 HAProxy에서 종료합니다.
HAProxy 적용
1. 설정 파일 편집
sudo vi /etc/haproxy/haproxy.cfg위의 frontend와 backend 설정을 추가합니다.
2. 설정 검증
설정 파일에 문법 오류가 없는지 반드시 검증합니다:
sudo haproxy -c -f /etc/haproxy/haproxy.cfgConfiguration file is valid 메시지가 나오면 정상입니다. 이 단계를 건너뛰고 바로 재시작했다가 설정 오류로 HAProxy가 죽으면... 모든 서비스가 한 번에 접근 불가능해집니다. 꼭 검증하세요! 🙏3. HAProxy 재시작
sudo systemctl restart haproxy
sudo systemctl status haproxy🔗 Ceph Dashboard에 Grafana 연동
HAProxy까지 세팅했으면 이제 핵심인 Ceph Dashboard ↔ Grafana 연동을 진행합니다.
Ceph Dashboard는 Grafana 차트를 iframe으로 임베딩하여 클러스터 모니터링 정보를 시각적으로 표시합니다. 이 연동이 정상적으로 작동하려면 두 가지 연결이 모두 필요합니다:
- Backend 연결 (
grafana-api-url): Ceph Manager가 Grafana 대시보드의 존재 여부를 확인하는 용도
- Frontend 연결 (
grafana-frontend-api-url): 사용자의 브라우저가 실제로 Grafana에 접근하는 용도
왜 URL이 두 개나 필요할까요? 🤔
Ceph Manager(backend)는 내부 네트워크에서 Grafana에 직접 접근할 수 있지만, 사용자의 브라우저(frontend)는 외부 네트워크에 있을 수 있습니다. HAProxy를 통해 접근하는 환경에서는 두 URL이 다를 수 있기 때문에, Ceph는 이를 분리하여 설정할 수 있도록 제공합니다.
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 --> GrafanaGrafana 연동에서 헷갈리기 쉬운 지점
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 환경에서는 커스텀 설정)에서:[security]
allow_embedding = true익명 접근 허용
Ceph Dashboard의 iframe에서 Grafana에 접근할 때 별도의 로그인 없이 차트를 볼 수 있도록 익명 접근을 설정합니다:
[auth.anonymous]
enabled = true
org_name = Main Org.
org_role = ViewerGrafana URL 설정
현재 설정 확인
먼저 현재 Grafana 설정 상태를 확인합니다:
ceph dashboard get-grafana-api-url
ceph dashboard get-grafana-frontend-api-urlBackend API URL 설정
Ceph Manager가 Grafana의 존재를 확인할 때 사용하는 URL입니다. 내부 네트워크에서 접근 가능한 주소를 지정합니다:
ceph dashboard set-grafana-api-url https://gf.ceph.dmslab.re.krFrontend API URL 설정
사용자의 브라우저가 Grafana에 접근할 때 사용하는 URL입니다. HAProxy를 통해 접근하는 외부 도메인을 지정합니다:
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 검증 오류가 발생할 수 있습니다:
ceph dashboard set-grafana-api-ssl-verify False추가 Grafana 설정 (선택사항)
필요한 경우 Grafana 접근 계정도 설정할 수 있습니다:
# Grafana API 사용자 설정
ceph dashboard set-grafana-api-username admin
# Grafana API 비밀번호 설정
ceph dashboard set-grafana-api-password <password>설정 확인
변경된 모든 설정을 한 번에 확인합니다:
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 임베딩 확인
- Ceph Dashboard(
https://ceph.dmslab.re.kr)에 로그인
- Cluster → Hosts 또는 Performance 메뉴로 이동
- Grafana 차트가 iframe 내에 정상적으로 표시되는지 확인
Grafana 차트가 보이지 않는다면 브라우저 개발자 도구(F12)의 Console 탭에서 에러 메시지를 확인하세요. 대부분 mixed content 문제이거나
X-Frame-Options 관련 이슈입니다.HAProxy 상태 확인
# HAProxy 프로세스 상태
sudo systemctl status haproxy
# Backend 서버 상태 확인 (HAProxy stats socket 사용)
echo "show stat" | sudo socat stdio /var/run/haproxy.sock🔧 트러블슈팅
Grafana 차트가 표시되지 않는 경우
이건 정말 다양한 원인이 있을 수 있습니다. 순서대로 확인해보세요:
- Grafana
allow_embedding설정 확인 — 이게false면 iframe이 아예 차단됩니다
- anonymous auth 설정 확인 — 로그인 창이 iframe 안에 뜨는 경우
grafana-frontend-api-url확인 — 브라우저에서 접근 가능한 URL이어야 합니다
- SSL 인증서 확인 — 브라우저가 self-signed 인증서를 차단할 수 있습니다
# 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-verifyself-signed 인증서를 사용하는 경우, Grafana URL을 브라우저에서 직접 한 번 접속하여 보안 예외를 수락해야 합니다. 그래야 Ceph Dashboard 내의 iframe에서도 정상적으로 로드됩니다.
SSL 인증서 문제
SSL 관련 오류가 발생하는 경우:
# 인증서 파일 확인
sudo ls -la /etc/haproxy/ssl/
# 특정 도메인의 인증서 유효성 검사
openssl s_client -connect gf.ceph.dmslab.re.kr:443 -servername gf.ceph.dmslab.re.krBackend 연결 실패
HAProxy에서 backend 서버로 연결이 안 되는 경우:
# 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 로그를 확인하면 원인을 빠르게 찾을 수 있습니다:
# 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 설정