Docker

PostgreSQL 란? — 블록 탐색기 하나를 위한 전용 DB

한 줄로

Fabric Explorer(블록 탐색기) 하나만 쓰는 전용 DB 다.

애플리케이션 DB 가 아니다. 이 시스템의 본체 DB 는 따로 있고, 이건 탐색기가 화면을 그리려고
쌓아두는 사본
이다.

왜 블록체인에 DB 가 또 필요한가

Fabric Explorer 는 블록·트랜잭션을 웹 화면으로 보여주는 도구다. 그런데 원장(블록 사슬)을
직접 읽어서 화면을 그리기엔 느리다.

  • “최근 트랜잭션 20건” → 사슬 끝에서부터 뒤져야 한다
  • “시간대별 트랜잭션 수” → 전부 훑어야 한다
  • “이 조직이 만든 블록” → 전부 훑어야 한다

그래서 Explorer 는 블록을 읽어서 관계형 DB 에 다시 적재한다. 화면은 그 DB 에서 조회한다.

Fabric 원장  →  Explorer 가 읽음  →  PostgreSQL 에 적재  →  화면 조회

즉 이 DB 는 원본이 아니라 조회용 사본이다. 날아가도 원장은 멀쩡하고, 다시 적재하면 된다.

couchdb 편의 상태 DB 와 성격이 비슷하다.
블록체인 주변에는 “빠른 조회를 위한 사본” 이 이렇게 여러 개 붙는다.

alpine 을 골랐다

이미지가 postgres:13-alpine 이다. 뒤에 붙은 -alpine 이 선택이다.

태그 베이스 대략 크기
postgres:13 Debian ~130MB
postgres:13-alpine Alpine Linux ~80MB

Alpine 은 아주 작은 리눅스 배포판이다. 같은 PostgreSQL 인데 바탕 OS 를 가볍게 해서
이미지 크기를 줄인 것이다.

busybox 편에서와 같은 이유다.
폐쇄망에서는 이미지 용량이 곧 레지스트리 저장 공간이고, 옮길 때 그대로 전송량이 된다.

네트워크마다 하나씩 뜬다

Explorer 와 이 DB 는 Fabric 네트워크의 같은 네임스페이스 안에 뜬다.

fabric-{네트워크ID}
  ├─ CA · 피어 · 오더러      ← 블록체인 본체
  ├─ explorer-db            ← 이 글의 주인공
  └─ fabric-explorer        ← 탐색기

Fabric 네트워크를 만들 때마다 PostgreSQL 이 하나씩 늘어난다.
디스크는 볼륨으로 1Gi 를 잡는다.

여기서 Fabric 편에서 다룬 문제와
이어진다. 상태 판정이 네임스페이스 전체를 보기 때문에, 이 DB 파드가 죽으면
Fabric 네트워크 전체가 ERROR 로 표시된다. 블록체인 본체는 멀쩡한데도 그렇다.

스키마를 psql 11번 호출로 만든다

설치 방식이 특이하다. 마이그레이션 도구를 쓰지 않는다.

kubectl exec -n ${NS} deploy/explorer-db -- env PGPASSWORD=... psql ... -c "
  CREATE TABLE ...
"

이런 kubectl exec 호출이 11번 이어진다. 테이블을 하나씩 만드는 것이다.

폐쇄망이라 이해되는 면이 있다. Explorer 공식 배포본에는 스키마 SQL 이 들어 있지만, 그걸
컨테이너 안으로 가져다 실행하려면 파일을 옮기거나 이미지를 다시 말아야 한다. 그냥
kubectl exec 로 SQL 을 던지는 게 간단하다.

대신 약점이 뚜렷하다.

  • 중간에 실패하면 절반만 만들어진 상태로 남는다. 되돌리는 코드가 없다
  • 순서가 코드에 암묵적으로 박혀 있다 — 어떤 테이블이 어떤 것보다 먼저인지 스크립트 순서가 전부다
  • 다시 돌리면 어떻게 되는지가 명확하지 않다

DB 스키마를 절차적으로 만드는 방식의 전형적인 한계다. 항목이 11개라 지금은 관리되지만,
늘어날수록 힘들어진다.

자격증명이 평문으로 박혀 있다

이 스크립트에서 가장 걸리는 부분이다.

DB 사용자·비밀번호·DB 이름이 매니페스트와 psql 명령줄에 그대로 들어 있다.
11번의 kubectl exec 마다 비밀번호가 명령줄에 실린다.

문제가 몇 겹이다.

문제 설명
소스에 남는다 git 에 그대로 커밋돼 있다
프로세스 목록에 뜬다 명령줄 인자는 ps 로 보인다
모든 네트워크가 같다 회사·네트워크가 달라도 값이 동일하다
교체 경로가 없다 바꾸려면 스크립트를 고쳐야 한다

폐쇄망이고 클러스터가 회사별로 격리돼 있어 실제 위험은 낮다. 하지만 쿠버네티스에는
Secret 이라는 표준 수단이 있는데 안 쓴 것
이라, 고치기 어려운 종류의 문제도 아니다.

이 글에는 실제 값을 적지 않는다. 위치만 남긴다.

겪은 이슈 — 두 번째 회사부터 포트가 틀렸다

이 DB 자체가 아니라 함께 뜨는 Explorer 의 포트에서 사고가 났다.

fix(fabric): Explorer NodePort 오계산 및 TLS CA fallback 처리   (2026-04-20)

RemoteFabricService: EXPLORER_NODE_PORT를 portRangeStart+9 고정값으로 WAS에서 직접 전달
  (기존 API_SERVER_PORT+9 계산은 두 번째 이상 Fabric 생성 시 잘못된 포트 산출)

첫 회사는 멀쩡했고, 두 번째부터 틀렸다. 이런 종류가 발견이 늦다.

원인은 기준점을 잘못 잡은 것이다. 포트를 API_SERVER_PORT + 9 로 계산하고 있었는데,
회사마다 포트 대역을 나눠주는 구조에서
그 두 값은 첫 회사에서만 우연히 일치한다.

회사A : 대역 10000~10009,  API 서버 10000  →  +9 = 10009  ✅
회사B : 대역 10010~10019,  API 서버 10010  →  +9 = 10019  ✅

여기까지는 맞다. 그런데 API 서버 포트는 kind 가 실제로 잡은 값을 도커에서 긁어오는
반면, 포트 대역은 DB 에 저장된 값이다. 두 출처가 어긋나는 순간 계산이 깨진다.

고친 방식은 계산 자체를 없앤 것이다. WAS 가 portRangeStart + 9 를 직접 넘긴다.
포트 대역의 주인이 WAS 이니, 그 값을 아는 쪽이 계산해서 내려보내는 게 맞다.

같은 값을 두 곳에서 각자 계산하면 언젠가 어긋난다. 한쪽을 원본으로 정하고 나머지는
받아쓰는 게 낫다.

한 가지 더. 같은 커밋에서 cacert.pem 이 없을 때 시크릿에서 대신 가져오는 처리도
들어갔다. 인증서 파일이 항상 같은 자리에 있다고 가정했다가 깨진 것으로 보인다.

Explorer 는 비필수인데 DB 는 따라온다

한 가지 구조적으로 어색한 지점이 있다.

Fabric 배포 스크립트는 Explorer 설치를 “비필수” 로 선언한다.

... || { echo "⚠️ ... non-critical, continuing..."; }

탐색기가 없어도 블록체인은 돈다는 판단이고, 맞는 말이다.

그런데 비필수 기능 하나 때문에 PostgreSQL 파드와 1Gi 볼륨이 네트워크마다 따라붙는다.
그리고 앞서 말했듯, 그 비필수 파드가 죽으면 네트워크 전체가 ERROR 로 보인다.

비필수라면서 실패에 가장 민감한 자리에 놓여 있는 셈이다.

정리

  • Fabric Explorer 전용 DB — 원장을 다시 적재한 조회용 사본이다. 날아가도 복구 가능
  • -alpine 을 고른 이유는 크기(~130MB → ~80MB). 폐쇄망에서 용량은 곧 비용
  • Fabric 네트워크마다 하나씩 뜬다. 볼륨 1Gi 포함
  • 스키마를 kubectl exec + psql 11번으로 만든다. 마이그레이션 도구가 아니라
    중간 실패 시 절반만 남는다
  • ⚠️ 자격증명이 평문으로 매니페스트와 명령줄에 있다. 모든 네트워크가 같은 값이고
    Secret 을 쓰지 않았다
  • ⚠️ Explorer 는 “비필수” 인데, 이 DB 가 죽으면 네트워크 전체가 ERROR 로 표시된다
  • ⚠️ 두 번째 회사부터 Explorer 포트가 틀렸다. 같은 값을 WAS 와 스크립트가 각자
    계산하다 어긋났다. 한쪽을 원본으로 정하고 받아쓰도록 고쳤다

같이 읽을 글:
couchdb — 피어마다 붙는 상태 DB ·
Fabric 네트워크는 어떻게 생기나 ·
registry:2 — 자기 자신을 담고 있는 레지스트리