스토리지
5.1 ZFS 풀 관리
섹션 제목: “5.1 ZFS 풀 관리”풀 목록
섹션 제목: “풀 목록”pcvctl storage pool list출력 예시:
NAME SIZE USED AVAIL CAP HEALTHpcvpool 8.0T 2.1T 5.9T 26% ONLINEdatapool 4.0T 1.5T 2.5T 38% ONLINE풀 생성
섹션 제목: “풀 생성”# mirror 풀 (2-디스크 미러)pcvctl storage pool create --name datapool --vdev /dev/sdb /dev/sdc --type mirror
# raidz1 풀 (3-디스크 RAIDZ)pcvctl storage pool create --name raidpool --vdev /dev/sdb /dev/sdc /dev/sdd --type raidz1RPC 직접 호출:
echo '{"jsonrpc":"2.0","method":"storage.pool.create","params":{ "name": "datapool", "vdevs": ["/dev/sdb", "/dev/sdc"], "type": "mirror"},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool풀 상태 / 스크럽
섹션 제목: “풀 상태 / 스크럽”# 풀 헬스 (health, scrub 진행률, 용량)pcvctl storage pool health pcvpool
# 스크럽 시작pcvctl storage pool scrub pcvpool
# 풀 삭제pcvctl storage pool destroy datapool용량 예측
섹션 제목: “용량 예측”# 현재 사용량 추세 기반 용량 고갈 예측pcvctl storage pool forecast pcvpool5.2 ZFS Zvol 관리
섹션 제목: “5.2 ZFS Zvol 관리”Zvol 목록
섹션 제목: “Zvol 목록”pcvctl storage zvol list출력 예시:
NAME VOLSIZE USED REFERpcvpool/vms/web-prod 20.0G 8.5G 8.5Gpcvpool/vms/db-prod 100.0G 45.2G 45.2Gpcvpool/vms/web-staging 20.0G 8.5G 8.5G (clone)Zvol CRUD
섹션 제목: “Zvol CRUD”# zvol 생성pcvctl storage zvol create pcvpool/vms/new-disk --size 50G
# zvol 삭제pcvctl storage zvol delete pcvpool/vms/old-diskRPC 직접 호출:
# 목록echo '{"jsonrpc":"2.0","method":"storage.zvol.list","params":{},"id":"1"}' \ | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
# 생성echo '{"jsonrpc":"2.0","method":"storage.zvol.create","params":{ "name": "pcvpool/vms/test-disk", "size": "50G"},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
# 삭제echo '{"jsonrpc":"2.0","method":"storage.zvol.delete","params":{ "name": "pcvpool/vms/test-disk"},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.toolZFS 프로모트
섹션 제목: “ZFS 프로모트”클론 데이터셋을 독립 데이터셋으로 전환합니다 (원본 스냅샷 의존 해소).
pcvctl storage promote pcvpool/vms/web-staging5.3 iSCSI 관리
섹션 제목: “5.3 iSCSI 관리”iSCSI 타겟
섹션 제목: “iSCSI 타겟”
pcvctl에는iscsi서브커맨드가 없습니다. iSCSI 타겟 관리는 RPC(또는 REST·웹 UI) 로만 합니다 — 아래 예시를 쓰세요.
(이 자리에 있던pcvctl iscsi list/create/delete --name iqn.2026-04.…예시는 실제로 존재한 적이 없는 명령이었고 IQN 접두사도 틀렸습니다.
현재 접두사는iqn.2026-03.purecvisor이며, 타겟은 IQN 이 아니라vm_name으로 지정합니다 — IQN 은 데몬이 조립합니다.)
RPC 직접 호출:
# 타겟 목록 — 응답 요소는 {vm_name, tid, iqn}.# ★ 정본 식별자는 iqn 이다. tid 는 커널 LIO 와 무관한 인메모리 순번(하위 호환 잔존 필드)이므로# tid 로 커널 자원을 찾으려 하지 말 것.echo '{"jsonrpc":"2.0","method":"iscsi.target.list","params":{},"id":"1"}' \ | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
# 타겟 생성 — params 는 vm_name·zvol_path 두 개다(IQN 은 데몬이 조립한다).# vm_name 은 1~64자 [a-zA-Z0-9_-] 로 제한되며, IQN 은 iqn.2026-03.purecvisor:<vm_name> 이 된다.echo '{"jsonrpc":"2.0","method":"iscsi.target.create","params":{ "vm_name": "disk1", "zvol_path": "/dev/zvol/pcvpool/iscsi/disk1"},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
# 타겟 삭제 (멱등)echo '{"jsonrpc":"2.0","method":"iscsi.target.delete","params":{"vm_name":"disk1"},"id":"1"}' \ | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
# 이니시에이터: 원격 타겟 로그인 / 로그아웃echo '{"jsonrpc":"2.0","method":"iscsi.connect","params":{ "target_ip": "192.0.2.50", "vm_name": "disk1"},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.toolecho '{"jsonrpc":"2.0","method":"iscsi.disconnect","params":{ "target_ip": "192.0.2.50", "vm_name": "disk1"},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool타겟 백엔드는 커널 LIO다(D4 전환).
데몬은tgtadm같은 외부 명령을 실행하지 않고/sys/kernel/config/target아래 configfs 트리를 직접 만든다.
따라서tgt패키지·데몬이 필요 없고, 대신target_core_mod·iscsi_target_mod·target_core_iblock커널 모듈이 올라와 있어야 한다(/etc/modules-load.d/purecvisor-lio.conf— deb 가 conffile 로 설치하며, deb 를 쓰지 않는 배포에서만 운영자가 직접 만든다).
모듈이 없으면 데몬은 degraded 경고만 남기고 기동하며, 타겟 생성 시 실패 경로를 명확히 알려 준다.
CHAP 인증:
daemon.conf의[iscsi] chap_user/chap_password를 설정하면 타겟에 CHAP 이 적용됩니다.
타겟 측 비밀번호는 프로세스 인자로 나가지 않습니다 — 데몬이 configfsauth/password파일에 직접 씁니다(D4 전환의 목적).데몬은 타겟을 만들기 전에 자격을 검증하고, 아래 중 하나라도 걸리면 생성을 거부합니다(조용히 넘어가지 않습니다):
- 한쪽만 설정 —
chap_user만 있고chap_password가 없거나 그 반대.
그대로 두면 커널에 “인증 불필요”가 기록되어 누구나 인증 없이 그 LUN 에 접속할 수 있게 됩니다.
chap_password가 암호화 저장돼 있는데 복호에 실패한 경우(머신 ID 변경, 다른 노드에서 복원한 설정 파일 등)도 같은 경로이므로, 살아 있는 타겟의 인증이 재생성 중에 꺼지는 일이 없습니다."NULL"로 시작하는 값 — 커널이 그 자격을 미설정으로 되돌립니다.- 255자 초과 — 커널이 조용히 잘라 저장하므로 로그인이 영영 실패합니다.
- 개행이 섞인 값 — configfs 는 개행을 제거하지 않아 자격의 일부가 됩니다.
거부 시 오류 메시지는 어느 항목이 문제인지만 알려 주고 값 자체는 절대 싣지 않습니다.
이니시에이터(클라이언트) 측 CHAP도 비밀번호를
iscsiadm인자로 전달하지 않습니다.
discovery 뒤 open-iscsi 호환 lock을 잡고 같은 target/address/port의 모든 TPGT·iface node record를 0600 임시 파일과 atomic rename으로 갱신합니다.
일부 파일 갱신 중 오류가 나면 이미 교체한 record를 역순 원복하며, 무매치·symlink·중복 auth key·반쪽 CHAP 설정은 login 전에 fail-closed합니다.
discovery는discoverydb --discover로 record를 영속하며, 최종 활성/var/lib/iscsi/nodes/...record(legacy 설치는/etc/iscsi/nodes/...)에는 open-iscsi가 로그인에 사용할 비밀번호가 저장되므로 해당 트리와 root 권한은 계속 비밀 경계입니다.
같은 target이 두 root에 모두 있으면 정본을 추측하지 않고 거부합니다(ADR-0036).
5.4 스토리지 티어링
섹션 제목: “5.4 스토리지 티어링”ZFS 풀의 디스크를 NVMe/SSD/HDD 계층으로 자동 분류합니다.
# 티어 목록pcvctl storage tier list출력 예시:
TIER DEVICES IOPS LATENCYNVMe nvme0n1 500K 0.1msSSD sda, sdb 50K 0.5msHDD sdc, sdd 200 5.0ms5.5 ISO 관리
섹션 제목: “5.5 ISO 관리”# 설정된 모든 iso_dirs에서 ISO/IMG 파일 스캔pcvctl iso list출력 예시:
PATH SIZE/pcvpool/iso/ubuntu-24.04-live-server-amd64.iso 2.6G/pcvpool/iso/debian-12.0-amd64-netinst.iso 628M/var/lib/libvirt/images/cloud-init.img 384K다중 ISO 경로:
daemon.conf [storage] iso_dirs에 콤마로 구분하여 여러 디렉터리를 지정할 수 있습니다.
5.6 Prometheus 스토리지 메트릭
섹션 제목: “5.6 Prometheus 스토리지 메트릭”/api/v1/metrics에서 다음 스토리지 메트릭을 수집합니다:
# ZFS 풀 메트릭 (6개)purecvisor_zpool_size_bytes{pool="pcvpool"}purecvisor_zpool_used_bytes{pool="pcvpool"}purecvisor_zpool_free_bytes{pool="pcvpool"}purecvisor_zpool_capacity_percent{pool="pcvpool"}purecvisor_zpool_fragmentation_percent{pool="pcvpool"}purecvisor_zpool_health{pool="pcvpool"}
# 파일시스템 메트릭node_filesystem_size_bytes{mountpoint="/",fstype="ext4"}node_filesystem_avail_bytes{mountpoint="/",fstype="ext4"}node_filesystem_files{mountpoint="/"}
# Disk I/O 메트릭node_disk_reads_completed_total{device="sda"}node_disk_writes_completed_total{device="sda"}node_disk_read_bytes_total{device="sda"}node_disk_written_bytes_total{device="sda"}node_disk_io_time_seconds_total{device="sda"}