보통의 가상화 플랫폼 소프트웨어를 설치하고 보면 기본적으로 소모되는 메모리나 컴퓨팅 자원이 상당합니다. 이를 해결하기 위해 AlpineLinux와 Libvirt를 통해 간접적으로 최소한의 자원을 사용하면서 가상머신을 만들 수 있습니다. 이 글에서 사용할 스택은 다음과 같습니다:

  • Virsh
  • Libvirt
  • KVM
  • QEMU
  • AlpineLinux
  • Networking* (sharing physical device as bridge interface, VM network over host computer)

이 글에서는 Hyper-V를 통한 실습 환경을 제공합니다. 그런 경우에는 몇 가지 스택이 더 필요할 수 있습니다:

  • NestedVM
  • Hyper-V

실제로 물리적인 서버에 설정을 완료하였으며 완료할 경우엔 호스트는 디스크 약 2GB(가상 머신을 포함하지 않으며 설치 후에 47MB 정도의 여유공간 밖에 생기지 않음), 메모리 200MB만의 한정된 자원만을 사용하면서도 가상화 호스트 서버로의 운영이 가능합니다. 덕분에 남는 컴퓨터 중에 애매한 포지션이 있다면 유용하게 사용할 수 있습니다.

실습환경 준비: Hyper-V와 NestedVM 설정하기

현재 저는 운용 가능한 컴퓨터가 따로 없기 때문에 Hyper-V에 NestedVM을 통해 KVM 기능을 활성화한 다음 진행할 예정입니다. 바로 준비하실 분들은 현재 섹션을 건너뛰셔도 됩니다.

먼저 관리자 권한으로 PowerShell를 실행한 다음 명령어를 통해 Hyper-V를 운영체제에서 활성화시켜줍니다:

Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All

그리고 Hyper-V에서 새로운 가상 컴퓨터를 생성합니다:

가상 컴퓨터의 위치같은 경우에는 저장 공간이 충분하고 찾기 쉬운 곳에 위치해야 합니다. 가상 컴퓨터의 삭제는 데이터까지 삭제하지 않는데 현재 이 가상 컴퓨터는 일시적으로 쓰이기 때문입니다.

일반적으로 Windows가 아닌 경우 호환성을 위해 1세대를 선택합니다:

그 외 설정은 메모리 등이나 자신이 원하는 옵션을 따로 맞추시면 될 것 같습니다. 저는 이 글에서만 2GB로 저장공간을 제한했습니다:

마지막으로 CDROM을 설정해줍니다:

VM이 생성되었다면 여기에서 NestedVM 기능을 통해 Hyper-V의 VM 내부에서 KVM을 사용할 수 있도록 설정해주는 PowerShell 스크립트를 다운로드하고 실행합니다:

이제 모든 준비가 완료되었습니다.

가상화 호스트 준비하기

오늘 가상화 호스트에 사용될 운영체제는 AlpineLinux의 스탠다드 이미지(약 100MB)입니다. AlpineLinux의 홈페이지 혹은 미러 서버에서 설치용 ISO 이미지를 다운로드할 수 있습니다.

AlpineLinux 설치하기

AlpineLinux는 타 운영체제와 다르게 운영체제 자체가 매우 가벼워 부팅 후 설치한 것처럼 사용할 수 있으나 설치 중에 특별한 그래픽 리소스는 제공하지 않습니다. ISO 이미지로 부팅 후에 root 계정으로 로그인 후에 setup-alpine 명령을 사용하면 쉽게 설치가 가능합니다.

디스크 설정 시에는 표시되는 디스크 중 원하는 디스크를 sys로 설치하시면 됩니다.

AlpineLinux 기본 설정

새로 설치가 완료되었다면 몇 가지 해주어야 할 일이 있습니다.

Community branch 활성화하기

먼저 대부분의 패키지가 위치한 Community branch를 패키지 매니저에 활성화시키는 것입니다. /etc/apk/repositories에서 community를 주석해제하신 후에 저장하세요.

SSH 외부에서 접근 허용하기

그 후에 즉시 할 일은 SSH의 외부 접근을 허용하는 것입니다. 기본적으로 root 사용자 밖에 주어지지 않기 때문에 새로운 사용자를 만들거나 /etc/ssh/sshd_config 파일에서 PermitRootLogin 값을 yes로 변경해주시면 됩니다.

그 후에는 sshd 프로세스를 재시작해야 적용됩니다:

service sshd restart

시스템 업데이트 및 패키지 관리자

AlpineLinux를 처음 접해보신 분이라면 패키지 관리자로 어떤 것을 사용하시는지 궁금하실 수가 있습니다. AlpineLinux에서는 APK를 패키지 관리자로 사용하며 pkgs.alpinelinux.org에서 패키지를 검색하실 수 있습니다. AlpineLinux는 기본적으로 Musl libc를 사용하기 때문에 사용이 불가능하거나 기본적인 환경에 차이가 있습니다. 또한 패키지명이 타 리눅스 배포판과는 다른 점이 있으니 잘 활용하시면 도움이 됩니다.

기본적인 패키지 검색:

중간 중간에 없는 명령어 그리고 명령어 이름과 패키지 명이 일치하지 않을 때가 있습니다. 이 때에는 Contents 탭에서 검색을 시도하면 됩니다:

이제 시스템을 일단 업그레이드합니다:

apk update
apk upgrade

그 외에도 사용성에 중요한 패키지를 설치하면 설정이 완료됩니다:

apk add git nano util-linux sudo

가상화 지원 여부 확인하기

혹여나 시스템이 가상화를 지원하는지 확인하고 싶었지만 lscpu 유틸리티가 없어서 확인하지 못했다면 util-linux를 설치하면 됩니다.

AlpineLinux를 가상화 호스트로 만들기

이제 가상화 호스트로 만들 준비가 완료되었으니 관련 패키지를 설치하고 브릿지를 설정하면 됩니다.

필요한 패키지 설치하기

몇 가지 패키지를 설치해야 합니다. 먼저 설치할 패키지는 libvirt 및 qemu 에뮬레이터로 전반적인 가상화를 담당하게 됩니다.

apk add libvirt-daemon qemu-img qemu-system-x86_64
rc-update add libvirtd

그 다음 설치할 명령어는 virt-install 명령어를 사용하기 위함입니다. cdrkitvirt-install 명령어 실행 중에 필요하니 같이 설치합니다.

apk add virt-install cdrkit libosinfo
Seia: Can I ask where is isoinfo package?
unowe: cdrkit in the community repo.

브릿지 설정하기

그 다음으로 이제 VM과 물리적인 네트워크 어댑터를 브릿지로 공유하여 VM이 또 다른 외부 IP를 직접 받을 수 있도록 설정합니다.

먼저 tun 모듈을 로드시킵니다:

modprobe tun
echo tun | sudo tee -a /etc/modules

브릿지 패키지 또한 설치합니다:

apk add bridge

브릿지는 단순히 /etc/network/interfaces에 설정하면 되지만 몇 가지 제약이 있습니다.

AlpineLinux에서 ipv6가 활성화된 상태로 RA 메세지를 보내는 라우터가 있으면 SLAAC 주소와 함께 IP 주소를 할당하는데 이렇게 된다면 모든 게스트 네트워크 IP가 호스트에도 할당됩니다. 이를 방지 하기 위해서 post-up 훅을 걸어주는 작업을 병행해야 합니다.

먼저 /etc/network/interfaces에 새 DHCP 브릿지 인터페이스를 정의합니다. 기존 eth0 인터페이스는 제거해주세요. 최종적인 파일 내용은 다음과 같습니다:

auto lo
iface lo inet loopback

auto br0
iface br0 inet dhcp
  bridge_ports eth0
  bridge_stp 0

그 다음 iptables 너머로 게스트 네트워크가 DHCP 신호를 전송할 수 있도록 합니다:

rc-update add local

cat >> /etc/local.d/iptables_dhcp_kvm.start << EOM
echo 0 > /proc/sys/net/bridge/bridge-nf-call-arptables
echo 0 > /proc/sys/net/bridge/bridge-nf-call-iptables
echo 0 > /proc/sys/net/bridge/bridge-nf-call-ip6tables
iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
exit 0
EOM

cat >> /etc/local.d/iptables_dhcp_kvm.stop << EOM
exit 0
EOM

chmod +x /etc/local.d/iptables_dhcp_kvm.*

마지막으로 네트워크 서비스를 재시작한 뒤에 시스템을 한 번 다시시작하면 설정이 저장되어 있는 것을 확인하실 수 있습니다:

service networking restart && reboot

재시작 후에 네트워크 할당 상태를 보면 다음이 br0 브릿지가 eth0 어댑터를 공유하고 있음을 알 수 있습니다:

가상 컴퓨터 만들기

이제 가상화 준비가 완료되었으니 가상 컴퓨터를 만들 시간입니다. 물론 저같은 경우에는 위에서 2GB로 용량 제한을 했으니 8GB의 새로운 디스크를 가상 머신에 할당하였습니다.

Virt-Install의 OS-Variant 값 찾기

보통 다른 컴퓨터에서 가상머신을 다루어보셨다면 가상머신의 종류를 지정하는 파트를 보셨을 겁니다. 여기에서는 libosinfo 패키지의 osinfo-query 명령어를 통해 이를 결정할 수 있습니다. 이미 위에서 패키지는 설치하였으니 바로 실행하셔도 무관합니다.

osinfo-query os

여기에서는 AlpineLinux를 다시 가상화할 예정이니 지원하는 AlpineLinux의 최신 버전의 Short ID를 복사합니다.

Hyper-V의 AlpineLinux에서 AlpineLinux 가상화하기

이제 Alpine 안에 Alpine을 돌려봅시다. 물론 안에 Docker까지 한 번 더 돌릴 수 있으니 Windows_Alpine_Alpine_Alpine이 되는 것입니다. 먼저 AlpineLinux의 VM(virt) 이미지를 다운로드해줍시다. AlpineLinux의 Virt 이미지는 커널에서 가상화에 최적화되었는데 불필요한 드라이버 등을 제거하여 용량이 매우 적습니다.

그리고 virt-install 명령을 사용하여 설치하면 됩니다. 이 때 설치에는 2가지 방법이 있는데 보통 디스플레이 드라이버가 없는 상태로 출력을 TTYS0, 즉 콘솔로 우회시키는 방법이 있습니다. virt-install 명령어를 사용하여 가상머신을 설치하시면 됩니다. 단, 반드시 root 사용자로 실행하여야 합니다.

virt-install --connect=qemu:///system \
        -n alpine \
        --ram 1024 \
        --vcpus=2 \
        --cpu host \
        --cdrom alpine-virt-3.12.1-x86_64.iso \
        --os-type=linux \
        --os-variant=alpinelinux3.8 \
        --disk path=./alpine.qcow2,size=16,bus=virtio,format=qcow2 \
        --network bridge=br0 \
        --accelerate \
        --nographics \
        --extra-args "console=ttyS0" \
        --debug
  • n: 가상머신의 이름
  • ram: 가용 메모리
  • vcpus: 가용 가상 코어
  • cpu: 가상 컴퓨터 CPU 설정, host의 경우에는 에뮬레이팅하지 않고 호스트 CPU를 그대로 사용합니다.
  • chrom: 설치에 사용될 ISO 이미지, URL이 주어져도 괜찮습니다.
  • os-type: linux
  • os-variant: 설치하는데에 사용될 운영체제 종류를 선택합니다. (위에서 복사한 short id를 여기에서 붙여넣으면 됩니다)
  • disk: 하드디스크 드라이브, size 값은 GiB 단위입니다.
  • network: 네트워크 어댑터, br0은 생성한 브릿지 인터페이스 이름입니다.
  • accelerate: KVM이 사용가능한 경우 사용하여 가속합니다.
  • nographics: 그래픽 드라이버를 사용하지 않습니다.
  • extra-args: 가상머신 시작 시에 사용될 추가 인수이며 현재 ttyS0, 즉, 콘솔로 출력을 표현하도록 되어 있습니다.
  • debug: 가상머신이 설치 중에 오류가 발생할 경우 유용합니다.

하지만 이 방법이 싫으신 사람들에게는 VNC를 사용하는 방법이 있습니다. VNC와 같은 경우에는 몇 가지 추가 설정이 필요합니다.

VNC를 사용하여 설치하는 방법

VNC를 사용할 경우에는 먼저 QEMU에서 몇 가지 설정을 건드려주면 편리합니다. /etc/libvirt/qemu.conf에서 vnc_listen 항목을 찾고 vnc_password 변수 또한 추가합니다.

vnc_listen = "0.0.0.0"
vnc_password = "password"

그 다음 /etc/libvirt/libvirtd.conf에서 listen_tcp 항목을 활성화합니다.

listen_tcp = 1

마지막에 libvirt 데몬을 재시작해주면 설정이 적용됩니다.

service libvirtd restart

마지막으로 virt-install 명령어를 사용하여 가상머신을 설치하시면 됩니다.

virt-install --connect=qemu:///system \
        -n alpine \
        --ram 1024 \
        --vcpus=2 \
        --cpu host \
        --cdrom alpine-virt-3.12.1-x86_64.iso \
        --os-type=linux \
        --os-variant=alpinelinux3.8 \
        --disk path=./alpine.qcow2,size=16,bus=virtio,format=qcow2 \
        --network bridge=br0 \
        --accelerate \
        --graphics vnc,port=5900,listen=0.0.0.0 \
        --debug
  • graphics: 그래픽 드라이버, 여기에서는 VNC로 설정하였습니다.

Troubleshooting!

만약 실행 중에 오류가 발생하였다면 다음 항목을 확인해보시는 것을 권장드립니다.

  • tun 모듈 로드 여부: modprobe tun
  • 이미 같은 이름으로 실행되는 가상 컴퓨터의 존재 여부

가상 컴퓨터에 운영체제 설치 및 작동 확인

실제로 가상 컴퓨터에서 Alpine 설치를 진행하다보면 Hyper-V에서 새로운 VM을 추가한 것이 아님에도 불구하고 정상적으로 DHCP 프로토콜이 호스트 컴퓨터의 iptables 방화벽을 지나 가상 컴퓨터에 IP를 할당하는 모습을 볼 수 있습니다.

다시 호스트 컴퓨터로 돌아와 ip a 명령어로 확인해보면 정상적으로 vlan 인터페이스가 로드가 된 상태입니다.

Fin.

읽어주셔서 감사합니다.