태스크 #13626
OpenStack Manila Driver 동적 사용 기능 지원 조사
설명
OpenStack Manila Driver 동적 사용 기능 지원에 대해서 조사한다.
프로토타이핑까지 진행한다.
오 지호님이 2달 전에 변경
조사 결론 요약¶
- 설계부터 새로 할 필요는 없다. 기존 CSI 드라이버(#13179)의 도메인 로직 — Anystor-E 조작 시퀀스, 멱등 규칙, 명명 규칙 — 은 Manila에서도 그대로 유효하다.
- 다만 코드 재사용은 불가하다. Manila 드라이버는
manila-share프로세스 내에서 동작하는 Python 클래스이므로 Go 코드가 아닌 로직만 이식한다. - 재설계가 필요한 영역은 상태 영속/재시도 메커니즘 1개 축으로 국한된다.
- 규모 추정: 기존 자산 참고 시 약 6주, 맨땅에서 시작 시 3~4개월. 차이의 대부분은 조작 시퀀스와 멱등 규칙을 재발견하는 비용이다.
"동적 사용 기능"의 의미¶
dynamic provisioning(동적 프로비저닝)으로 판단된다. K8s의 StorageClass 기반 동적 프로비저닝과 동일한 개념이다.
openstack share create NFS 100 --share-type anystor -> manila-scheduler가 backend/pool 선택 -> manila-share가 드라이버의 create_share() 호출 -> 드라이버가 Anystor-E API로 LV 생성 -> mkfs -> mount -> NFS share 생성 -> export_locations 반환 -> share status: available openstack share access create <share> ip 10.0.0.5 -> 드라이버의 update_access() 호출 -> 해당 IP에 export 허용
반대 개념(정적)은 관리자가 미리 만들어 둔 share를 openstack share manage로 사후 등록하는 방식이다. 드라이버 인터페이스에서 manage_existing/unmanage는 optional, create_share는 필수다.
즉 동적 프로비저닝은 Manila 드라이버의 별도 옵션 기능이 아니라 기본 동작이며, 요구사항은 사실상 "정상적인 Manila 드라이버 구현"과 동일하다.
선결 확인 사항 (착수 전 필수)¶
"동적"의 해석에 따라 범위가 크게 달라진다.
| 해석 | 내용 | 범위 영향 |
|---|---|---|
| 1. 동적 프로비저닝 (유력) | 위 설명대로. Manila 드라이버 기본 동작 | 본 조사 기준 |
| 2. DHSS=True | driver_handles_share_servers. 테넌트별 share server를 동적 생성하고 Neutron 네트워크에 연결 |
별도 프로젝트급. Anystor-E에 테넌트별 NFS 서버 인스턴스 개념 필요 |
| 3. 동적 확장 | extend_share/shrink_share만 지칭 |
소규모 |
확인 질문: "테넌트별로 share server를 분리해야 하는가, 공용 서비스 IP를 사용하면 되는가?" 전자면 2번으로 일정이 수 배 증가한다.
추가 확인 사항:
- Anystor-E의
SetNfsNetworkAccessAPI가 임의 IP/CIDR를 받아주는가? 사전 정의된 network zone 객체만 허용한다면update_access()구현에 우회 설계 또는 API 변경이 필요하다. 본 건 최대 리스크. - Anystor-E API의 OpenAPI spec 보유 여부. 미보유 시 실사용 37개 엔드포인트를 수기 작성해야 한다.
기존 CSI 코드 자산 재사용 판정¶
| 레이어 | LOC | 판정 | 비고 |
|---|---|---|---|
internal/storage/ |
3,362 | 핵심 자산 - 이식 | k8s 의존 2개소뿐. Python 1:1 이식 가능 |
internal/proxy/ |
7,473 | 재생성 | OpenAPI generated client -> Python 재생성 |
internal/operator/ |
2,889 | 대부분 폐기 | CRD phase state machine은 Manila에 대응물 없음 |
internal/driver/ |
1,745 | 폐기 | CSI gRPC + kubelet 마운트. Manila에 node plugin 개념 없음 |
api/v1/, charts/ |
1,144+ | 폐기 | CRD -> 없음, Helm -> manila.conf backend stanza |
그대로 이식할 항목¶
- 프로비저닝 시퀀스 (
api/v1/logicalvolume_types.gocreation phase order)LV 생성 -> mkfs -> (스냅샷이면 activate) -> mount -> chmod 777 -> Pacemaker 템플릿 fetch -> Pacemaker 리소스 적용 -> Share 생성 -> NFS enable -> NFS network access -> nfsd 재시작 - 삭제 시퀀스 (deletion phase order) - 단순 역순이 아니라 순서가 비자명함
NFS disable -> Share 삭제 -> nfsd 재시작 -> Pacemaker 삭제 -> unmount -> LV 삭제 - 멱등 판정 로직 -
internal/storage/volume_lifecycle.go의Ensure*패턴. 특히EnsureFilesystemFormatted의 재포맷 방지 판정은 누락 시 데이터 손실로 직결된다. - 404 = 성공 처리 -
DeleteLV/DeleteShare/DisableNfs - 에러 3분법 - Terminal/Transient/Orphan (
docs/spec/error-handling.md). Manila는 예외 발생 시 share가error상태로 고정되므로 transient 에러는 드라이버 내부에서 흡수해야 한다. - 명명 규칙 -
DevicePath/FSPath/ShareName/SharePath/NFSPath,rsc_<vg>,vip_<serviceIP>,tp_prefix - RSA sign-in 인증 - 토큰 캐시 + 401 자동 재시도
- Pacemaker 템플릿 처리 - 스냅샷 볼륨에
nouuid옵션 주입 등 자체 발견이 어려운 지식 포함 - thinpool 용량 계산 -
RequiredLE/ThinpoolRemainingLE - MaintenanceGuard 상태 모델 - maintenance mode <-> share 작업 상호 배제 개념 (구현은 변경)
재설계 필요 항목¶
1. 상태 영속: CRD status -> Manila DB + private_storage¶
CSI는 RPC 재시도 기반이라 "CRD 생성 후 Aborted 반환 -> Operator 비동기 처리 -> poll" 구조가 성립했다. Manila는 create_share()가 동기 블로킹이며 status 전이(creating -> available/error)는 manila manager 소관이다.
- 20단계 phase 분기 -> 단일 함수 내 순차 호출로 평탄화 (코드량 감소)
- API 재조회가 불가능한 진행도만
self.private_storage.update(share['id'], {...})에 보존 (예: PacemakerAppliedIndex,fs-formatted체크포인트)
2. 락: 프로세스 로컬 -> 분산 또는 배포 제약¶
MaintenanceGuard는 sync.Map 기반 in-memory이며 Operator 단일 replica를 전제한다. Pacemaker maintenance mode는 스토리지 클러스터 전역 상태이므로, manila-share 다중 인스턴스 환경에서 상호 배제가 깨지면 즉시 장애다.
- 대안 A: tooz(DLM) 기반 분산 락
- 대안 B: "backend당 manila-share 1개"를 배포 제약으로 명시
3. node plugin 제거¶
internal/driver/node.go 전체(NFS 마운트, RPC NULL health probe, mount timeout)는 대응물이 없다. 드라이버는 create_share()에서 export location만 반환하고 마운트는 Nova/게스트 책임이다.
신규 구현 필요 기능¶
| 항목 | 내용 | 현황 |
|---|---|---|
update_access() |
클라이언트 IP별 access rule 동적 add/delete, rule별 rw/ro | 없음. 생성 시점 networkZone 고정 모델 -> 재설계. 최대 리스크 |
_update_share_stats() |
풀별 용량, thin_provisioning, snapshot_support, driver_handles_share_servers=False 보고. manila-scheduler 배치 판단의 유일한 근거 |
ThinpoolRemainingLE 재활용 |
extend_share/shrink_share |
thin LV 확장 + XFS growfs | 없음. CSI에 ControllerExpandVolume 미구현. LvmApi.ChangeLv 활용 |
share_type extra_specs |
vg/thinpool/serviceIP 선택 | StorageClass 파라미터가 대응 |
| export_locations | NFSPath() 결과를 리스트로 반환 |
재활용 |
| 볼륨 명명 | Manila share id는 UUID(36자). LVM LV 이름 제약과 충돌 가능 | 매핑 규칙 신규 수립 |
매핑이 용이한 항목: create_snapshot/delete_snapshot/create_share_from_snapshot <- 기존 CreateSnapshot/CreateLVFromSnapshot 거의 그대로.
스킵 권장(전부 optional): DHSS=True, share group, replication, migration, manage/unmanage, revert_to_snapshot.
이식 시 주의 - CSI 잔재¶
| 항목 | 처리 |
|---|---|
| PVC 존재 검증 / orphan cleanup | external-provisioner 무한 재시도 방어용 -> 전부 삭제 |
SINGLE_NODE_WRITER 전제 |
Manila share는 본질적으로 multi-attach -> 제거 |
| PVC annotation override 계층 | 소멸. 단 mergeExportOptions의 toggle keyword 병합 로직은 export option 파싱에 재사용 |
| networkZone 정적 모델 | 동적 access rule로 전환 |
진행 계획¶
| 단계 | 내용 | 비고 |
|---|---|---|
| 0 | 선결 확인 사항 확정 | 착수 전 필수 |
| 1 | docs/spec/ 11개 문서를 Manila 관점으로 리라이트 |
코드보다 먼저 |
| 2 | update_access() <-> Anystor-E NFS API 궁합 검증 |
여기서 막히면 계획 재수립 |
| 3 | Python REST client 생성 (spec 재생성 또는 37개 엔드포인트 수기) | |
| 4 | internal/storage/ Python 이식 (멱등 판정 유지, phase 인자 제거) |
약 2,000~2,500 LOC |
| 5 | ShareDriver 서브클래스 구현 |
필수 메서드 8종 |
| 6 | 락 전략 결정 후 MaintenanceGuard 이식 |
초기에는 out-of-tree 배포를 권장한다. OpenStack in-tree 머지는 third-party CI(tempest 회귀 환경) 구축을 요구하므로 초기 비용이 크다.
리스크¶
| 리스크 | 영향 | 대응 |
|---|---|---|
| Anystor-E API가 동적 IP access rule 미지원 | 높음 - Manila 핵심 기능 미충족 | 착수 전 검증(단계 2). API 변경 필요 시 별도 일정 반영 |
| 요구사항이 DHSS=True 해석인 경우 | 매우 높음 - 일정 수 배 증가 | 착수 전 확정 |
| manila-share 다중 인스턴스 시 maintenance mode 경합 | 높음 - 스토리지 클러스터 장애 | tooz 도입 또는 배포 제약 명시 |
| OpenAPI spec 미보유 | 낮음 | 37개 엔드포인트 수기 작성 |
참고¶
최종 목표가 Kubernetes 연동인 경우, upstream에 csi-driver-manila가 이미 존재하므로 Manila 드라이버 개발만으로 Kubernetes 동적 프로비저닝 경로도 확보된다.
오 지호님이 2달 전에 변경
NFS 공유 변경 후 파일시스템 umount 시 busy target 문제 정리¶
NFS 공유를 생성/수정/제거한 뒤 해당 볼륨을 umount할 때 target is busy가 발생하는 조건과
해제 방법을 NFS 버전별로 두 환경에서 실측했습니다.
결론¶
- 공유를 제거해도(
exportfs -r) 서버가 파일시스템 참조를 놓지 않아 umount가 실패할 수 있습니다. - 한 번 발생하면 대기·재시도로는 복구되지 않습니다. 클라이언트가 파일을 닫거나 마운트를 해제해도 풀리지 않습니다.
systemctl restart nfs가 반드시 필요한 경우는 CentOS 7 + NFSv4 조합입니다.- 그 외 조합은
/proc/fs/nfsd/unlock_filesystem으로 재시작 없이 해제할 수 있습니다. - NFSv3에서 락을 사용하지 않는 클라이언트만 있으면 문제가 발생하지 않습니다.
테스트 환경¶
| 환경 A | 환경 B | |
|---|---|---|
| OS | CentOS 7.9 | Rocky Linux 10.2 |
| kernel | 3.10.0-1160.119.1.ase3.1 | 6.12.0-211.16.1.el10_2 |
| nfs-utils | 1.3.0-0.68.el7.2 | 2.8.3-5.el10 |
| nfsd threads | 8 | 16 |
| NFSv4 grace / lease | 90s / 90s | 90s / 90s |
결과 매트릭스¶
| 환경 | NFS 버전 | 서버측 상태 | unexport 후 umount | unlock_filesystem |
restart nfs |
|---|---|---|---|---|---|
| 공통 | v3 | 없음 (락 미사용) | 즉시 성공 (0초) | 불필요 | 불필요 |
| 공통 | v3 | NLM 락 보유 | busy | 해결 | 불필요 |
| Rocky 10 | v4.2 | open state | busy | 해결 | 불필요 |
| CentOS 7 | v4.2 | open state | busy | 효과 없음 | 해결 |
발생 조건¶
exportfs -r 시점에 서버 측에 클라이언트 상태가 남아 있었는지가 분기점입니다.
- NFSv3: 파일을 열고 쓰는 중이어도 서버에 상태가 없으므로 즉시 umount 가능합니다.
단
flock/fcntl락을 잡은 클라이언트가 있으면 lockd가 락을 들고 있어 busy가 됩니다. (서버/proc/locks에서 확인 가능) - NFSv4: 파일을 열고 있으면 서버가 open state를 보유하므로 busy가 됩니다. 클라이언트가 마운트만 하고 열어둔 파일이 없는 유휴 상태라면 즉시 umount 가능합니다.
추정 원인(미검증): unexport 이후 클라이언트는 서버에 CLOSE/UNLOCK을 보낼 수 없게 되므로
(ESTALE / EACCES 수신) 서버 측 상태가 정상 경로로 정리되지 못하고 고착되는 것으로 보입니다.
시도했으나 해제되지 않는 방법 (busy 상태에서)¶
| 시도 | 결과 |
|---|---|
exportfs -r 직후 umount |
busy (rc=32) |
exportfs -f 추가 후 umount |
busy |
| 5초 간격 30~60초 대기 | busy 유지 |
| 클라이언트가 열린 fd를 닫은 뒤 (60초 관찰) | busy 유지 |
| 클라이언트가 마운트를 완전히 해제한 뒤 (24초 관찰) | busy 유지 |
CentOS 7 + v4 에서 unlock_filesystem |
busy 유지 |
주의: unlock_filesystem 파일은 CentOS 7에도 존재하고 write도 rc=0으로 성공하지만, v4
open state는 해제되지 않습니다. 따라서 파일 존재 여부로 사용 가능 여부를 판단할 수 없고
OS/커널 버전과 NFS 버전을 함께 봐야 합니다.
해제 방법¶
| 방법 | 적용 | 실측 |
|---|---|---|
echo <path> > /proc/fs/nfsd/unlock_filesystem |
v3 락(양 환경), v4(Rocky 10) | 즉시 umount 성공 |
systemctl restart nfs |
CentOS 7 + v4 | 재시작 0.12초, 직후 umount 성공 |
재현 절차¶
- 서버에 XFS 볼륨을 마운트하고
/etc/exports.d/<name>.exports로 export - 원격 클라이언트에서 마운트 (
-o vers=3또는-o vers=4.2) - 클라이언트에서 상태를 만든다
- v4: 파일을 열어둔 상태 유지 (fd open + 주기적 쓰기)
- v3:
flock <파일> -c "sleep 600"으로 락 보유
- 서버에서 export 파일 삭제 후
exportfs -r(공유 제거에 해당) - 서버에서 해당 볼륨
umount시도
진단 시 참고¶
fuser -m <mountpoint>로는 점유 대상이 잡히지 않습니다. busy 상태에서도 출력이 비어 있습니다. 커널(nfsd/lockd)이 참조를 들고 있어 userspace 프로세스로 나타나지 않기 때문에, "사용 중인 프로세스 없음"으로 판단한 뒤 umount가 실패하는 형태가 됩니다.umount -f는 응답 없는 NFS 클라이언트 마운트를 강제 해제하는 용도이므로 이 상황(서버 측 커널 참조)에는 효과가 없습니다./proc/fs/nfsd/filecache의 항목 수는 클라이언트 접속 여부와 무관하게 같은 값이 나와 판정 지표로 쓸 수 없습니다. (CentOS 7에는 해당 파일이 없습니다)- v3 락 여부는 서버의
/proc/locks에서 확인할 수 있습니다.
참고: 재시작의 부작용¶
systemctl restart nfs는 노드의 nfsd를 내리므로, 같은 노드에서 서비스 중인 다른 NFS 공유의
클라이언트까지 NFSv4 상태를 잃고 grace period(기본 90초) 동안 reclaim해야 합니다.
unlock_filesystem은 대상 파일시스템만 해제하므로 이 부작용이 없습니다. 볼륨 2개를 각각
export하고 양쪽에 클라이언트를 붙인 뒤 한쪽만 처리했을 때:
| 처리한 볼륨 | 나머지 볼륨 | |
|---|---|---|
| 서버 마운트 | 해제됨 | 유지 |
| export | 제거됨 | 유지 |
| 클라이언트 | Stale file handle | 읽기/쓰기 정상 (20MB, 49.7MB/s) |
nfsd는 재시작되지 않고 threads 16을 유지했습니다.
오 지호님이 2달 전에 변경
nfsd restart 부작용 실측 결과 (CentOS 7 / Rocky 10 교차 검증)¶
앞선 노트에서 "share 삭제 시 동일 노드의 다른 NFSv4 클라이언트가 grace period(기본 90초) 동안 reclaim해야 한다"고 기록했는데, 실제로 얼마나 멈추는지는 측정된 바 없었습니다. 두 환경에서 직접 측정했고 결과가 예상과 달랐습니다.
측정 방법¶
- 서버에 loop-backed xfs 볼륨 2개(vol_a, vol_b)를 만들어 각각 별도
/etc/exports.d/*.exports로 export - 클라이언트가 양쪽을 마운트. 삭제 대상 vol_a 에는 활성 writer + fcntl locker 를 걸어둔 상태
- vol_a 삭제(unexport → daemon 조작 → umount) 시점에 vol_b 쪽에서 다음 3가지를 op 단위로 지연 측정
- 새 파일 OPEN(O_CREAT)
- 재시작 전에 열어둔 fd 에 write + fsync (기존 open state)
- fcntl lock 획득/해제
- 서버/클라이언트 역할을 서로 바꿔 양방향 측정, 각 조건 2회 이상 재현
- 환경: CentOS 7.9 (kernel 3.10.0-1160, nfs-utils 1.3.0, nfsdcltrack) / Rocky 10.2 (kernel 6.12.0-211, nfs-utils 2.8.3, nfsdcld)
결과 1 — 서버 CentOS 7.9, NFSv4.2¶
| daemon 조작 | umount | 새 open | 기존 fd write | lock 획득 |
|---|---|---|---|---|
| 없음 | 실패 (target is busy) | - | - | - |
| unlock_filesystem | 실패 (target is busy, 무효) | 영향 없음 | 영향 없음 | 영향 없음 |
| restart nfs-server (118~133ms) | 성공 42ms | 3.08s | 3.08s | 60.2 / 60.5s |
결과 2 — 서버 Rocky 10.2, NFSv4.2¶
| daemon 조작 | umount | 새 open | 기존 fd write | lock 획득 |
|---|---|---|---|---|
| 없음 | 실패 (target is busy) | 영향 없음 | 영향 없음 | 영향 없음 |
| unlock_filesystem | 성공 45 / 49ms | 11.1 / 6.9s | 영향 없음 | 11.0 / 6.7s |
| restart nfs-server (389~413ms) | 성공 61ms | 1.07s | 1.05s | 56.6s |
결과 3 — 서버 Rocky 10.2, NFSv3¶
| daemon 조작 | umount | 새 open | 기존 fd write | lock 획득 |
|---|---|---|---|---|
| 없음 | 성공 53ms | 영향 없음 | 영향 없음 | 영향 없음 |
| restart nfs-server | 성공 48ms | 6.4s | 6.4s | 91.4s |
정정 1 — grace period 는 실제로 0.75초에 끝난다¶
Rocky 10 서버 dmesg:
NFSD: Using nfsdcld client tracking operations. NFSD: starting 90-second grace period (t=75431.096) NFSD: all clients done reclaiming, ending NFSv4 grace period (t=75431.847)
nfsdcld 가 클라이언트를 추적하므로 전원이 reclaim 을 마치면 즉시 grace 를 해제합니다. 실측 0.751초.
따라서 앞선 노트의 "grace period(기본 90초) 동안 reclaim" 이라는 표현은 90초 정지를 뜻하는 것처럼 읽힐 수 있지만 사실과 다릅니다. 새 open 과 기존 파일 I/O 는 v4 에서 1~3초 면 복구됩니다. grace 는 신규 OPEN/LOCK 만 막고(NFS4ERR_GRACE), 이미 열려 있던 파일의 reclaim 은 곧바로 통과합니다.
정정 2 — 진짜 비용은 grace 가 아니라 lock 획득 1분 지연¶
grace 가 0.75초에 끝났는데도 lock 획득은 56.6초 걸렸습니다. 즉 이 지연은 grace 가 원인이 아닙니다.
- 서버/클라이언트 조합을 바꿔도 56~60초로 일관되게 재현 (EL7 서버 + EL10 클라이언트 60.2 / 60.5s, EL10 서버 + EL7 클라이언트 56.6s) → 클라이언트 상의 lock 재시도 타이머로 추정되나 원인은 규명하지 못했습니다
- NFSv3 에서 restart 하면 91.4초. 이건 lockd grace 90초를 조기 종료 없이 완주한 값과 일치
영향 범위는 "모든 I/O 정지"가 아니라 NFS 볼륨에서 fcntl lock 을 쓰는 워크로드 입니다 (SQLite, 일부 DB, leader-election lockfile 등).
따라서 스펙에 기록해야 할 부작용은 "grace 90초" 가 아니라 다음입니다.
share 삭제 시 nfsd 재시작으로 동일 노드의 다른 볼륨 클라이언트에서 fcntl lock 획득이 최대 1분 지연된다 (NFSv4 기준, 실측 56~60초). 새 파일 open 과 기존 파일 I/O 는 1~3초 내 복구된다.
확인 — unlock_filesystem 은 Rocky 10 에서만 동작¶
note 84819 의 기록대로였습니다.
- CentOS 7.9 + NFSv4.2:
echo /export/vol_a > /proc/fs/nfsd/unlock_filesystem은 rc=0 이지만 효과 없음 → umount 여전히 target is busy → restart 필수 - Rocky 10.2 + NFSv4.2: umount 성공 (45~49ms). 단 무비용은 아니고 다른 볼륨의 새 open / lock 이 7~11초 지연
발견 — NFSv3 로 마운트하면 restart 자체가 불필요¶
같은 호스트, 같은 시점, 같은 활성 부하(writer + locker)에서 프로토콜 버전만 바꿨을 때:
- NFSv4.2 →
umount: /export/vol_a: target is busy - NFSv3 →
umount OK in 53ms
target is busy 는 NFSv4 전용 문제입니다. v4 는 서버가 open state 를 유지해 unexport 만으로 참조가 풀리지 않지만, v3 는 stateless 라 unexport 직후 곧바로 umount 됩니다.
현재 CSI 는 charts/gluesys-csi/values.yaml 의 mountOptions: [] 기본값이라 커널 기본 협상 결과인 NFSv4.2 로 마운트됩니다. StorageClass 에 nfsvers=3 을 지정하면 restart 필요성 자체가 사라집니다. 다만 삭제 경로의 RestartingNfs 단계를 건너뛰려면 CSI 상의 조건 분기가 필요하고(현재는 무조건 restart), v4 전용 기능(delegation, sec=krb5*, NFSv4 ACL)을 포기하며 lock 이 NLM 으로 내려갑니다. 즉시 적용할 사항은 아니고 선택지로 기록합니다.
note 84799 ↔ 84819 정리¶
note 84799 의 "NFS 한정으로는 reload 해도 상관없을 것 같다" 는 export 설정 반영 관점에서는 맞지만, note 84819 가 밝힌 restart 의 실제 목적(unexport 후 서버 상의 파일시스템 참조 해제 → umount 가능)에는 해당하지 않습니다. 84819 가 84799 를 대체합니다. NFSv4 를 쓰는 한 삭제 경로의 restart 는 제거할 수 없습니다.
별건 버그 — libgms 의 reload 는 EL9+ 에서 동작하지 않는다¶
측정 중 발견했습니다. Rocky 10 에는 nfs.service 유닛이 존재하지 않습니다.
systemctl reload nfs -> rc=5 Unit nfs.service not found. systemctl reload nfs-server -> rc=0
libgms/lib/GMS/NFS/Kernel/Export.pm 의 save_to_file() 이 호출하는 것이 control_service(service => 'nfs', action => 'reload') 입니다. 게다가 판정이 < 0 인데 control_service 의 반환값은 GMS::Common::IPC::exec 의 $? >> 8 (0~255) 이므로 rc=5 가 걸러지지 않고 경고조차 없이 조용히 삼켜집니다.
Rocky 10 실증:
[1] /etc/exports.d/vol_c.exports 작성 [2] systemctl reload nfs -> rc=5 [3] exportfs -v | grep vol_c -> (NOT EXPORTED) [4] systemctl reload nfs-server -> rc=0 [5] exportfs -v | grep vol_c -> /export/vol_c 192.168.22.0/24(...)
결과적으로 EL9+ 에서는 생성 경로의 nfsd restart 가 export 를 반영하는 유일한 단계입니다. CentOS 7 에서는 nfs 가 nfs-server 의 alias 로 등록되어 reload 가 동작하지만(단 nfs-server 가 enable 된 상태여야 alias 가 생성됨), EL9+ 에서는 alias 가 제거되었습니다.
수정 필요 사항 2건:
Export.pm의save_to_file()/destroy()의 서비스명을nfs→nfs-server로 변경- 실패 판정을
< 0→ truthiness 로 변경 (Protocol.pm의control및set_config는 이미 올바르게 처리하고 있음)
이 버그는 Manila 와 무관하게 현재 CSI + Anystor-E on EL9+ 조합에 존재합니다.
결론¶
- GMS 에 unlock_filesystem 신규 API 를 만들 필요는 없다 (CentOS 7 에서 무효라 restart fallback 이 그대로 남으므로 코드 경로만 늘어남)
- 삭제 경로의 nfsd restart 는 유지 (NFSv4 에서 필수)
- 스펙에 기록할 부작용은 "grace 90초" 가 아니라 "동일 노드 다른 볼륨의 fcntl lock 획득 최대 1분 지연"
- libgms reload 버그(서비스명 + 실패 판정) 는 별건으로 수정 필요
부작용이 실제로 문제가 되는 조건¶
노드의 NFS 볼륨을 쓰는 워크로드가 fcntl lock 을 사용하지 않으면 restart 는 사실상 무상관입니다. 새 open 과 기존 파일 I/O 는 1~3초 내 복구되므로 체감되지 않습니다.
lock 을 쓰는 워크로드가 있을 때만 지연이 드러나고, 그때 고려할 사항은 다음입니다.
- 현재 삭제는 직렬(
MaxConcurrentReconciles: 1)이고 볼륨당RestartingNfs단계가 1회씩이므로 PVC N 개 삭제 = nfsd N 회 재시작입니다. 대량 삭제 시 lock 대기가 반복됩니다. - #13064 (Reconsile 병렬 처리) 는 이 문제를 키우는 것이 아니라, unexport 를 모아 restart 를 1회로 묶을 수 있는 개선 기회입니다.
- 노드당 share 수가 많아지면 restart 횟수가 아니라 1회 restart 의 영향 범위(같은 노드에서 영향받는 클라이언트 수)가 커집니다.
- 미측정: restart 가 연속 발생할 때 lock 지연이 누적/연장되는지는 확인하지 않았습니다. 본 측정은 단발 restart 기준입니다.
개선이 필요해질 경우의 카드는 unlock_filesystem 신규 API 가 아니라 (a) 삭제 배치화로 restart 를 1회로 묶기, (b) StorageClass nfsvers=3 입니다.