
논문을 번역하다 보면 결과물이 여기저기 흩어진다. GPU 서버에 번역된 PDF가 쌓이고, 노트북에선 Obsidian으로 메모를 적고, 용어 사전은 또 다른 디렉토리에 있고. 어느 순간 "아까 번역한 그 논문 어디 뒀지?" 하면서 터미널을 뒤지는 자신을 발견했다.
해결책은 의외로 단순했다. 모든 걸 NFS 공유 스토리지 한 곳에 모으면 된다.
홈랩 구성은 좀 복잡하다. Samsung 990 PRO 2TB SSD를 Hyper-V에서 Proxmox로 패스스루하고, 다시 worker1 VM의 /mnt/ssd에 마운트한다. 3단계 패스스루인 셈이다. 이 SSD 위에 K8s NFS Server Pod을 띄우면 클러스터 안팎에서 같은 파일 시스템을 쓸 수 있다.
핵심 트릭은 모든 PV의 NFS 경로를 루트(/)로 통일한 것이다. 처음에는 서비스마다 하위 경로를 나눴는데 서비스 간 파일 공유가 필요해지면서 전부 루트로 바꿨다. 덕분에 Syncthing, n8n, WSL 모두 같은 디렉토리 트리를 본다.
# NFS PV - 모든 소비자가 같은 루트를 공유
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-syncthing
spec:
nfs:
server: 192.168.31.35 # MetalLB IP
path: / # 루트 통일!
mountOptions:
- nfsvers=4
claimRef: # 바인딩 고정
namespace: syncthing
name: shared-nfsn8n 번역 워크플로는 PDF를 받으면 두 가지 일을 동시에 한다. 원본 PDF를 NFS의 /shared/obsidian-vault/ 경로에 즉시 저장하고, TranslateGemma에 번역을 요청한다. 번역이 끝나면 결과 PDF도 같은 경로에 떨어진다.
Obsidian은 Syncthing을 통해 이 NFS 볼륨과 동기화된다. 그래서 번역 워크플로가 PDF를 저장하는 순간 Obsidian 볼트에도 자동으로 나타난다. WSL에서 직접 NFS를 마운트해서 파일을 편집할 수도 있다. 별도 복사나 동기화 스크립트 없이 "한 곳에 쓰면 어디서든 읽힌다"는 구조다.
논문 번역에서 가장 짜증나는 건 용어 불일치다. 같은 논문 안에서 "attention mechanism"이 "주의 메커니즘"으로도, "어텐션 메카니즘"으로도 번역되면 읽기가 힘들다. 여러 논문을 번역할수록 문제는 더 커진다.
이걸 해결하려고 마스터 용어 사전(glossary.json)을 만들었다. 모든 논문의 용어가 하나의 JSON 파일에 누적된다. 새 논문을 번역할 때 기존 용어는 마스터 사전의 번역을 그대로 쓰고, 신규 용어만 추가한다. TranslateGemma가 번역할 때 이 사전을 프롬프트에 주입해서 일관된 번역을 보장한다.
# 마스터 사전에서 기존 용어 재사용, 신규만 추가
for src, tgt in new_terms.items():
if src in master:
existing[src] = master[src] # 마스터 번역 유지
else:
master[src] = tgt
added[src] = tgt용어가 너무 많으면 컨텍스트 윈도우를 잡아먹어 번역 품질이 떨어지기도 한다. 그래서 논문별 CSV를 마스터의 부분집합으로 뽑아 해당 논문에 등장하는 용어만 주입하는 게 중요했다.
결과적으로 NFS 공유 볼륨의 구조는 이렇게 생겼다.
/shared/
obsidian-vault/
zotero-zotmoov/
public/ # 번역 원본+결과 PDF
notes/ # Obsidian 노트
paper-translate/
glossary.json # 마스터 용어 사전
papers/
paper-name.csv # 논문별 용어 CSVn8n이 obsidian-vault/에 PDF를 저장하면 Syncthing이 Obsidian으로 동기화한다. glossary.json은 번역할 때마다 갱신되고, 논문별 CSV는 그 부분집합으로 자동 생성된다.
NFS 셋업에서 가장 많이 헤맨 건 두 가지다.
첫째, kubelet이 호스트 레벨에서 NFS를 마운트하기 때문에 K8s 내부 DNS(nfs-server.shared-storage.svc)를 PV에 쓸 수 없다. MetalLB가 할당한 고정 IP를 써야 한다. 이걸 몰라서 한참 삽질했다.
둘째, NFSv4 전용 서버인데 PV에 mountOptions: [nfsvers=4]를 빼먹으면 NFSv3으로 폴백해서 마운트가 실패한다. 에러 메시지가 명확하지 않아서 원인 찾기가 어려웠다.
glossary 쪽에서는 용어를 통째로 주입했다가 컨텍스트 윈도우 문제를 겪었다. 마스터 사전에 용어가 300개 넘어가니까 본문 번역 품질이 눈에 띄게 떨어졌다. 논문별 CSV로 필요한 용어만 골라 넣는 방식으로 바꾸고 나서야 해결됐다.
돌이켜보면 이 구조의 핵심은 별거 없다. NFS로 파일 시스템을 공유하고 각 서비스가 자기 역할에 맞게 읽고 쓰는 것뿐이다. n8n은 PDF를 저장하고, TranslateGemma는 glossary를 읽고, Obsidian은 결과를 보여준다. 데이터가 이동하는 게 아니라 한 곳에 머물면서 여러 서비스가 접근하는 패턴이다.
NFS는 1984년에 나온 프로토콜이다. 40년이 넘었는데 여전히 이런 문제를 풀기에 가장 실용적인 도구라는 게 재밌다. 화려한 오브젝트 스토리지나 분산 파일시스템 대신 NFS 하나로 충분했다.