
Intro
안녕하세요. 환이s입니다 👋
지난 글에서는 데이터 레이크하우스 플랫폼의
여섯 번째 스택으로 Prometheus + Grafana를 Kubernetes 위에 구축하고
클러스터 모니터링 환경을 구성하는 과정을 정리해 봤습니다.
이번 글에서는 일곱 번째 스택,
Superset을 Kubernetes 환경에 구축하고
Trino와 연동해서 Delta Lake 데이터를 시각화하는 과정을 정리해보려고 합니다.

지금까지 구축한 파이프라인에서
Kafka → Spark → Delta Lake → Trino까지 데이터가 흘러왔다면,
이제 이 데이터를 비즈니스 관점으로 시각화할 도구가 필요합니다.
그 역할을 담당하는 것이 바로 Superset입니다.
이번 글에서는
- Trino 드라이버가 포함된 커스텀 이미지를 빌드하고 Harbor에 푸시하는 방법
- OCI 방식으로 Superset Helm Chart를 설치하는 방법
- Superset에서 Trino DB 연결을 등록하고 Delta Lake 데이터를 조회하는 방법
까지 순서대로 확인해 보겠습니다.
1. Superset 아키텍처 개요
본격적인 설치에 앞서,
이번 구성의 전체 아키텍처를 먼저 이해하는 것이 중요합니다.
Superset (시각화)
│ SQLAlchemy URI로 연결
▼
Trino (쿼리 엔진)
│ 메타데이터 조회
▼
Hive Metastore
│ 실제 데이터 읽기
▼
Ceph S3 (Delta Lake)
각 컴포넌트의 역할은 아래와 같습니다.
| 컴포넌트 | 역할 |
| Superset | Trino를 통해 Delta Lake 데이터를 SQL로 조회하고 차트/대시보드로 시각화 |
| Trino | Superset의 쿼리를 받아 Ceph S3의 실제 데이터를 조회하고 결과 반환 |
| PostgreSQL | Superset의 메타데이터 (대시보드, 차트, 유저 등) 영구 저장 |
| Redis | Superset Celery Worker의 캐시 및 비동기 작업 큐 |
즉, 여기서 확인할 수 있는 핵심은
Superset은 데이터를 직접 저장하지 않고,
Trino를 통해 Delta Lake 데이터를 SQL로 조회한 뒤 시각화한다는 점입니다.
2. 설치 순서
이번 구축에서 사용하는 디렉토리 구조는 아래와 같습니다.
superset/
├── helm/
│ └── 10_superset_values.yaml # Helm 커스텀 값
└── yaml/
├── 10_superset_namespace.yaml # Namespace 생성
└── 20_superset_ingress.yaml # Ingress 설정
설치 순서는 아래와 같습니다.
커스텀 이미지 빌드 및 푸시 → Namespace 생성 → Helm 설치 → Ingress 설정 → Trino 연동
3. 커스텀 이미지 빌드
Superset 공식 이미지에는 Trino 드라이버가 포함되어 있지 않습니다.
Trino 연동을 위해 trino 패키지를 추가한 커스텀 이미지를 빌드합니다.
# Dockerfile
FROM apache/superset:5.0.0
USER root
RUN /app/.venv/bin/python -m pip install --no-cache-dir psycopg2-binary trino
USER superset
빌드 후 이미지 레지스트리에 푸시합니다.
Harbor를 사용하는 경우
docker build -t harbor.local/library/superset-custom:5.0.1 .
docker push harbor.local/library/superset-custom:5.0.1
Harbor가 없는 경우
Docker Hub 또는 다른 레지스트리를 사용할 수 있습니다.
# Docker Hub
docker build -t <your-dockerhub-id>/superset-custom:5.0.1 .
docker push <your-dockerhub-id>/superset-custom:5.0.1
# 또는 직접 클러스터 노드에 이미지를 로드하는 방법 (폐쇄망 환경)
docker save <your-dockerhub-id>/superset-custom:5.0.1 -o superset-custom.tar
scp superset-custom.tar <node-ip>:/tmp/
ssh <node-ip> docker load -i /tmp/superset-custom.tar
💡 참고: 클러스터가 외부 레지스트리에 접근할 수 없는 폐쇄망 환경이라면 docker save → docker load 방식으로 각 노드에 직접 이미지를 로드할 수 있습니다.
즉, 여기서 확인할 수 있는 핵심은
/app/.venv/bin/python으로 pip install을 실행해야 한다는 점입니다.
Superset 이미지는 /app/.venv 가상환경 안에 패키지가 설치되어 있기 때문에
일반 pip install로는 반영이 되지 않습니다.
4. Namespace 생성
Superset 전용 Namespace를 먼저 생성합니다.
# yaml/10_superset_namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: superset
kubectl apply -f yaml/10_superset_namespace.yaml
5. Helm으로 Superset 설치
OCI 방식으로 Harbor에서 Superset Helm Chart를 가져옵니다.
(Harbor가 없는 환경이라면 공식 Chart를 사용할 수 있습니다.)
superset/helm/superset at master · apache/superset
Apache Superset is a Data Visualization and Data Exploration Platform - apache/superset
github.com
helm upgrade --install superset-helm \\
oci://harbor.local/helm-chart/superset \\
--version 0.15.2 \\
--namespace superset \\
-f helm/10_superset_values.yaml
💡 참고: 이전에는 로컬 .tgz 파일로 설치했다가 현재는 OCI 방식으로 변경했습니다. 로컬 tgz 방식으로 설치할 경우 아래와 같이 실행하면 됩니다.
helm upgrade --install superset-helm helm/superset-0.15.2.tgz \\
--namespace superset \\
-f helm/10_superset_values.yaml
values.yaml의 핵심 설정은 아래와 같습니다.
이미지 설정
image:
repository: harbor.local/library/superset-custom
tag: "5.0.1"
pullPolicy: IfNotPresent
initImage:
repository: harbor.local/library/superset-dockerize
tag: "dockerize"
pullPolicy: IfNotPresent
3번에서 빌드한 커스텀 이미지를 사용합니다.
리소스 설정
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
Superset 설정
configOverrides:
secret: |
SECRET_KEY = 'UEp10tAn2qzHK2wzng2f4Q6EKv26aBsDYKfrg5le9qWhihn3aPDMb+1i'
SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://admin:admin123@superset-helm-postgresql:5432/superset"
⚠️ 운영 환경에서는 SECRET_KEY와 DB 접속 정보를 Kubernetes Secret으로 분리해서 관리하는 것을 권장합니다.
PostgreSQL 설정
postgresql:
enabled: true
image:
registry: harbor.local
repository: library/postgresql
tag: "16"
auth:
username: admin
password: admin123
database: superset
primary:
persistence:
enabled: true
storageClass: rook-ceph-block
size: 8Gi
Superset 메타데이터를 Ceph 블록 스토리지에 영구 저장합니다.
Redis 설정
redis:
enabled: true
image:
registry: harbor.local
repository: library/redis
tag: "7.2"
Pod가 Running 상태인지 확인합니다.
kubectl get pods -n superset
정상적인 경우 아래처럼 보입니다.
NAME READY STATUS RESTARTS AGE
superset-helm-xxxxxxxxxx-xxxxx 1/1 Running 0 ...
superset-helm-celerybeat-xxxxxxxxxx-xxxxx 1/1 Running 0 ...
superset-helm-postgresql-0 1/1 Running 0 ...
superset-helm-redis-master-0 1/1 Running 0 ...
superset-helm-worker-xxxxxxxxxx-xxxxx 1/1 Running 0 ...
Pod가 Running 상태가 되지 않는 경우 아래 명령어로 원인을 확인합니다.
# Pod 상태 상세 확인
kubectl describe pod <pod-name> -n superset
# Pod 로그 확인
kubectl logs <pod-name> -n superset
자주 발생하는 원인은 아래와 같습니다.
| 증상 | 원인 | 조치 |
| Pending 상태 지속 | PVC 바인딩 실패 | kubectl get pvc -n superset으로 PVC 상태 확인 |
| CrashLoopBackOff | SECRET_KEY 또는 DB URI 오류 | kubectl logs로 Superset 컨테이너 로그 확인 |
| ImagePullBackOff | 이미지 pull 실패 | Harbor 로그인 상태 또는 커스텀 이미지 빌드 여부 확인 |
6. Ingress 설정
# yaml/20_superset_ingress.yaml
spec:
ingressClassName: nginx
rules:
- host: superset.<your-ip>.sslip.io
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: superset-helm
port:
number: 8088
kubectl apply -f yaml/20_superset_ingress.yaml
Superset UI는 아래 주소로 접근할 수 있습니다.
http://superset.<your-ip>.sslip.io
ID: admin
PW: (values.yaml에서 설정한 패스워드)
7. Trino 연동
1.Trino 연결 테스트
Superset Pod에서 Trino로 연결이 되는지 먼저 확인합니다.
kubectl exec -n superset deploy/superset-helm -c superset -- \\
python3 -c "
import trino
conn = trino.dbapi.connect(
host='trino-service.trino.svc',
port=8080,
user='admin'
)
cur = conn.cursor()
cur.execute('SHOW CATALOGS')
print(cur.fetchall())
"
정상적인 경우 아래처럼 보입니다.
[['delta'], ['hive'], ['jmx'], ['memory'], ['system'], ['tpcds'], ['tpch']]
즉, 여기서 확인할 수 있는 핵심은
Superset과 Trino가 서로 다른 Namespace(superset vs trino)에 있기 때문에 클러스터 내부 DNS 형식인 trino-service.trino.svc로 접근해야 한다는 점입니다.
2.Superset UI에서 DB 연결 등록
- Superset 접속 → 상단 메뉴 Settings → Database Connections 클릭
- 우측 상단 + Database 클릭
- Trino 선택
- SQLAlchemy URI 입력
trino://admin@trino-service.trino.svc:8080/delta
URI 구조는 아래와 같습니다.
| 부분 | 의미 |
| trino:// | SQLAlchemy Trino 드라이버 |
| admin | Trino 접속 유저명 |
| trino-service.trino.svc | 서비스명.네임스페이스.svc (클러스터 내부 DNS) |
| 8080 | Trino 서비스 내부 포트 |
| /delta | 카탈로그명 |
⚠️ 포트를 NodePort로 넣으면 안 됩니다.
NodePort는 클러스터 외부에서 접근할 때 사용하는 포트입니다.
Superset은 클러스터 내부에 있기 때문에 반드시 서비스 내부 포트인 8080을 사용해야 합니다.클러스터 외부 (브라우저 등) → NodePort 사용 클러스터 내부 (Superset Pod) → 서비스 포트 8080 사용
5.Test Connection 클릭 → 연결 성공 확인
6.Connect 클릭

즉, 여기서 확인할 수 있는 핵심은
URI에서 마지막 /delta가 카탈로그명을 의미한다는 점입니다.
delta 카탈로그를 통해 Delta Lake 테이블을 조회할 수 있습니다.
8. 차트 구현
DB 연결이 완료되면 Delta Lake 데이터를 기반으로 차트를 만들 수 있습니다.
Dataset 등록
- 상단 메뉴 Datasets 클릭
- + Dataset 클릭
- Database: Trino, Schema: default, Table 선택
- Add Dataset 클릭
차트 생성
- 상단 메뉴 Charts 클릭
- + Chart 클릭
- Dataset 선택 → 차트 유형 선택 (Bar Chart, Line Chart 등)
- 쿼리 조건 설정 후 Run 클릭

즉, 여기서 확인할 수 있는 핵심은
Dataset을 한 번 등록해 두면 이후 여러 차트와 대시보드에서 동일한 Dataset을 재사용할 수 있다는 점입니다.
📝 마무리
이번 글에서는
Kubernetes 위에서 Superset을 구축하고 Trino와 연동해서 Delta Lake 데이터를 시각화하는 과정을 정리해 봤습니다.
정리하면,
- 커스텀 이미지 → 공식 Superset 이미지에 trino 드라이버 추가 후 Harbor에 푸시
- Helm OCI 방식 → Harbor에서 Chart를 가져와서 설치
- PostgreSQL + Redis → Superset 메타데이터 영구 저장 + Celery 작업 큐
- Trino 연동 → trino-service.trino.svc 클러스터 내부 DNS로 연결
- Delta Lake 시각화 → Dataset 등록 → 차트 생성 → 대시보드 구성
라고 볼 수 있습니다.
특히 이번 구축에서 주의해야 할 포인트는
- pip install 시 /app/.venv/bin/python -m pip 경로로 실행해야 가상환경에 반영
- Superset과 Trino가 다른 Namespace에 있으므로 trino-service.trino.svc 형식으로 접근
- SECRET_KEY와 DB 접속 정보는 운영 환경에서 반드시 Kubernetes Secret으로 분리 권장
이 3가지였습니다.
다음 편에서는 지금까지 구축한 전체 스택을 GitOps 방식으로 관리하는 ArgoCD 구축 과정을 다뤄보겠습니다. 🙌
궁금한 점이나 추가로 다뤄줬으면 하는 내용이 있다면 언제든지 편하게 말씀해 주세요! 😊