컨테이너 관리
PureCVisor는 LXC 컨테이너의 ZFS backend와 명시적으로 선택하는 Btrfs backend를 관리합니다.
4.1 컨테이너 생성
섹션 제목: “4.1 컨테이너 생성”초기 2.0.0 태그의 LXC 생성은 ZFS 전용입니다.
공개 소스
e028ef2부터
선택형 Btrfs backend가 구현되어 있으며, 기본값과 제품 버전은 zfs·2.0.0으로
유지합니다.
새 태그나 버전 인상을 뜻하지 않으므로 설치한 소스 commit을 확인하세요.
지정 Arch/Btrfs 호스트의 실제 API 통합 검증을 통과했으며 Btrfs API 검증 기록에
결과를 별도로 기록합니다.
설계 계약은 ADR-0058을 따릅니다.
기본 ZFS backend
섹션 제목: “기본 ZFS backend”[container] storage_backend=zfs가 기본값입니다.
이 backend에는 사용 가능한 ZFS 풀,
ZFS 커널 모듈과 zfs 명령이 필요합니다.
[storage] container_pool은 컨테이너용
부모 파일시스템 dataset이며 기본값은 pcvpool/containers입니다.
부모 dataset이 없으면
생성 과정에서 만들기를 시도합니다.
VM용 블록 볼륨 zvol을 별도로 만들 필요는 없습니다.
명시적인 Btrfs backend
섹션 제목: “명시적인 Btrfs backend”Btrfs를 사용할 때는 daemon.conf에 다음 값을 명시합니다.
[container]storage_backend = btrfslxc_path = /var/lib/purecvisor/lxcrootless = falselxc_path는 실제로 mount된 Btrfs 위의 절대 경로여야 합니다.
관리 디렉터리와
상위 경로는 root가 관리하고, 관리 디렉터리는 그룹·다른 사용자가 쓸 수 없어야 하며
symlink 경로는 허용하지 않습니다.
LXC 런타임과 Btrfs 커널 지원을 준비하고,
btrfs-progs로 파일시스템과 subvolume을 점검합니다.
이미 Btrfs인 경로를 선택한 뒤
다음과 같이 확인할 수 있습니다.
이 명령은 파일시스템을 생성하거나 변환하지 않습니다.
sudo install -d -o root -g root -m 0755 /var/lib/purecvisor/lxcfindmnt -T /var/lib/purecvisor/lxc -o TARGET,FSTYPE,OPTIONSsudo btrfs filesystem show /var/lib/purecvisor/lxcBtrfs 생성은 lxc-create -B btrfs를 사용합니다.
rootless=false인 privileged
컨테이너만 지원하며, 요청에서 rootless=true를 지정해도 거부합니다.
잘못된 backend 값,
비Btrfs 경로와 식별자 불일치는 오류로 종료합니다.
일반 디렉터리 backend와 다른
backend로의 자동 폴백은 없습니다.
Btrfs LXC만 사용할 때 ZFS는 필요하지 않습니다.
LXC 7의 cgroup v2에서는 vcpu_count를 상대 CPU 배분 가중치로 기록합니다.
예를 들어 2는 cpu.weight=200이며 CPU 코어 수의 강제 상한을 뜻하지 않습니다.
1의 가중치는 100이고 최대값은 10000입니다.
v1·v2 CPU 설정이 모두 거부되면
생성을 실패로 처리합니다.
실제 CPU 상한과 상대 가중치는 구분해서 확인하세요.
Arch의 파일시스템은 설치자가 선택합니다.
조사한 Omarchy 시험 환경이 Btrfs였다는
사실을 모든 Arch 설치에 적용하지 않습니다.
기존 컨테이너와 실패 복구
섹션 제목: “기존 컨테이너와 실패 복구”각 컨테이너의 rootfs 밖 purecvisor.storage에는 backend와 실제 ZFS dataset 또는
Btrfs filesystem UUID·rootfs subvolume UUID/ID를 기록합니다.
후속 작업은 이 기록과
실제 저장소를 대조하며, 현재의 기본 backend나 pool 이름으로 다시 계산하지 않습니다.
기본값 변경은 기존 컨테이너의 변환·이동이 아닙니다.
marker 없는 기존 ZFS는 실제
mountpoint와 dataset이 정확히 일치할 때만 호환하며, marker 없는 Btrfs를 자동 편입하지 않습니다.
생성 실패 후 marker가 없는 디렉터리나 subvolume이 남으면 데이터를 보존하고 작업을
거부합니다.
이름이나 현재 설정만으로 삭제 대상을 추측하지 않습니다.
오류·설정·mount와
subvolume identity를 확보한 뒤 관리자가 생성 결과를 확인해야 하며, marker를 임의로
작성하거나 경로를 재귀 삭제해서 성공 상태로 만들지 마세요.
# 설정한 backend로 생성 (기본값은 ZFS)pcvctl container create --name app-ctr --dist ubuntu --release noble
# 생성 요청 후 반환된 job_id의 completed 상태를 확인하고 시작pcvctl container create --name web-ctr --dist ubuntu --release jammy# 아래 작업 결과 조회 절차로 완료를 확인한 뒤 실행pcvctl container start web-ctrRPC 직접 호출:
echo '{"jsonrpc":"2.0","method":"container.create","params":{ "name": "app-ctr", "image": "ubuntu:noble"},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool비동기 작업 결과: 생성·시작·중지·삭제·복제와 snapshot 생성·복원·삭제는
status=accepted와job_id를 먼저 반환합니다.
접수는 완료가 아닙니다.
작업 worker의 실제 결과를GET /api/v1/jobs/<job_id>의status=completed|failed와 오류detail, WebSocketjob.complete, audit 기록으로 확인합니다.
Web UI도 최종 job 결과를 기다립니다.
목록에 컨테이너가 보이는 것만으로 생성 성공을 판정하지 마세요.
JOB_ID="<accepted-response-job-id>"curl -s -H "Authorization: Bearer $TOKEN" \ "http://127.0.0.1:8080/api/v1/jobs/${JOB_ID}" | python3 -m json.tool4.2 라이프사이클
섹션 제목: “4.2 라이프사이클”# 시작 (cgroup v2 리소스 제한 자동 적용)pcvctl container start app-ctr
# 중지 (오퍼레이션 잠금으로 동시 실행 방지)pcvctl container stop app-ctr
# 삭제pcvctl container destroy app-ctr
# 목록 조회pcvctl container listREST API:
# 컨테이너 목록curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8080/api/v1/containers | python3 -m json.tool
# 컨테이너 시작curl -X POST -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8080/api/v1/containers/app-ctr/start
# 컨테이너 중지curl -X POST -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8080/api/v1/containers/app-ctr/stop4.3 명령 실행
섹션 제목: “4.3 명령 실행”# 단일 명령pcvctl container exec app-ctr "hostname -I"
# 패키지 업데이트pcvctl container exec app-ctr "apt update && apt upgrade -y"
# 서비스 상태 확인pcvctl container exec app-ctr "systemctl status nginx"4.4 리소스 제한 (cgroup v2)
섹션 제목: “4.4 리소스 제한 (cgroup v2)”# CPU/메모리 제한 설정pcvctl container set-limits app-ctr --cpu_quota 50 --memory_mb 1024# --cpu_quota: CPU quota# --memory_mb: 메모리 제한 (MB)RPC 직접 호출:
echo '{"jsonrpc":"2.0","method":"container.set_limits","params":{ "name": "app-ctr", "cpu_percent": 50, "memory_mb": 1024},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool네트워크 대역폭 QoS
섹션 제목: “네트워크 대역폭 QoS”# 대역폭 제한 (tc qdisc 기반, KB/s)pcvctl container set-bandwidth app-ctr --inbound 100000 --outbound 1000004.5 컨테이너 메트릭
섹션 제목: “4.5 컨테이너 메트릭”# 개별 컨테이너 메트릭pcvctl container metrics app-ctr출력 예시:
Container: app-ctr (RUNNING) CPU: 8.3% Memory: 256/1024 MB PIDs: 42 Net: eth0 RX 15.2MB TX 3.1MB4.6 컨테이너 스냅샷
섹션 제목: “4.6 컨테이너 스냅샷”Btrfs snapshot은 정지된 privileged 컨테이너의 rootfs만 읽기 전용 subvolume으로
저장합니다.
생성·복원·삭제 중에는 컨테이너 작업 lock을 사용합니다.
nested subvolume,
실제로 연결된 외부 mount, 설정된 외부 bind volume 또는 lxc.mount.fstab이 있으면
복제·snapshot·복원을 거부합니다.
해당 데이터가 snapshot에 포함된다고 가정하지 마세요.
복원은 현재 LXC config, owner와 image metadata를 보존하고 rootfs만 원자적으로 교체합니다.
이전·새 rootfs identity를 가진 journal로 중단된 복원을 판별하며, 다음 저장소 변경 또는
시작 전에 정지 상태와 lock 아래에서 복구합니다.
모호한 identity는 데이터를 보존하고
오류로 남깁니다.
삭제는 관리 rootfs와 snapshot을 먼저 검증하고, 부분 실패 시 남은
marker·삭제 기록을 이용해 같은 삭제 요청을 재시도합니다.
Btrfs의 rootless 컨테이너, backend 간 migration, 다른 filesystem으로의 CoW 복제, 컨테이너별 디스크 quota와 Btrfs send/receive 기반 제품 백업은 지원하지 않습니다.
# 스냅샷 생성pcvctl container snap create app-ctr --name v1
# 스냅샷 목록pcvctl container snap list app-ctr
# 롤백pcvctl container snap rollback app-ctr v1
# 삭제pcvctl container snap delete app-ctr v14.7 컨테이너 복제
섹션 제목: “4.7 컨테이너 복제”복제는 원본에 기록된 backend를 사용합니다.
Btrfs는 정지된 원본에서
lxc-copy -B btrfs -s로 CoW 복제하며, 대상은 새 저장소 identity와 원본의 image
metadata를 갖습니다.
owner는 원본의 값을 복사하지 않고 복제 요청자로 기록합니다.
# 원본 backend로 복제 (Btrfs는 정지 상태의 CoW clone)pcvctl container clone app-ctr --name app-ctr-clone4.8 볼륨 마운트
섹션 제목: “4.8 볼륨 마운트”# 호스트 디렉터리를 컨테이너에 바인드 마운트echo '{"jsonrpc":"2.0","method":"container.volume.attach","params":{ "name": "app-ctr", "host_path": "/data/shared", "container_path": "/mnt/shared", "readonly": false},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
# 볼륨 목록echo '{"jsonrpc":"2.0","method":"container.volume.list","params":{ "name": "app-ctr"},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
# 볼륨 분리echo '{"jsonrpc":"2.0","method":"container.volume.detach","params":{ "name": "app-ctr", "container_path": "/mnt/shared"},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool경로 순회 방어:
realpath검증으로 심볼릭 링크를 통한 경로 순회 공격을 차단합니다.
4.9 환경 변수
섹션 제목: “4.9 환경 변수”# 환경변수 설정 (멱등 upsert)echo '{"jsonrpc":"2.0","method":"container.env.set","params":{ "name": "app-ctr", "key": "DATABASE_URL", "value": "postgresql://localhost:5432/app"},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
# 환경변수 목록echo '{"jsonrpc":"2.0","method":"container.env.list","params":{ "name": "app-ctr"},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
# 환경변수 삭제echo '{"jsonrpc":"2.0","method":"container.env.delete","params":{ "name": "app-ctr", "key": "DATABASE_URL"},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool4.10 헬스체크
섹션 제목: “4.10 헬스체크”컨테이너에 주기적 헬스체크를 등록할 수 있습니다.
# 헬스체크 등록echo '{"jsonrpc":"2.0","method":"container.health.set","params":{ "name": "app-ctr", "cmd": "curl -sf http://localhost:8080/health || exit 1", "interval": 30, "timeout": 5, "retries": 3},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
# 헬스 상태 확인echo '{"jsonrpc":"2.0","method":"container.health.get","params":{ "name": "app-ctr"},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool상태값: healthy | unhealthy | starting
# 헬스체크 해제echo '{"jsonrpc":"2.0","method":"container.health.delete","params":{ "name": "app-ctr"},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool4.11 컨테이너 로그
섹션 제목: “4.11 컨테이너 로그”# 최근 100줄 로그 조회echo '{"jsonrpc":"2.0","method":"container.logs","params":{ "name": "app-ctr", "lines": 100},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool4.12 CRIU 체크포인트/복원
섹션 제목: “4.12 CRIU 체크포인트/복원”실행 중인 컨테이너의 상태를 저장하고 나중에 복원할 수 있습니다.
# 체크포인트 (실행 상태 저장)pcvctl container checkpoint app-ctr --dir /tmp/criu-app
# 복원 (체크포인트에서 재개)pcvctl container restore app-ctr --dir /tmp/criu-app4.13 Seccomp 프로파일
섹션 제목: “4.13 Seccomp 프로파일”# 프로파일 설정pcvctl container seccomp-set app-ctr --profile default# 현재 프로파일 조회pcvctl container seccomp-get app-ctr4.14 NIC 관리 (VM 동등 기능)
섹션 제목: “4.14 NIC 관리 (VM 동등 기능)”컨테이너도 VM과 동일한 NIC 관리 기능을 제공합니다.
# NIC 목록echo '{"jsonrpc":"2.0","method":"container.nic.list","params":{ "name": "app-ctr"},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
# NIC 추가echo '{"jsonrpc":"2.0","method":"container.nic.attach","params":{ "name": "app-ctr", "bridge": "pcvbr0"},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
# NIC 분리echo '{"jsonrpc":"2.0","method":"container.nic.detach","params":{ "name": "app-ctr", "interface": "eth1"},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool