Metabase를 Supabase에 안전하게 연결하기 – Read-Only Role, RLS Policy

🧭 상황 Supabase에 저장된 데이터를 시각화하기 위해 Metabase 대시보드를 셋업 🔒 Metabase 연결 시 보안 옵션 옵션 1. EC2 보안 그룹에서 IP 화이트리스트 설정 집 또는 사무실 IP만 인바운드 접근 허용 효과: 오직 본인만 Metabase 로그인 페이지에 접근 가능 단점: 이동 중이거나 다른 네트워크를 사용할 때마다 규칙을 갱신해야 함 옵션 2. 리버스 프록시 + 기본 인증 (Basic Auth) 적용 같은 EC2 인스턴스에 Nginx 리버스 프록시를 실행 Nginx에서 다음을 처리: HTTPS (TLS 인증서) Metabase 진입 전 추가 비밀번호 게이트 외부에는 443(HTTPS) 포트만 노출하고, 3000 포트는 비공개 ...

10월 29, 2025

Postgres FTS와 dbt 인덱스로 빠르고 정확한 검색 만들기

이번 글에서는 내가 KBooks 사이트에 검색 기능을 처음 추가했던 과정을 공유한다. 국립중앙도서관 API에서 수집한 모든 도서 데이터는 이미 dbt 파이프라인을 통해 Supabase(Postgres) 로 들어오고 있었다. 이제 검색을 붙여보겠다. 아래는 데이터베이스 수준에서 검색을 준비한 단계별 과정과, 각각의 결정이 왜 타당했는지에 대한 설명이다. 1. 깨끗한 출발점: silver_books 원본 데이터는 raw_nl_books에 JSON 형태로 저장된다. 여기서 dbt를 통해 silver_books 테이블을 만들었고, 각 행은 ISBN-13으로 식별되는 고유한 책 하나를 나타낸다. 유효한 ISBN만 남겨 중복을 제거했다. ...

10월 23, 2025

🚀 핀테크 배치 ETL 파이프라인 — 모듈식으로 구축하기

👉 Code, Portfolio, Blog, and LinkedIn 🎯 거래 데이터 배치 파이프라인 어느날 K-pop 데몬 헌터들이 핀테크 스타트업을 만들었다고 가정하자. 이제 그들은 매일 수백만 건의 신용카드 거래를 처리하고 이해해야 한다. ...

9월 12, 2025

💯 dbt 테스트 이해하기: 기본부터 중급까지

dbt로 데이터를 변환하고 있다면 이미 잘하고 있는 겁니다. 🙌 그런데 dbt에는 데이터를 더 깨끗하고 신뢰할 수 있게 유지하는 강력한 테스트 기능도 있다는 거, 알고 계셨나요? 이번 글에서는 다음을 다룹니다: ✅ 기본 dbt 테스트 — 빠르게 적용 가능한 기본기 🚀 중급 테스트 — 사용자 정의 로직과 재사용 가능한 매크로 ✅ 기본 dbt 테스트 (Built-in) dbt는 모델의 .yml 파일 안에서 바로 사용할 수 있는 기본 테스트들을 제공합니다. 예시: version: 2 models: - name: customers description: 고객 마스터 테이블 columns: - name: customer_id tests: - not_null - unique - name: email tests: - not_null 🔧 각 테스트가 하는 일: not_null: 컬럼에 NULL 값이 없는지 확인 unique: 값이 고유한지 검증 accepted_values: 허용된 값만 포함되어 있는지 체크 relationships: 외래 키가 참조 대상 테이블과 매칭되는지 확인 accepted_values 예시 - name: status tests: - accepted_values: values: ['active', 'inactive', 'suspended'] 이런 기본 테스트들은 생산 대시보드에 오류가 반영되기 전에 단순한 데이터 이상을 빠르게 잡을 수 있습니다. ...

6월 10, 2025

PostgreSQL의 의외의 함정: Boolean, 텍스트 I/O, 그리고 ETL 이슈

PostgreSQL은 강력하고 표준을 잘 따르는 데이터베이스입니다. 하지만 의외의 작은 함정들도 있죠. 그중 하나는 바로 boolean 값을 다루는 방식, 특히 데이터를 텍스트 형식으로 내보낼 때의 이야기입니다. 🧠 PostgreSQL의 Boolean 처리 방식: 생각과 다르다 PostgreSQL은 boolean 값을 내부적으로 1비트(bit) 만으로 효율적으로 저장합니다. 예상한 대로죠. 하지만 그 값을 텍스트로 변환하거나 COPY 같은 방식으로 내보내면, 결과는 좀 다릅니다: SELECT true::text; -- 결과: 't' SELECT false::text; -- 결과: 'f' 맞습니다 — true는 't', false는 'f' 로 표현됩니다. 이건 PostgreSQL의 텍스트 I/O 기본 동작 방식인데, 이 동작 때문에 시스템 간 데이터를 주고받을 때 미묘한 버그가 생기기도 합니다. ...

6월 10, 2025

Spark → Kafka → Postgres 파이프라인에서 UUID가 터트린 지뢰

Kafka와 Spark Structured Streaming을 이용해서 데이터 파이프라인을 구축하고 있었습니다. 완전히 컨테이너화된 시스템. 스택 구성은 이렇습니다: Kafka → 거래 데이터를 스트리밍으로 전송 Spark Structured Streaming → 실시간 처리 및 이상 거래 탐지 Postgres → 데이터 웨어하우스 모든 게 순조로웠습니다. 그런데 갑자기 등장한 한 놈. UUID 필드. 맞습니다 — UUID. 이제 어떤 일이 벌어졌는지 정확히 보여드릴게요. ✅ 원래 설계 Postgres 테이블을 이렇게 설계했죠: CREATE TABLE fact_transaction ( transaction_id UUID PRIMARY KEY, customer_id UUID REFERENCES dim_customer(customer_id), merchant_id UUID REFERENCES dim_merchant(merchant_id), ... ); Kafka는 UUID를 문자열로 직렬화해서 이벤트를 잘 뿌려주고 있었습니다 (JSON은 원래 UUID 타입이 없으니까요). ...

6월 7, 2025

🛡️ Spark Docker 스트리밍에서 Kerberos 사용자 인증 문제 해결

Spark, Kafka, Docker를 사용하여 실시간 스트리밍 파이프라인을 구축하던 중, Kerberos를 사용하지도 않았는데 Kerberos 인증과 관련된 Spark 오류가 발생했습니다. org.apache.hadoop.security.KerberosAuthException: failure to login: javax.security.auth.login.LoginException: java.lang.NullPointerException: invalid null input: name ❓ 문제가 발생한 원인은? 공식 apache/spark:3.5.0 Docker 이미지를 사용하고 있었습니다. Docker 내부의 Spark가 Hadoop의 기본 인증 메커니즘을 해결하려고 시도했습니다. Hadoop은 다음을 통해 현재 OS 사용자를 검색하려고 했습니다: UnixPrincipal(name) Docker 컨테이너 내부에서 앱이 적절한 사용자명 매핑이 없는 UID/GID로 실행되고 있었습니다. 이로 인해 다음과 같은 오류가 발생했습니다: invalid null input: name UnixPrincipal()이 null을 받았기 때문입니다. ...

6월 7, 2025

🫙 Spark Streaming의 마지막 장애물: 왜 --jars 만으로 Kafka가 안 될까

데이터 엔지니어로서 복잡한 분산 시스템을 구축하면서 마지막 장애물을 넘었을 때 느끼는 성취감은 정말 특별합니다. 오늘은 Apache Spark Structured Streaming + Kafka를 사용할 때 굉장히 답답한 문제를 공유하려고 합니다: 👉 바로 악명 높은 Failed to find data source: kafka 에러입니다. 🧨 문제: 모든 게 정상인데 Kafka만 안 된다 상황을 떠올려봅시다: Spark 클러스터 정상 구동 Postgres 연결도 문제 없음 Kafka에서 이벤트도 잘 발행됨 코드에서 .readStream.format("kafka") 호출 그런데 갑자기 다음과 같은 에러가 발생: ...

6월 7, 2025

🧚 왜 dbt를 Airflow Docker 컨테이너 안에서 실행하는가

데이터 엔지니어링 파이프라인에서 dbt와 Airflow는 종종 함께 사용된다. 여기서 자주 마주하는 설계 결정이 있다: dbt를 Airflow와 어떻게 함께 실행할 것인가? dbt를 별도의 컨테이너에서 실행하고 API나 CLI 호출로 오케스트레이션할 것인가? 아니면 dbt를 Airflow의 Docker 컨테이너 안에서 직접 실행할 것인가? 둘 다 실험해본 결과, dbt를 Airflow 컨테이너 안에서 실행하는 방식을 선호한다. 이유는 다음과 같다. ✅ 하나의 컨테이너 = 하나의 환경 Airflow DAG가 동일한 컨테이너 안에서 dbt 명령어를 직접 실행한다. 이를 통해 다음이 보장된다: 동일한 Python 버전 동일한 dbt 버전 동일한 의존성 버전 (dbt 패키지, 어댑터) 컨테이너 간 네트워킹 이슈 없음 별도의 컨테이너로 분리할 경우 다음을 관리해야 한다: ...

6월 4, 2025

🧹 데이터 클렌징: 왜 스테이징 레이어에서 클렌징을 해야 하는가

실제 데이터 엔지니어링 파이프라인에서 가장 흔한 실수 중 하나는 데이터 클렌징을 너무 뒤로 미루는 것입니다. 업스트림 데이터가 깨끗할수록 다운스트림 모델은 더 단순하고 유지보수하기 쉬워집니다. 이제 하나씩 살펴보겠습니다. ✅ 기본 원칙 가능한 한 가장 이른 단계에서 데이터를 클렌징 — 이상적으로는 스테이징 레이어에서 처리해야 합니다. ✅ 그 이유 1️⃣ 책임 분리의 명확성 스테이징 모델의 역할은 다음과 같습니다: 클렌징 표준화 (정규화) 타입 캐스팅 만약 더러운 데이터를 marts까지 (예: dim_customer, fct_transaction) 넘긴다면: 다운스트림 모델이 복잡해짐 중복 필터 발생 유지보수가 어려운 취약한 코드 생성 2️⃣ Marts 레이어는 비즈니스 로직만 담당해야 한다 Marts 레이어는 오직 다음에 집중해야 합니다: ...

6월 4, 2025