Files
document-haness/docs/virtualization/tech-log-studio/lab-environment-build/setup/setup-prepare-the-lab-host-for-virtualization.md
T
DongHyeonkaandClaude Opus 5 32e39e20aa fix(setup): 실험대에서 35편을 끝까지 밟고 어긋난 명령·결과 31건을 고친다
test-server 를 비우고 다시 세운 뒤 Setup 기록 35편(virtualization 9 ·
keycloak-session-store 26)을 문서에 적힌 명령 그대로 쳤다. 어긋난 자리를
기록과 SSOT 양쪽에 실측과 함께 넣었다.

막히던 것
- 04 의 인증서 경로가 live/hyeonworks.com 이라 nginx 가 [emerg] 로 안 떴다.
  실제 계보는 live/auth.hyeonworks.com 이고 「문제가 생기면」은 진단이 거꾸로였다
- 인증서가 와일드카드가 아니다. SAN 이 auth·app1·app2 셋뿐이라 그 밖의 이름은
  TLS 에서 끊기고 curl 이 exit 60 · %{http_code} 000 을 낸다. SSOT 안에서
  두 문단이 서로 어긋나 있었다
- A-7 14번 ①이 kc-lab-1 에서 여섯 줄 다 실패하는데 마지막 date 만 「차단」을 찍는다

검사가 실패할 수 없던 자리
- B-1 의 세션 키 고르기는 앞 단계가 $KEY 를 채워 둬서 루프가 한 건도 못 맞혀도
  통과한다. KEY= 로 비우고 키마다 1/0 을 찍게 바꿨다
- k3s-agent 유닛의 sed -i 는 패턴에 $HOME 이 들어 있어 아무 줄도 안 바꾼 채 성공한다

certbot
- renew --dry-run 의 종료 코드는 성공도 0, 실패도 0, 다른 사유의 실패는 1 이다.
  본문의 renew failure(s) 로만 판정할 수 있다
- --dry-run 은 staging 서버를 쓰는데 renewal/*.conf 의 account= 는 운영 계정을
  가리킨다. 실패한 dry-run 이 staging 계정을 하나 더 만들어 다음 실행이 계속 멎는다
- 훅을 755 로 놓고 시뮬레이션이 성공해도 Running deploy-hook command 는 안 나온다.
  certbot 2.1.0 에는 --run-deploy-hooks 도 없다
- 강제 갱신은 실제로 쳤고 서빙까지 닿았다. serial 06F3E0EF…1373 → 065547…3DF1,
  notAfter Dec 3 → Dec 16, nginx worker 2629 4712 → 4745 4754

독자가 칠 수 있는 형태로
- 안 되는 형태가 번호 붙은 단계에 앉아 있던 8곳을 뒤집고, 되는 형태를 ①로 올렸다
- 랩 안에서 공개 이름을 치는 curl 65줄에 --resolve 를 붙였다. 붙인 형태를 실제로
  쳐서 문서가 적은 값과 같은지 확인했다
- 힙독·sed -i·echo >>·&&·|| 를 편집기 + 파일 리스팅 + 분할 형태로 바꿨다
- 닫는 코드펜스가 빠져 뒤 200여 줄의 블록 종류가 뒤집혀 있던 곳을 포함해 3곳을 고쳤다

관문: check_body PASS · check_prose error 0 · check_evidence 두 프로젝트 문제 없음 ·
verify-tech-log-tree error 0 · verify-project-layout error 0 · 코드펜스 전수 0건

남은 것: B-0 주입은 keycloak-pattern 저장소의 소스를 고치고 이미지를 다시 구워야
해서 안 했다(unknown).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 19:38:12 +09:00

25 KiB

id, kind, slug, title, topic, topicName, project, status, studio, pinnedVersions, source, sourceRevision
id kind slug title topic topicName project status studio pinnedVersions source sourceRevision
7c66a553-0008-4294-a27a-687bd1bda0c1 SETUP prepare-the-lab-host-for-virtualization lab host 에 가상화 패키지를 깔고 virsh 가 sudo 없이 돌게 만든다 lab-environment-build 실험대 환경 구성 virtualization 게시 전 https://hyeonworks.com/studio/documents/7c66a553-0008-4294-a27a-687bd1bda0c1/edit
name version
libvirt 12.7.0
name version
QEMU 11.1.1
final/document.md#186-단계-00-lab-host-가상화-준비
final/document.md#185-가이드-묶음이-스스로-정한-규약
final/document.md#184-이-부의-출처와-범위
9465582b5d1630eb4ae7c4e078021486919bf6b6

lab host 에 가상화 패키지를 깔고 virsh 가 sudo 없이 돌게 만든다

물리 기계 한 대를 게스트를 올릴 수 있는 상태로 바꾸는 절차다. 가상화 패키지 넷을 깔고, libvirt 소켓을 켜고, 사용자를 libvirt 그룹에 넣고, 연결 URI 를 시스템 단위로 고정한다. 끝나면 virsh list --allsudo 없이 통과한다.

관계

  • cloud-init 시드로 게스트 세 대를 만들고 SSH 가 키로 붙게 한다 다음 단계이고, 여기서 고정한 qemu:///systemdefault 네트워크 위에서 virt-install 이 돈다.
  • qcow2 파일 한 장이 담는 것 — 매핑표와 데이터 클러스터가 같은 파일 안에 있고, 파일 밖을 가리키는 것은 백킹 파일 경로 하나다 여기서 깐 qemu 가 다루는 디스크 형식을 그 글이 설명한다. 다음 단계의 오버레이가 성립하는 근거도 거기 있다.
  • 도구가 낸 출력은 대상의 상태가 아니다 — 그 명령이 무엇을 세는지부터 가른다 virsh list 의 빈 표와 net-list 에서 --all 을 뺐을 때 안 보이는 네트워크를 어떻게 읽어야 하는지 그 기준이 정한다.
  • 단계별 구축 문서는 작성 시점이 아니라 실행 순서로 검증한다 이 절차의 만드는 명령이 왜 재실행으로 검증되지 않은 채 남았는지를 그 기준이 가른다.
  • 가이드대로 다시 쳐서 이 실험대가 같은 상태로 서는가 같은 명령을 다시 쳐서 이 호스트가 같은 상태가 되는지는 아직 재지 않았다.

본문

읽기 전에 — 어디서 치는가

명령은 전부 [lab host] 에서 친다. 게스트가 아직 없어서 다른 셸 표시가 나오지 않는다.

sudo 가 붙는 곳은 둘이다. 패키지를 깔 때와 systemd 유닛을 만질 때이고, virsh 는 3번이 끝나면 sudo 없이 돈다. 그 뒤로 sudo virsh 를 치면 root 환경으로 돌아 사용자 홈의 설정을 못 보므로, 붙이지 않는 쪽이 맞는 형태다.

표시 어느 기계 어떻게 들어가나
[lab host] test-server. virsh 가 도는 곳 ssh test-server

편집기를 여는 곳은 4번 한 단계다. 거기서 ~/.bashrc~/.config/libvirt/libvirt.conf 를 차례로 연다. 나머지는 전부 조회·설치·유닛 조작이라 운영자가 평소에 치는 CLI 를 그대로 쓴다.

이 단계가 세우는 것

가이드 00 의 「이 단계가 끝나면」은 한 줄이다.

virsh list 가 sudo 없이 돌고, VM 을 만들 수 있는 상태가 된다.

그 한 줄이 요구하는 것을 풀면 여덟이다.

무엇
저장소 ~/workspace/keycloak-pattern — 뒤 단계의 deploy/... 상대경로가 이 디렉터리 기준이다
패키지 (Arch) qemu-full · libvirt · virt-install · dnsmasq
패키지 (Debian/Ubuntu) qemu-system-x86 · libvirt-daemon-system · virtinst · cloud-image-utils
판 번호 libvirt 12.7.0 · QEMU emulator version 11.1.1
유닛 libvirtd.socket.service 가 아니다
그룹 donghyeon libvirt wheel
연결 URI LIBVIRT_DEFAULT_URI=qemu:///system
가상 네트워크 default / active / autostart yesvirbr0 · 192.168.122.0/24

네 패키지가 하는 일이 서로 다르다.

무엇 하는 일
qemu 실제로 가상 기계를 돌리는 것
libvirt qemu 를 관리하는 층 (virsh 가 여기 붙는다)
virt-install VM 을 만드는 명령
dnsmasq 가상 네트워크의 DHCP·DNS

전제와 되돌리기

전제는 가이드가 두 줄로 적었다 — 물리 기계 한 대가 있고, 배포판은 상관없다. 이 실험대는 Arch Linux 로 세웠고 배포판이 다르면 패키지 이름만 달라진다. 앞 단계가 없으므로 이 절차는 다른 무엇도 전제하지 않는다.

되돌리는 절차는 원본 가이드 00 에 없다(unknown). 가이드 7편 가운데 되돌리기를 적은 편은 단계 03 하나다. 이 단계가 호스트에 남기는 것은 여섯이다.

남는 것 어디에
패키지 넷 배포판 패키지 데이터베이스
libvirt 보조 그룹 사용자 계정
libvirtd.socket 활성화 systemd
export 한 줄 ~/.bashrc
uri_default 한 줄 ~/.config/libvirt/libvirt.conf
default 네트워크의 autostart libvirt 설정

무엇을 어떤 순서로 걷어내는지는 가이드에 적혀 있지 않고 이 실험대도 걷어내 본 적이 없다. 여기에 되돌리는 명령을 적으려면 지어내야 하므로 적지 않는다.

세우기 전에 먼저 본다

두 확인은 아무것도 바꾸지 않는다. 기계를 켤 때 먼저 도는 펌웨어와 그 설정 화면을 BIOS(Basic Input/Output System)라고 부르는데, 거기서 가상화가 꺼져 있으면 뒤가 전부 헛일이므로 먼저 본다.

확인 ① CPU 가 하드웨어 가상화 확장을 내놓고 있는가

grep -Eo 'vmx|svm' /proc/cpuinfo | head -1

어디를 봐야 하는가 — 출력 한 줄이 전부다. vmx(Intel) 또는 svm(AMD) 중 하나가 찍히는가, 아니면 아무것도 안 찍히는가.

이 결과가 의미하는 것 — 찍혔으면 이 호스트에서 KVM 을 쓸 수 있다. 빈 출력은 CPU 가 못 한다는 뜻이 아니라 대개 BIOS 에서 꺼져 있다는 뜻이다. 재부팅해 Intel VT-x 나 AMD-V 를 켜고 다시 잰다. 여기서 막히면 뒤의 어떤 단계도 의미가 없으므로 진행하지 않는다.

확인 ② 커널이 그 확장을 실제로 잡고 있는가

lsmod | grep kvm

출력은 이 실험대에서 캡처해 두지 않았다(unknown). 가이드도 줄 모양만 적었다.

kvm_intel   ...
kvm         ...

어디를 봐야 하는가 — 왼쪽 첫 열의 모듈 이름 두 개. 벤더 모듈(kvm_intel 또는 kvm_amd)과 공용 kvm 이 둘 다 있어야 한다. 셋째 열은 이 모듈을 쓰고 있는 쪽의 수라서, 아직 VM 이 없으면 0 으로 나온다.

이 결과가 의미하는 것 — 두 줄이면 커널이 하드웨어 가상화를 쓸 준비를 마쳤고 virt-install 이 KVM 가속으로 뜬다. kvm 만 있고 벤더 모듈이 없으면 확인 ① 의 BIOS 설정이 커널까지 안 넘어왔다. 아무것도 없으면 확인 ① 로 돌아간다. 모듈을 직접 올려 보면 거부 사유가 그대로 나온다.

sudo modprobe kvm_intel

왜 이걸 먼저 보나 — KVM 없이도 QEMU 는 돌지만 소프트웨어 에뮬레이션이 되어 수십 배 느려진다. 게스트가 뜨긴 뜨는데 느리다면 대개 여기서 갈린다. 그 상태로 게스트 셋을 올리면 원인을 게스트 안에서 찾게 된다.

실행 절차

1. 저장소를 lab host 에 받는다

목적 — 뒤 단계가 deploy/ 아래 파일을 쓴다. 단계 05·06 의 kubectl apply -f deploy/lab/k8s/... 가 그것이고, 경로는 저장소 루트 기준이다.

① 이미 세웠다 철거한 적이 있으면 무엇이 남아 있는지 먼저 본다.

ls ~/workspace

② 받는다.

git clone https://git.learn.hyeonworks.com/donghyeon.kang/keycloak-pattern.git ~/workspace/keycloak-pattern
cd ~/workspace/keycloak-pattern

예상 결과 — 매니페스트 두 장이 보인다.

ls deploy/lab/k8s/

keycloak-cluster.yamlobservability.yaml 이 보이는가만 본다.

왜 필요한가 — 이후 단계에서 deploy/... 로 시작하는 상대경로가 나오면 전부 이 디렉터리 안에서 친다. lab host 에 저장소가 없으면 cp: cannot stat 이나 error: the path ... does not exist 로 막히고, 이 실험대가 실제로 그 형태로 겪었다. 한 번 세웠다 철거했으면 이 디렉터리가 없을 수 있다. 철거는 VM 과 디스크와 네트워크만 지우고 저장소는 각자 관리라, ~/workspace 에 cloud-init 시드만 남아 있는 상태가 흔하다. ① 을 먼저 치는 까닭이 여기 있다.

문제가 생기면ls 가 아무것도 못 찾으면 클론이 실패한 것이니 ② 를 다시 친다. 클론은 됐는데 deploy/lab/k8s/ 가 없으면 다른 브랜치를 받았다.

2. 가상화 패키지를 깐다

목적virshvirt-install 을 PATH 에 올리고 가상 네트워크의 DHCP 를 준비한다. PATH 는 셸이 실행 파일을 찾아 다니는 디렉터리 목록을 말한다.

sudo pacman -S --needed qemu-full libvirt virt-install dnsmasq

Debian 이나 Ubuntu 면 이름이 다르다. 이 실험대는 Arch 로 세웠고 아래 줄은 가이드가 참고로 적어 둔 것이다(external).

sudo apt install qemu-system-x86 libvirt-daemon-system virtinst cloud-image-utils
virsh --version
qemu-system-x86_64 --version

예상 결과 — 판 번호 두 줄. 이 실험대는 libvirt 12.7.0QEMU emulator version 11.1.1 이었다(observed).

왜 필요한가 — 여기서 나오는 libvirt 판 번호가 뒤의 옵션 이름을 가른다. 훨씬 낮은 판이면 virt-install --cloud-init 같은 옵션의 동작이 달라질 수 있으니, 다음 단계에서 막힐 때 이 번호를 같이 본다.

문제가 생기면command not found 면 패키지가 안 깔렸다. 번호가 나오면 깔렸다.

3. libvirt 를 띄우고 권한을 받는다

목적 — 지금 이 셸이 sudo 없이 libvirt 에 붙게 한다.

sudo systemctl enable --now libvirtd.socket
sudo usermod -aG libvirt "$USER"

③ 로그아웃했다 다시 들어온다. 보조 그룹은 로그인할 때 정해지므로 usermod 만으로는 지금 셸에 반영되지 않는다.

groups            # libvirt 가 보여야 한다
virsh list --all  # sudo 없이 돌아야 한다

예상 결과groups 가 이렇게 나왔다(observed).

donghyeon libvirt wheel

virsh list --all 은 머리글만 있는 빈 표를 내놓는다. 아직 VM 을 안 만들었으므로 표가 비어 있는 쪽이 정상이고, 봐야 할 것은 표의 내용이 아니라 명령이 오류 없이 통과했는가다.

왜 필요한가libvirtd.service 가 아니라 .socket 을 켠다. 소켓 활성화라 데몬이 미리 떠 있지 않아도 virsh 가 접속하는 순간 systemd 가 띄우고, 자원을 아끼며, 데몬을 재시작해도 클라이언트가 끊기지 않는다.

문제가 생기면groupslibvirt 가 없으면 usermod 는 됐지만 지금 로그인 세션이 옛 그룹 목록을 들고 있다. usermod -aG 가 고치는 것은 /etc/group 파일이다. 프로세스의 그룹 목록은 로그인할 때 한 번 읽혀 고정되므로 이미 떠 있는 셸에는 소급 적용되지 않는다. 두 곳을 나란히 보면 그 상태가 그대로 드러난다.

id                    # 현재 셸이 들고 있는 그룹 (여기 libvirt 가 보여야 함)
getent group libvirt  # /etc/group 의 실제 내용 (이쪽엔 바로 반영됨)

두 결과가 다르면 재로그인이 필요하다는 뜻이다. 급하면 newgrp libvirt 로 그 셸만 갱신한다.

groups 에는 있는데 virshPermission denied 를 내면 그룹이 아니라 소켓 문제이므로 유닛 상태를 본다.

systemctl status libvirtd.socket

4. 연결 URI 를 시스템 단위로 고정한다

목적virsh 가 VM 을 만들 곳과 같은 하이퍼바이저를 보게 한다. virsh 는 기본으로 사용자 단위인 qemu:///session 에 붙는데 VM 은 시스템 단위인 qemu:///system 에 만들어야 한다. 이걸 안 맞추면 만든 VM 이 목록에 안 보인다.

① 설정 파일을 연다.

nano ~/.bashrc

② 파일 끝에 이 줄을 더한다. 저장은 Ctrl+O 다음 Enter, 나가기는 Ctrl+X.

export LIBVIRT_DEFAULT_URI=qemu:///system

③ 저장한 설정을 현재 셸에 반영하고 확인한다.

source ~/.bashrc
virsh uri

예상 결과(observed)

qemu:///system

끝의 한 낱말만 본다. system 인가 session 인가.

왜 필요한가qemu:///system 이면 뒤에서 만들 VM 과 지금 virsh 가 같은 곳을 본다. qemu:///session 이면 사용자 단위 하이퍼바이저를 보고 있어, VM 은 만들어졌는데 virsh list 에 안 나오는 상태가 된다.

이 실험대는 같은 줄을 편집기 없이 넣었다(observed).

echo 'export LIBVIRT_DEFAULT_URI=qemu:///system' >> ~/.bashrc
virsh uri

rc 파일에만 넣으면 ssh lab-host '명령' 에서는 안 먹는다. 그 형태는 비대화형 셸이라 .bashrc·.zshrc 를 안 읽는다. 뒤의 편들이 ssh test-server 'virsh …' 처럼 한 줄로 치는 일이 많으므로 여기서 갈라 둔다. 2026-09-17 에 확인했다(observed).

ssh 로 한 줄     LIBVIRT_DEFAULT_URI=[(비어 있음)]
대화형 셸        LIBVIRT_DEFAULT_URI=qemu:///system

셸과 무관하게 고정하려면 libvirt 자기 설정에 넣는다. 이 실험대에는 그 파일도 있었고, 같은 줄을 echo 'uri_default = "qemu:///system"' >> ~/.config/libvirt/libvirt.conf 로 넣었다(observed). 여기서도 디렉터리는 명령으로 만들고 파일은 편집기로 연다.

mkdir -p ~/.config/libvirt
nano ~/.config/libvirt/libvirt.conf
uri_default = "qemu:///system"
virsh uri
/home/donghyeon/.config/libvirt/libvirt.conf:uri_default = "qemu:///system"
qemu:///system

첫 줄은 virsh 가 그 파일을 읽었다고 알리는 것이고 둘째 줄이 답이다. 이 나눈 형태는 이 실험대에서 치지 않았다(unknown).

둘 중 하나만 있으면 어디선가 어긋난다. rc 만 있으면 ssh 한 줄에서 qemu:///session 을 보게 되고 — 그쪽에는 VM 이 없으므로 목록이 빈 채로 나와 「VM 이 죽었다」로 읽힌다 — libvirt 설정만 있으면 대화형 셸의 echo $LIBVIRT_DEFAULT_URI 가 비어서 「설정이 안 됐다」로 읽힌다. 둘 다 넣어 두는 편이 낫다.

따라 하는 사람에게는 편집기 쪽이 맞다. echo >> 는 같은 가이드를 두 번 따라 하면 같은 줄을 한 번 더 붙이고, 파일에 이미 무엇이 들어 있는지도 보여 주지 않는다. 파일을 열면 둘 다 해결된다.

문제가 생기면.bashrc 에 넣은 것은 새로 여는 셸에만 적용된다. 지금 셸에서 값이 안 바뀌었으면 source ~/.bashrc 를 치거나 새 셸을 연다.

sudo virsh 와 그냥 virsh 를 섞어 치지 않는다. 이 문제는 한 번 고쳐도 반복해서 재발한다. sudo 는 환경 변수를 물려주지 않아 여기서 넣은 줄이 전달되지 않는데, root 로 도니 결과적으로 qemu:///system 이 되어 그쪽도 동작한다. 둘 다 되기 때문에 섞어 쓰면 어떤 명령은 되고 어떤 명령은 Network not found: no network with matching name 'default' 가 나온다. 네트워크가 없어서가 아니라 두 명령이 서로 다른 인스턴스에 물어본 것이다.

5. 기본 네트워크를 켠다

목적 — VM 이 붙을 virbr0192.168.122.0/24 를 지금도 재부팅 뒤에도 있게 한다.

virsh net-list --all

예상 결과(observed)

 Name      State    Autostart   Persistent
--------------------------------------------
 default   active   yes         yes

default 행의 State 와 Autostart 두 칸 중 하나라도 어긋나면 아래 두 줄로 맞춘다.

virsh net-start default
virsh net-autostart default

두 줄을 && 로 잇지 않는다. virsh net-start default 는 이미 activeerror: network is already active 로 실패한다. A && B 는 A 가 성공했을 때만 B 를 실행하므로, 두 번째로 칠 때는 net-autostart 가 아예 돌지 않는다. 화면에는 둘 다 실패한 것처럼 보이지만 앞선 실행에서 이미 목적을 이룬 상태다. 이 가이드를 두 번 이상 따라 한다면 ; 로 잇고 앞엣것의 실패를 삼킨다.

virsh net-start default 2>/dev/null; virsh net-autostart default

왜 필요한가active 이면서 autostart 가 yes 면 지금도, 호스트를 재부팅한 뒤에도 virbr0192.168.122.0/24 가 있다. inactive 면 VM 을 만들어도 DHCP 가 없어 IP 를 못 받는다. autostart 가 no 면 지금은 되고 호스트를 재부팅한 다음 게스트의 SSH 가 전부 실패하는데, 그때 원인을 게스트에서 찾게 된다.

문제가 생기면--all 을 주는 까닭이 여기 있다. 빼면 inactive 인 네트워크는 아예 목록에 안 나와서 없는 것과 꺼진 것을 구분할 수 없다. net-start defaultalready active 말고 다른 사유로 실패하면 dnsmasq 가 안 깔린 것이므로 2번으로 돌아간다.

구성 값

무엇이 서나 어떤 이름과 값으로
저장소 ~/workspace/keycloak-pattern
패키지 (Arch) qemu-full · libvirt · virt-install · dnsmasq
유닛 libvirtd.socket
보조 그룹 libvirt
연결 URI qemu:///system~/.bashrcLIBVIRT_DEFAULT_URI
가상 네트워크 default · active · autostart yes
브리지와 대역 virbr0 · 192.168.122.0/24

대역이 192.168.122.0/24 로 굳으면 다음 단계의 DHCP 예약 세 줄과 그 뒤 모든 단계의 upstream 주소가 그 안에서 정해진다. 게스트 주소를 바꾸고 싶으면 여기서 바꾸는 것이지 게스트 안에서 바꾸는 것이 아니다.

끝났는지 판정한다

확인 ① virsh 가 sudo 없이 통과하는가

무엇을 확인하는가 — 이 셸에서 VM 을 만들 수 있는 상태인지.

virsh uri
virsh net-list --all
virsh list --all

어디를 봐야 하는가 — 첫 줄이 qemu:///system 인가, 둘째에서 defaultactive 이고 autostart 가 yes 인가, 셋째가 sudo 없이 오류 없이 끝나는가.

이 결과가 의미하는 것 — 셋이 다 통과하면 이 단계는 끝났다. virsh list --allsudo 없이 오류 없이 끝나는 것이 이 단계의 통과 조건 전부이고, 표의 내용은 아직 볼 것이 없다. 빈 표를 「호스트에 아무것도 없다」로 읽지 않는다 — 지금은 만들지 않았으니 비어 있는 것이고, 다음 단계가 끝난 뒤에 같은 명령이 세 줄을 내놓는다.

확인 ② 그룹이 지금 셸에 반영됐는가

무엇을 확인하는가usermod 가 파일에만 들어간 것인지, 지금 세션이 들고 있는 목록에도 들어간 것인지.

groups

어디를 봐야 하는가 — 출력에 libvirt 가 끼어 있는가.

이 결과가 의미하는 것 — 끼어 있으면 소켓에 붙을 권한이 지금 셸에 있다. 없는데 virsh 가 도는 일은 없으므로, 확인 ① 이 Permission denied 로 끝났다면 먼저 여기를 본다.

통과 조건을 한 번에 다시 본다

무엇 명령 통과
가상화 확장 grep -Eo 'vmx|svm' /proc/cpuinfo | head -1 vmx 또는 svm 한 줄
그룹 groups libvirt 가 끼어 있다
연결 URI virsh uri qemu:///system
네트워크 virsh net-list --all defaultactive · autostart yes
빈 목록 virsh list --all sudo 없이 통과. 표가 비어 있어도 된다

다섯 칸이 다 맞으면 다음 단계로 넘어간다.

막히면

증상 원인 확인
virsh list 에 permission denied 그룹 반영 안 됨 로그아웃과 로그인을 했는가. groups 에 libvirt 가 있는가
만든 VM 이 목록에 없다 URI 가 session virsh uri
sudo 로는 되는데 그냥은 안 된다 세션 인스턴스를 보고 있다 virsh uri
net-startalready active 앞서 켜 두었다 virsh net-list --all 의 State
VM 이 극단적으로 느리다 KVM 미사용 lsmod | grep kvm · BIOS
net-start default 실패 dnsmasq 없음 패키지 설치 확인
cp: cannot stat 'deploy/...' lab host 에 저장소가 없다 ls ~/workspace

무엇이 관측이고 무엇이 아닌가

  • (observed) libvirt 12.7.0QEMU emulator version 11.1.1, groups 의 세 이름, default 네트워크가 active 이고 autostart 가 yes 인 것, virsh uri 가 내놓은 qemu:///system.
  • (observed) lsmod | grep kvm 의 출력을 2026-09-17 에 받았다. 세 줄이고, 마지막 칸이 그 모듈을 쓰는 수다.
kvm_intel             524288  11
kvm                  1490944  6 kvm_intel
irqbypass              16384  1 kvm
  • (observed) 이 호스트는 논리 코어 8 이다 — 가이드가 적은 「16 코어 전부」가 아니다. 2026-09-17 에 nproc8, lscpu11th Gen Intel(R) Core(TM) i5-1135G7, 물리 4 코어에 코어당 스레드 2 라고 답했다. 가이드의 그 줄은 다른 기계의 값이다.
nproc
lscpu | grep -E "^Model name|^CPU\(s\):|^Core\(s\)|^Thread\(s\)"
  • (observed) systemctl status libvirtd.socket 도 같은 날 쳤다. 보는 줄은 ActiveListenTriggers 셋이다.
● libvirtd.socket - libvirt legacy monolithic daemon socket
     Loaded: loaded (/usr/lib/systemd/system/libvirtd.socket; enabled; preset: disabled)
     Active: active (running) since Thu 2026-09-03 19:00:35 KST; 1 week 6 days ago
   Triggers: ● libvirtd.service
     Listen: /run/libvirt/libvirt-sock (Stream)

Triggerslibvirtd.service 를 가리키는 것이 소켓 활성화가 걸렸다는 뜻이다. 소켓이 먼저 뜨고 첫 접속이 올 때 서비스가 깨어난다 — 그래서 .service 가 아니라 .socketenable 한다.

  • (unknown) 원본 가이드에 되돌리는 절차가 없다. 패키지와 그룹과 유닛과 ~/.bashrc 와 네트워크 autostart 를 걷어내 본 적이 없다.
  • (unknown) sudo modprobe kvm_intel 은 막혔을 때 치라고 가이드가 적어 둔 명령이고, 이 실험대에서는 막힌 적이 없어 치지 않았다.
  • (unknown) nano ~/.bashrcnano ~/.config/libvirt/libvirt.conf 로 여는 형태는 이 실험대가 치지 않았다. 이 실험대는 두 파일 다 echo >> 로 넣었고, 편집기 쪽은 같은 상태에 닿는 형태로 적었다.
  • (external) Debian 과 Ubuntu 의 패키지 이름은 가이드가 참고로 적어 둔 것이고 이 실험대는 Arch 로 세웠다.
  • (external) 보조 그룹이 로그인 시점에 고정된다는 것, virsh net-start 가 이미 active 면 실패한다는 것, sudo 가 환경 변수를 물려주지 않는다는 것은 리눅스와 libvirt 의 동작이다. 이 실험대가 그 세 가지를 따로 재 보지는 않았다.
  • (unknown) 만드는 명령은 구축할 때 친 것을 옮긴 것이라, 지금 다시 쳐도 같은 상태가 되는지는 확인되지 않았다.