파드가 CreateContainerConfigError 또는 Failed 로 멈추고 이벤트에 다음이 남는다.
Error: failed to prepare subPath for volumeMount "data" of container "app"
볼륨 자체는 노드에 붙었는데(attach 성공) 그 안의 하위 경로를 컨테이너에 걸어 주는 단계에서 실패한 것이다. 볼륨이 아예 붙지 않는 경우와는 다른 문제이므로, 먼저 kubectl describe pod 에서 attach 단계가 지나갔는지 확인한다.
volumeMounts:
- name: data
mountPath: /var/lib/app/conf
subPath: conf
kubelet 은 볼륨을 노드의 스테이징 경로에 마운트한 뒤, 그 안의 conf 만 컨테이너에 bind mount 한다. 즉 볼륨 안에 그 경로가 실제로 있어야 한다. 없으면 kubelet 이 만들려고 시도하는데, 여기서 권한이나 파일시스템 상태 때문에 막히면 위 메시지가 난다.
같은 PVC 를 임시 파드에 subPath 없이 붙여 내용을 본다.
apiVersion: v1
kind: Pod
metadata:
name: pvc-inspect
spec:
containers:
- name: sh
image: busybox:1.36
command: ["sleep", "3600"]
volumeMounts:
- name: data
mountPath: /mnt
volumes:
- name: data
persistentVolumeClaim:
claimName: <PVC_NAME>
kubectl exec -it pvc-inspect -- ls -al /mnt
파일이 있어야 할 자리에 파일이 있는데 디렉터리로 걸었거나 그 반대인 경우에도 같은 오류가 난다. subPath 로 파일 하나를 거는 것과 디렉터리를 거는 것은 서로 다르다.
컨테이너가 비root 로 돌고 볼륨 최상위가 root 소유라면 kubelet 이 하위 디렉터리를 만들지 못한다. fsGroup 을 주어 볼륨 소유 그룹을 맞춘다.
spec:
securityContext:
fsGroup: 1000
fsGroupChangePolicy: OnRootMismatch
NFS 계열 볼륨에는 fsGroup 이 적용되지 않는다. 이 경우 서버 쪽 export 권한과 no_root_squash 여부를 본다.
노드가 비정상 종료했거나 파드가 강제로 지워지면 스테이징 경로가 남는다. 다음 파드가 그 자리에 다시 마운트하려다 실패한다.
# 문제 노드에서
mount | grep <PVC_NAME_OR_VOLUME_HANDLE>
ls /var/lib/kubelet/pods/<POD_UID>/volume-subpaths/
남아 있으면 해당 파드가 정말 없어졌는지 확인한 뒤 정리한다. 살아 있는 파드의 마운트를 풀면 그 파드가 깨진다.
umount /var/lib/kubelet/pods/<POD_UID>/volume-subpaths/<VOLUME>/<CONTAINER>/0
RHEL 계열에서 SELinux 가 강제 모드이면 컨테이너가 볼륨 경로에 접근하지 못할 수 있다. 감사 로그에 근거가 남는다.
ausearch -m avc -ts recent | tail -30
setenforce 0 은 원인 확인용이지 해결책이 아니다. 문제가 SELinux 라고 확인되면 컨텍스트를 맞춘다.
Longhorn 볼륨에서 이 오류가 나면 볼륨 상태부터 본다. Detached 나 Faulted 상태면 마운트 단계까지 오지 못한다.
kubectl get volumes.longhorn.io -n longhorn-system
kubectl get pod -n longhorn-system
노드를 비정상 재기동한 뒤라면 /var/lib/longhorn 아래에 끊어진 마운트가 남는 일이 잦다.
설정 파일 한 개를 얹으려고 subPath 를 쓰는 경우가 많은데, 이때 ConfigMap 을 subPath 로 걸면 내용이 바뀌어도 자동 갱신되지 않는다. 마운트 지점을 디렉터리로 두고 파일 전체를 얹는 방식으로 바꾸거나, 초기화 컨테이너에서 복사하는 방식으로 바꾸면 이 문제와 갱신 문제를 함께 없앨 수 있다.