Postgres initdb 실패 — 볼륨 루트의 lost+found
쿠버네티스에 Postgres 를 하나 올렸더니 파드가 뜨자마자 CrashLoopBackOff 로 돌기 시작했습니다.
DB 라 파드가 죽어도 데이터는 남아야 하니 EBS 를 PVC 로 잡고, 그 볼륨을 컨테이너 안의 데이터
디렉토리(/var/lib/postgresql/data)에 그대로 마운트했습니다. 공식 이미지가 그 경로를 데이터
디렉토리로 쓰니 볼륨도 거기다 붙이면 되겠다고 봤습니다.
컨테이너가 시작하자마자 죽으니 처음엔 이미지를 의심했습니다. 그다음으로는 볼륨 권한. Postgres 는 데이터 디렉토리의 소유자와 퍼미션에 까다로워서 이쪽이 흔한 원인이기도 한데, 둘 다 아니었습니다.
증상 — 디렉토리가 안 비었다며 멈추는 initdb
initdb: error: directory "/var/lib/postgresql/data" exists but is not empty
It contains a lost+found directory, perhaps due to it being a mount point.
initdb 는 데이터 디렉토리가 완전히 비어 있어야 초기화를 시작합니다. 방금 만든 빈 볼륨을
붙였는데도 안 비었다고 합니다. 메시지가 이유까지 짚어 줍니다 — lost+found 라는 디렉토리가 있고, 아마 그 자리가 마운트
지점이라 그럴 거라고 합니다.
원인 — 데이터 디렉토리에 직접 마운트한 EBS
ext4 로 포맷할 때 파일시스템이 최상위에 lost+found 디렉토리를 같이 만들어 두기 때문에, 그
볼륨을 마운트하면 마운트 지점에 이 디렉토리가 그대로 올라옵니다. fsck 가 복구한 조각을 넣어 두는
표준 디렉토리라 사용자가 만들지 않아도 항상 있습니다. 볼륨은 비어 있는 게 맞았고, 그 위에
파일시스템이 자기 디렉토리를 하나 얹어 둔 상태였습니다.
EBS 볼륨을 /var/lib/postgresql/data 에 바로 마운트했으니, 그 lost+found 가 곧 데이터
디렉토리 안의 정체불명 디렉토리가 됐습니다. initdb 가 보기에는 안 빈 디렉토리라 거부한 겁니다.
볼륨 루트를 그대로 데이터 디렉토리로 쓰는 DB 는 다 같은 자리에서 걸리니, Postgres 만의 얘기는 아닙니다.
해결 — 마운트 지점 아래 하위 디렉토리를 데이터 디렉토리로
마운트 지점 자체를 데이터 디렉토리로 쓰지 말고 그 아래 하위 디렉토리를 쓰면 되고, Postgres 는
PGDATA 로 지정합니다.
PGDATA=/var/lib/postgresql/data/pgdata
lost+found 는 마운트 지점인 .../data 에 생깁니다. initdb 가 보는 건 그 아래 pgdata 고,
거기는 비어 있으니 통과했습니다. 마운트는 루트에, 데이터는 한 칸 아래로.
옛 ReplicaSet이 파드를 계속 재생성
고치고 나서도 옛날 스펙의 파드가 자꾸 다시 떴고, 이전 ReplicaSet 이 남아서 파드를 계속 재생성하고 있었습니다. 루프를 끊으려면 그 ReplicaSet 을 직접 0 으로 내려야 합니다.
kubectl scale rs <old-rs> --replicas=0
rollout 이 정상으로 끝나면 Deployment 컨트롤러가 옛 ReplicaSet 을 알아서 0 으로 내려 주지만, 파드가 계속 죽는 바람에 rollout 자체가 안 끝나서 그 정리가 안 돌고 있었습니다.
데이터 디렉토리는 마운트 지점 한 칸 아래
빈 볼륨인데 안 비었다는 에러가 나오면 lost+found 부터 의심하면 됩니다. ext4 계열로 포맷할 때
최상위에 같이 만들어지는 디렉토리라 마운트 지점에 그대로 올라옵니다. 마운트 지점을 그대로 데이터
디렉토리로 쓰면 비어 있어야 한다는 검사를 통과하지 못합니다. DB 를 볼륨에 얹을 때는 처음부터
마운트 지점 한 칸 아래를 데이터 디렉토리로 잡아 두면 이 문제를 안 만납니다.
댓글 0