Docker
SQLite DB 파일을 Docker 볼륨에 두는 이유
컨테이너 레이어에 쓴 파일은 컨테이너가 재시작되면 사라진다. SQLite처럼 단일 파일 DB는 반드시 볼륨에 마운트해야 한다.
Docker 컨테이너는 기본적으로 stateless다. 컨테이너 안에서 파일을 만들고 수정해도, 컨테이너를 재시작하거나 새 이미지로 재배포하면 그 파일은 없어진다. 이건 이미지 레이어 위에 쌓이는 쓰기 레이어(writable layer)가 컨테이너 수명에 묶여 있기 때문이다.
SQLite는 DB 전체가 .db 파일 하나다. 이 파일을 볼륨 밖에 두면 배포할 때마다 DB가 초기화된다.
볼륨 마운트 방법
docker-compose.yml 예시:
services:
app:
image: myapp:latest
volumes:
- sqlite_data:/app/data
environment:
- DATABASE_URL=file:/app/data/prod.db
volumes:
sqlite_data:
sqlite_data는 네임드 볼륨이다. Docker가 /var/lib/docker/volumes/sqlite_data/_data에 실제 파일을 보관한다. 컨테이너가 죽어도, 이미지가 바뀌어도 이 위치의 파일은 그대로 남는다.
네임드 볼륨 vs 바인드 마운트
바인드 마운트(./data:/app/data)를 쓰면 호스트의 특정 경로와 직접 연결된다. 경로를 직접 관리할 수 있어서 백업이 쉽고 ls로 바로 볼 수 있다는 장점이 있다. 단, 호스트의 파일시스템 권한과 소유자 문제가 생길 수 있다.
네임드 볼륨은 Docker가 관리하는 격리된 공간이다. 호스트 경로를 신경 쓸 필요가 없고, Swarm 환경에서도 동작한다는 장점이 있다. 개인 프로젝트나 단일 서버라면 바인드 마운트가 오히려 직관적이다.
WAL 모드 활성화
여러 프로세스나 스레드가 SQLite에 동시 접근할 때는 WAL(Write-Ahead Logging) 모드를 켜두는 게 안전하다. 기본 모드(journal mode=DELETE)는 쓰기 중에 읽기가 블로킹된다.
PRAGMA journal_mode=WAL;
Prisma를 쓴다면 datasource에서 설정할 수 있다.
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
// connection_limit=1 도 SQLite에서는 유용하다
}
볼륨 백업
볼륨에 두면 데이터가 유지되지만, 서버 자체가 날아가면 볼륨도 함께 사라진다. 주기적으로 파일을 복사해두는 게 필요하다.
# 실행 중 컨테이너에서 DB 파일 꺼내기
docker cp app_container:/app/data/prod.db ./backup/prod-$(date +%Y%m%d).db
# 또는 볼륨에서 직접
docker run --rm -v sqlite_data:/data -v "$(pwd)/backup":/backup \
alpine cp /data/prod.db /backup/prod-$(date +%Y%m%d).db
SQLite 파일을 복사할 때는 쓰기가 없는 시점에 하거나, .backup 명령으로 일관된 스냅샷을 만드는 게 안전하다.