우분투(Ubuntu) 가상머신(Virtual Machine) 서버 환경 구축

대문 / 설치 및 구축 / 우분투(Ubuntu) 가상머신(Virtual Machine) 서버 환경 구축

우분투(Ubuntu) 가상머신(Virtual Machine) 서버 환경 구축

1.1. 개요

KVM+QEMU 환경에 Windows10 설치 화면
[PNG image (218.33 KB)]
KVM+QEMU 환경에 OSX 설치 화면
[PNG image (581.86 KB)]


[https]Ubuntu[](https://ubuntu.com/) 22.04 Server LTS 기준으로 가상머신 서버환경을 구축하는 방법을 소개합니다.

영문버젼으로 기본설치한 경우를 기준으로 설명합니다.

필자는 "libvirt-bin"(KVM+QEMU), "xfce4"(WindowsManager), "xrdp"(RemoveDesktopServer), [https]"virt-manager"[](https://virt-manager.org/)(KVM+QEMU UI management) 설치 조합을 권장드린다는 점 먼저 말씀드리며 윈도우 PC에 모두 있는 "원격 데스크톱 연결" 프로그램으로 가상머신 서버에 접속해서 "Virtual Machine Manager" UI를 통해서 KVM을 제어한다는 구성이라는 설명과 함께 읽어주시면 좋겠습니다.

이 글에서 각 설치 패키지에 대한 자세한 설명을 담고 있지는 않으나 정상적인 운영 및 보안적인 요소들을 신경쓰셔야 하며 docker 및 docker-compose, firewalld 또는 iptables 등을 이해하고 사용하시는 것을 강력히 권장드립니다.

하기 설명과정에서 선택사항에 따라서 달라지는 reboot 해야 하는 경우를 생략한 부분이 있습니다. 참고하셔서 적절한 과정에 따라서 reboot을 하시면서 진행하실 필요가 있습니다.

1.2. 우분투 배포판 기본 설치 및 구성

먼저 [https]Ubuntu[](https://ubuntu.com/) 22.04 Server LTS 배포판을 설치합니다. (본 문서는 22.04 기준으로 작성되었으나 14.04, 16.04, 18.04, 20.04 에서도 운영해왔으므로 큰 맥락에서는 구축 방법이 다르지 않습니다.)

  • 설치 직후 최신 패키지 업그레이드를 반영합니다. (권장사항)
    $ sudo apt-get update
    $ sudo apt-get upgrade
    
  • systemd 기반의 배포판의 경우 경우에 따라서 일정시간 경과 후 최대 절전모드로 진입할 수 있습니다. 이것을 원치 않는다면 다음과 같이 설정합니다. (권장사항)
    $ sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target
    
    BIOS 설정에서 C-state 제한을 걸어서 최대 절전모드를 진입하지 않도록 할 수도 있습니다. 이 경우 C1 ~ C3E 까지만 허용하고 이상의 상태조정은 제한하도록 하시면 됩니다.
    
    만약 최대 절전모드를 다시 허용하려면 다음과 같이 할 수 있습니다.
    $ sudo systemctl unmask sleep.target suspend.target hibernate.target hybrid-sleep.target
    
  • 또한 화면이 일정시간 경과시 꺼지는 것을 원치 않는 다면 다음과 같이 설정합니다. (선택사항)
    처음 설치시 첫 등록한 관리자 계정에서 다음과 같이 실행합니다. (위 최대 절전모드 해제한 경우 기본적으로 불필요)
    
    $ setterm --blink off --blank 0 --powersave off --powerdown 0 --store
    $ sudo setterm --blink off --blank 0 --powersave off --powerdown 0 --store
    
  • 시간동기화 클라이언트 설치 (권장사항)
    • ntp daemon 설치
      $ sudo apt-get install ntp
      
    • "/etc/ntp.conf" (Ubuntu 22.10 부터는 "/etc/ntpsec/ntp.conf") 에 하기 항목 추가/수정
      server 0.asia.pool.ntp.org
      server 1.asia.pool.ntp.org
      server 2.asia.pool.ntp.org
      server 3.asia.pool.ntp.org
      
    • ntp daemon 을 재시작
      $ sudo systemctl restart ntp.service
      
    • timezone 설정 (대한민국 시간대로 설정)
      $ sudo timedatectl set-timezone Asia/Seoul
      
      또는
      
      $ sudo dpkg-reconfigure tzdata
      
  • 이후 재부팅시 그래픽 로그인창 (부팅시 X-Window/Gnome/KDE등이 구동될 필요가 없다는 것을 의미) 환경이 나오는 것을 원치 않으신다면 다음과 같이 graphical.target 을 multi-user.target 으로 바꾸어줍니다. (권장사항, 불필요한 그래픽처리 부하를 줄이는 효과.)
    $ sudo systemctl get-default
    graphical.target
    $ sudo systemctl set-default multi-user.target
    Created symlink /etc/systemd/system/default.target → /lib/systemd/system/multi-user.target.
    
  • swap 조정 (선택사항, 메모리가 충분하다면 swap 비율을 낮추거나 비활성화 구성하는게 좋은 듯 합니다.
    • swap을 비활성화 (메모리가 충분히 큰 경우만)
      • "/etc/fstab" 에서 swap 설정부분을 모두 주석처리하고 "sudo swapoff -a" 명령으로 비활성화 합니다.
    • swap 비율을 낮추는 설정 (메모리가 충분치는 않아서 swap을 비활성화하기 어려운 경우)
      • "/etc/sysctl.conf" 에 "vm.swappiness" 값을 50 ~ 60 사이로 추가합니다. 50에 가까울수록 swap 비율을 낮추게 됩니다. (필자는 55정도로 설정)
        • "/etc/sysctl.conf" 에 변경된 사항을 반영하기 위해서는 재부팅하거나 하기 명령을 실행해주면 반영됩니다.
          $ sudo sysctl -p
          
    • ZRAM을 활성화 (메모리가 충분하지 않다면 활성화를 권장합니다. 필자 경험상으로는 메모리 사용률 확보와 함께 평균적인 응답성이 좋아지는 것 같습니다.)
  • HWE Kernel 로 업그레이드 (선택사항, 항상 최신 커널을 선호하신다면 HWE Kernel로 업그레이드 하셔도 좋을거 같습니다. 설치하시는 환경에 따라서 이미 HWE Kernel이 활성화된 상태일 수도 있습니다. 예외적으로 특정 커널 버젼을 원하신다면 mainline package 를 설치하셔서 이를 이용하여 원하시는 커널버젼으로 설치하실수 있습니다.)
    => 만약 기존부터 운영하던 서버인 경우에는 설치 및 부팅에 문제가 발생할 가능성을 무시하기 어렵기 때문에 이 과정은 생략하세요.
    => !!! HWE Kernel이 의미하는 바를 잘 모르시겠다면 이 과정은 건너뛰세요.
    
    => Ubuntu 20.04 LTS 인 경우
    $ sudo apt install --install-recommends linux-generic-hwe-20.04
    
    => Ubuntu 22.04 LTS 인 경우
    $ sudo apt install --install-recommends linux-generic-hwe-22.04
    
  • 가상화 인스턴스에서 사용할 인터페이스는 passthrough 또는 SR-IOV로 이용할 경우가 아니라면 Bridge로 구성하는 것을 권장합니다. (권장사항, 가상화 서버호스트와 인스턴스간에 직접 통신이 필요한 경우등을 위함.)
    => 아래는 netplan 설정파일 예시입니다. (lan0 가 eth0를 bridge로 구성한 것입니다.)
    => 참고) SR-IOV 가 현재로써는 네트워크 처리 성능이 가상화 환경에서는 제일 좋은거 같습니다.
    => 참고) 이 밖에도 macvlan, VXLAN, Bonding, ... 등의 구성을 이해하는 것도 좋습니다.
    $ cat /etc/netplan/50-cloud-init.yaml
    
    # netplain config file
    network:
        ethernets:
            eth0:
                optional: true
                dhcp4: false
                dhcp6: false
                accept-ra: false
    #    wifis:
    #        wlan0:
    #            access-points:
    #                <wireless ssid>:
    #                    password: <my wireless passphase>
    #            optional: true
    #            dhcp4: false
    #            dhcp6: false
    #            accept-ra: false
        bridges:
            lan0:
                optional: true
    #            macaddress: <bridge mac address>
                interfaces: [eth0]
                mtu: 1500
                parameters:
                    stp: false
                    forward-delay: 4
                    hello-time: 2
                    max-age: 20
                dhcp4: false
                dhcp6: false
                accept-ra: false
                addresses: [192.168.0.4/24]
                nameservers:
                    addresses: [1.1.1.1,1.0.0.1,168.126.63.1,168.126.63.2,8.8.8.8,8.8.4.4]
                routes:
                - to: 0.0.0.0/0
                  via: 192.168.0.254
                  metric: 1
        version: 2
    

1.3. 불필요한 패키지 제거

가상화 자원에 필요한 패키지를 제외한 나머지는 가급적 삭제하여 구동 자원을 확보하는 것으로써 최소한의 설치를 위해서 불필요한 패키지(Package)들은 모두 제거(Uninstall) 합니다. (필요에 의해서 삭제를 원치 않는 경우 적절히 생략하시고 진행하세요)

  • nano 편집기 삭제 (선택사항, 필요 없는 경우 삭제합니다. vim 사용법을 잘 모르신다면 이 부분은 건너뛰세요.)
    $ sudo apt-get remove --purge nano
    
    • nano 편집기는 누구나 쉽게 사용하기에 좋은 편집기입니다. vim 또는 ed 편집기를 사용하기 어려우시면 nano 편집기를 사용하시는게 좋습니다.
  • vim tiny 편집기를 제거하고 vim original을 설치 (선택사항, vim-basic 이 있기 때문에 vim-tiny 는 삭제해도 됩니다. vim을 보다 전문적으로 사용하기 위한다면 권장합니다.)
    $ sudo apt-get remove --purge vim-tiny
    $ sudo apt-get install vim
    
    • vim 편집기는 굉장히 많은 기능을 가지고 있습니다. vim tiny 패키지는 이 중에서 최소한의 사항만 필요하질 때 사용하는 것이고 vim 의 많은 기능을 다루실 수 있다면 vim tiny 보다는 vim 패키지가 유용합니다.
  • ed 편집기 삭제 (선택사항, ed를 사용할 줄 아시고 선호하신다면 이 부분은 건너뛰세요.)
    $ sudo apt-get remove --purge ed
    
    • ed 패키지는 라인단위 편집기입니다.
  • cloud-init 삭제 (선택사항, 아직은 이것이 없는게 더 좋다는 의견 드립니다.)
    $ sudo apt-get remove --purge cloud-init
    
    • cloud 환경에서 각 환경에 맞는 기초 구성을 해주는 패키지입니다. 자신의 서버가 cloud 환경에서 구동한다면 제거하지 않으시는게 좋습니다.
  • unattended-upgrades 삭제 (선택사항, 필요 없는 경우 삭제합니다.)
    $ sudo apt-get remove --purge unattended-upgrades
    
    • 무시하기 어려운 보안 패키지 업그레이드등을 자동으로 해주는 패키지입니다. 하지만 업그레이드를 직접 자주 하실 때는 제거하셔도 괜찮습니다. 업그레이드에 신경을 안쓰신다면 지우지 않는게 좋습니다.
  • snapd 삭제 (선택사항, 필요 없는 경우 삭제합니다.)
    $ sudo apt-get remove --purge snapd
    
    • snap 패키지를 사용하지 않으신다면 삭제하셔도 괜찮습니다.
    • firefox 나 chromium-browser 등을 snap으로 설치하여 사용할 계획이시라면 삭제하지 마세요.
  • modemmanager 삭제 (선택사항, 필요 없는 경우 삭제합니다.)
    $ sudo apt-get remove --purge modemmanager
    
    • 요즘 모뎀 쓰지 않으시므로 삭제를 권장합니다.
  • scanner 관련 기본 설치패키지들 삭제 (선택사항, 스캐너 관련 기능이 필요하지 않다면 삭제합니다. xrdp 설치 과정 이후에 진행합니다.)
    $ sudo apt-get remove --purge sane-utils colord
    
    • 스캐너 기능을 사용하지 않으시면 불필요하므로 삭제합니다.
  • mdadm 관련 (Raid 구성 관련) 기능들을 사용하지 않는다면 삭제 또는 비활성화를 합니다. (선택사항, mdadm 관련 가상화 환경에서의 passthrough disk가 Raid 인 경우와 충돌등을 방지하기 위한 사항)
    # 삭제는 권장하고 싶지는 않습니다. 주의가 필요합니다.
    $ sudo apt-get remove --purge mdadm
    
    또는
    
    # 이 명령을 수행하고 물어보는 것을 모두 No 로 하시면 비활성화하게 됩니다. (이 명령에 의해서 "/etc/default/mdadm" 파일이 변경되고 initramfs이 갱신됩니다.)
    $ sudo dpkg-reconfigure mdadm
    
  • 비의존적 패키지들 정리 (권장사항, 더이상 의존성이 존재하지 않는 패키지들을 정리합니다.)
    $ sudo apt autoremove --purge
    

1.4. 원격 데스크탑 패키지 설치 (rdp, TCP/3389)

권장사항 : 일반 Microsoft Windows 의 "원격 데스크톱 연결"을 통해서 UI접속을 하실 수 있기를 원하신다면 하기 설치 과정을 진행하시고 아닌 경우는 건너뛰세요.

  • Windows Manager(X, Gnome, KDE 등) 가 설치되어 있는 경우 (원격 작업보다 직접 모니터를 보고 작업하시는 경우)
    $ sudo apt-get install xrdp xorgxrdp
    
    • 일반 Desktop 환경 설치를 원하는 경우
      • Ubuntu 기본 Desktop 환경 설치하는 경우
        $ sudo apt-get install ubuntu-desktop
        
      • Ubuntu 기본 Desktop 환경 설치하는 경우 (권장, 필수적인 패키지만 설치)
        $ sudo apt-get install ubuntu-desktop-minimal
        
      • xfce4 기반 Desktop 환경 설치하는 경우
        $ sudo apt-get install xubuntu-desktop
        
      • KDE 기반 Desktop 환경 설치하는 경우
        $ sudo apt-get install kubuntu-desktop
        
  • Windows Manager가 설치되어 있지 않고 (GUI기본 설치하지 않는 환경) 최소한으로만 설치하고자 하는 경우 (주로 직접 모니터 보고 작업하지 않으시는 경우)
    $ sudo apt-get install xfce4 xfce4-terminal
    $ sudo apt-get install libfontenc1 libxfont2 xfonts-encodings xfonts-utils xfonts-base xfonts-75dpi
    $ sudo apt-get install xrdp xorgxrdp
    
    선택사항, 유용할 수 있는 xfce 패키지가 필요하다면 추가적으로 설치를 진행합니다.
    $ sudo apt-get install xfce4-clipman-plugin xfce4-cpugraph-plugin xfce4-netload-plugin xfce4-screenshooter xfce4-taskmanager xfce4-xkb-plugin
    
    선택사항, 화면보호기는 불필요한 경우 다음과 같이 삭제합니다.
    $ sudo apt-get remove --purge light-locker xscreensaver
    
    설치 과정에서 "display manager"를 선택하라고 나올 수 있습니다. 이 경우 "lightdm" 을 선택하는 것을 기준으로 설명합니다. (선택 사항)
    
    설치 완료 후 반드시 "/etc/xrdp/startwm.sh" 를 수정합니다. => 마지막 부분의 Xsession을 실행(exec)하는 부분은 모두 주석처리 또는 제거하시고 대신 그 위치에 "xfce4-session"가 실행되도록 하기와 같이 추가 (원격 접속이 잘 안되는 경우만 하시면 됩니다)
    >>>
        ... 생략 ...
    
        test -x /usr/bin/xfce4-session && exec /usr/bin/xfce4-session
        #test -x /etc/X11/Xsession && exec /etc/X11/Xsession
        #exec /bin/sh /etc/X11/Xsession
    <<<
    
    이렇게 설치하고 나면 xrdp 계정이 생성되는데 이 계정을 ssl-cert group 에 추가해주는게 좋습니다. (선택 사항, xrdp 접속시 인증서를 사용할 수 있도록 하는 사항)
    $ cat /etc/group|grep ssl-cert
    ssl-cert:x:120:xrdp
    
  • docker 를 이용해서 원격 데스크탑을 구성하실수도 있도록 docker hub에 "hwport/ubuntu:xrdp" 이미지를 만들어 두었습니다. (선택 사항, docker로 구성하는 것을 원하시는 경우)
    • docker-compose.xml 예제
      version: "2.1"
      services:
        xrdp:
          image: hwport/ubuntu:xrdp
          container_name: xrdp
          hostname: xrdp
          stdin_open: true
          tty: true
      #    privileged: true
      #    cap_add:
      #      - "SYS_ADMIN"
      #      - "SYS_RESOURCE"
      #      - "SYS_PTRACE"
      #      - "NET_ADMIN"
      #      - "NET_BIND_SERVICE"
      #      - "NET_BROADCAST"
      #      - "NET_RAW"
      #      - "BPF" # >= Linux Kernel v5.8
      #    security_opt:
      #      - seccomp:unconfined
          environment:
            - container=docker
            - TZ=Asia/Seoul
            - TERM=xterm
            - LC_ALL=C
            - LANG=en_US.UTF-8
            - EDITOR=vim
      #    volumes:
      #      - ./home:/home
      #    tmpfs:
      #      - /tmp
      #      - /run
      #      - /run/lock
          network_mode: bridge
          ports:
            - "3389:3389"
          restart: unless-stopped
      
      • docker-compose.xml 을 적절한 디렉토리 생성 후 저장하고 해당 디렉토리로 이동 후 다음과 같이 실행하고 사용자를 추가하면 됩니다.
        $ docker-compose up -d "xrdp"
        $ docker exec -i -t "xrdp" useradd -c "<comment>" -d "/home/<username>" -g "users" -G "users,adm,sudo,audio,input" -s "/bin/bash" -m "<username>"
        $ docker exec -i -t "xrdp" sh -c "echo \"<username>:<password>\" | chpasswd"
        
      • docker-compose 종료는 다음과 같이 실행하면 종료됩니다.
        $ docker-compose down
        
  • 한글 환경 설치
    • 언어팩 설치 (한글 환경을 원하는 경우 필수사항)
      $ sudo apt-get install language-pack-ko
      
    • 은폰트(unfonts) 설치 (선택사항)
      $ sudo apt-get install fonts-unfonts-core fonts-unfonts-extra 
      
    • 백묵폰트(baekmuk) 설치 (선택사항)
      $ sudo apt-get install fonts-baekmuk
      
    • 나눔폰트(nanum) 설치 (선택사항, 전반적인 폰트구성을 이 폰트로 하면 좋은 것 같습니다.)
      $ sudo apt-get install fonts-nanum fonts-nanum-coding fonts-nanum-extra
      
    • D2Coding폰트 설치 (선택사항, 개인적으로 이 폰트가 가장 개발콘솔용 폰트로 이용하기에 가시성이 좋은 것 같습니다.)
      $ sudo apt-get install fonts-naver-d2coding
      
    • 한글 입력기 설치 (권장사항, ibus-hangul, 한글 입력을 원하는 경우)
      $ sudo apt-get install ibus ibus-hangul im-config zenity
      
      => 설치 후 설정사항 (im, ibus, ibus-hangul, Autostart 설정)
        - "im-config" 를 실행하여 "ibus"을 선택합니다.
        - "ibus-setup" 을 실행하여 "Input Method" 에 "Korean - Hangul"을 추가해줍니다.
        - 매 접속마다 한글 입력기가 실행되어야 하므로 "설정(Settings)" > "Session and Startup" 메뉴에서 "Application Autostart" 항목에 "/usr/bin/ibus-daemon -drx" 명령이 실행될 수 있도록 추가해주세요.
      
    • 또 다른 한글 입력기 (선택사항, fcitx, 한글 입력을 원하는 경우 ibus 말고 또 다른 방법 중 하나)
      $ sudo apt-get install fcitx fcitx-hangul
      
      => 설치 후 /etc/default/im-config 를 편집기로 열어서 IM_CONFIG_DEFAULT_MODE 항목의 값을 auto 에서 fcitx 로 변경 후 저장하고 재부팅
      
  • pulse audio 의 XRDP redirection module 설치 (선택사항 : XRDP 원격접속 클라이언트에서 오디오를 듣고 싶을 때)
    • 기본적으로 오디오를 활성화 하려면 pulseaudio 를 설치해야 합니다.
      $ sudo apt-get install pulseaudio
      
      • 만약 XRDP 접속 후 pulseaudio가 실행되지 않는다면 설정 메뉴 'Session and Startup' 에서 '/usr/bin/pulseaudio --start' 명령이 실행되도록 추가해줍니다.
    • XRDP의 오디오 확장 모듈을 설치하려면 다음과 같이 추가적인 소스를 받아서 설치하는 과정이 필요합니다. (현재 확인한 기준으로 우분투 22.04 까지는 간단히 패키지 설치하는 방법은 없는 것으로 보입니다.)
      => build 에 필요한 패키지 설치
      $ sudo apt-get install build-essential dpkg-dev libpulse-dev git autoconf libtool
      
      => git source를 다운로드
      $ git clone https://github.com/neutrinolabs/pulseaudio-module-xrdp.git /tmp/pulseaudio-module-xrdp
      
      => 빌드 및 설치
      $ cd /tmp/pulseaudio-module-xrdp
      $ ./scripts/install_pulseaudio_sources_apt.sh
        마지막에 표시되는 PULSE_DIR=... 부분과 아래 configure의 실행시 인자가 일치해야 합니다. (기본적으로 PULSE_DIR은 "${HOME}/pulseaudio.src"를 가르키게 될 겁니다.)
        Ubuntu 배포판이 아닌 경우는 "./scripts/install_pulseaudio_sources_apt_wrapper.sh" 으로 실행하면 됩니다.
      $ ./bootstrap
      $ ./configure PULSE_DIR=~/pulseaudio.src
      $ make
      $ sudo make install
      
      => 소스 및 중간파일들을 정리(삭제)
      $ cd ..
      $ rm -rf /tmp/pulseaudio-module-xrdp ~/pulseaudio.src
      
    • 이 모듈을 설치하지 않으면 원격접속 클라이언트로 소리가 재지향 되지 않으므로 단순 Dummy 가상장치로 오디오가 출력되어 소리를 들을 수 없습니다.
  • FireFox 브라우져 (선택사항 : 브라우저 환경이 필요한 경우)
    • snap을 사용하는 경우 (with snap)
      $ sudo apt-get install firefox
      
    • snap을 사용하지 않는 경우 (without snap)
      $ sudo apt-get install -y software-properties-common
      $ sudo add-apt-repository -y ppa:mozillateam/ppa
      $ echo 'Package: *
      Pin: release o=LP-PPA-mozillateam
      Pin-Priority: 1001' | sudo tee /etc/apt/preferences.d/mozilla-firefox
      $ echo 'Unattended-Upgrade::Allowed-Origins:: "LP-PPA-mozillateam:${distro_codename}";' | sudo tee /etc/apt/apt.conf.d/51unattended-upgrades-firefox
      $ sudo apt-get update
      $ sudo apt-get install -y firefox
      
  • 크롬브라우져(Google chrome/chromium browser) (선택사항 : 브라우저 환경이 필요한 경우)
    • snap을 사용하는 경우 (with snap)
      => 이 경우 구글 크롬브라우져가 아닌 'without 구글' 버젼인 크로미움 브라우져입니다.
      $ sudo apt-get install chromium-browser
      
    • snap을 사용하지 않는 경우 (without snap, 이 글을 작성하는 시점에서 테스트해봤을 때 실행은 되지만 일부 문제가 좀 발생되는 것 같습니다.)
      $ sudo apt-get install -y software-properties-common apt-transport-https wget ca-certificates gnupg2 ubuntu-keyring
      $ wget -O- https://dl.google.com/linux/linux_signing_key.pub | gpg --dearmor > /usr/share/keyrings/google-chrome.gpg \
        && echo deb [arch=amd64 signed-by=/usr/share/keyrings/google-chrome.gpg] http://dl.google.com/linux/chrome/deb/ stable main | sudo tee /etc/apt/sources.list.d/google-chrome.list
      $ sudo apt-get update
      $ sudo apt-get install -y google-chrome-stable
      
  • Android studio 설치 (선택사항 : 안드로이드 개발환경이 필요한 경우)
    $ sudo apt-get install -y software-properties-common
    $ sudo add-apt-repository -y ppa:maarten-fonville/android-studio
    $ sudo apt-get update
    $ sudo apt-get install -y android-studio
    


xrdp.png
[PNG image (33.49 KB)]

1.5. KVM + QEMU 가상서버 설치

  • KVM + QEMU 및 기반유틸 설치
    • KVM(libvirt) 와 QEMU 및 그에 종속적인 기본 패키지 설치
      • Ubuntu 배포판 버젼이 18.04 이하인 경우
        $ sudo apt-get install qemu-kvm libvirt-bin ovmf ubuntu-vm-builder bridge-utils
        
      • Ubuntu 배포판 버젼이 20.04 이상인 경우
        $ sudo apt install qemu-kvm ovmf bridge-utils libvirt-daemon-system
        
    • 만약 TPM 모듈이 없고 TPM을 요구하는 Windows11등의 OS를 가상화 환경으로 설치하고 싶으신 경우 다음과 같이 swtpm-tools 를 설치하여 TPM을 에뮬레이션할 수 있도록 할 수 있습니다.
      $ sudo add-apt-repository ppa:stefanberger/swtpm-focal && sudo apt update              # 20.04 이하 버젼인 경우에만 필요
      $ sudo apt install swtpm-tools
      
    • 추가적으로 ARM archtecture에 대한 에뮬레이션을 원하신다면 다음과 같이 추가로 QEMU arm 지원을 추가할 수 있습니다. (선택사항, Android나 Raspberry pi 등을 ARM archtecture 로 에뮬레이션하고 싶다면 설치하세요.)
      $ sudo apt install qemu-user-static qemu-system-arm qemu-efi
      
      • 참고) 여기서 qemu-user-static 은 다른 아키텍쳐로 빌드된 실행파일들을 내 서버에서 실행할 수 있게 해주는 패키지입니다.
    • 만약 OpenGL render 기반 가속기능을 사용할 계획이신 경우 libegl1 패키지를 설치합니다. (선택사항)
      $ sudo apt install libeql1
      
      • 그리고 사용하고자 하는 계정에 render 그룹 권한을 추가해줍니다.
        $ sudo adduser `id -un` render
        Adding user '<username>' to group 'render' ...
        
    • 특정 계정에게 libvirt 사용권한을 할당하려면 다음과 같이 group에 userid 를 추가해줍니다. (만약 현재 로그인한 계정에서 추가했다면 다시 로그인해야 권한이 반영됩니다.)
      $ sudo adduser `id -un` libvirt
      Adding user '<username>' to group 'libvirt' ...
      
      • 예전 배포판의 경우 group 이 libvirt 가 아닌 libvirtd 일 수 있습니다. "/etc/group"에서 확인하여 해당하는 group 에 추가하여야 합니다.
    • KVM + QEMU 설치 확인
      • Intel VT-x 와 AMD-V 중에서 H/W 가속이 지원 가능한 경우 0보다 큰 값이 출력됩니다.
        $ egrep -c '(vmx|svm)' /proc/cpuinfo
        
    • KVM+QEMU 관리 UI 프로그램인 virt-manager 설치 (강력추천, 윈도우상의 "시스템" 메뉴에 보시면 "Virtual Machine Manager"가 설치되며 이를 실행하여 손쉽게 가상환경을 다루실 수 있습니다.)
      $ sudo apt-get install virt-manager
      
      • virt-manager 에서 원격지의 KVM+QEMU 서버를 SSH를 경유하여 관리하고자 한다면 하기와 같이 ssh-askpass-gnome package를 추가로 설치합니다.
        $ sudo apt-get install ssh-askpass-gnome
        
    • 올바르게 설치되었다면 다음과 같이 나올겁니다.
      $ virsh list --all
       Id Name                 State
      ----------------------------------
      
      $
      
    • 만약 설치에 문제가 있다면 다음과 비슷하게 나올겁니다.
      $ virsh list --all
      libvir: Remote error : Permission denied
      error: failed to connect to the hypervisor
      $
      
  • VirtualBox 설치 (선택사항, 실제 사용계획이 있는 경우만 설치하세요.)
    $ sudo apt-get install virtualbox
    
  • Docker 설치 (선택사항, 만약 libvirt와 firewalld 가 운영중인 환경에 docker 를 운영하기 위해서는 몇가지 네트워크에 대한 전문적인 구성이 필요하므로 잘 다룰 수 없다면 생략하세요.)
    $ sudo apt-get install docker.io
    $ sudo apt-get install docker-compose
    
    • 자신의 계정을 docker 사용 group에 추가하려면 다음과 같이 실행합니다.
      $ sudo usermod -a -G docker $(whoami)
      
    • 참고) "/etc/docker/daemon.json" 을 적절히 아래와 같이 수정하여 firewalld/iptables 등을 고려할 필요가 있을 수 있음. (아래의 설정내용은 예시이며 각 환경에 따라서 전문적으로 수정할 필요성 있음)
      {
              "bridge":"br0",
              "fixed-cidr":"192.168.0.240/29",
              "default-gateway":"192.168.0.254",
              "dns":["192.168.0.3","168.126.63.1","168.126.63.2"],
              "mtu":1500,
              "ipv6":false,
              "iptables":false,
              "ip-forward": false,
              "ip-masq": false
      }
      
      OR
      
      {
              "bip": "198.18.1.1/24",
              "userland-proxy": false
      }
      
      OR
      
      {
              "bip":"198.18.1.1/24",
              "iptables":false,
              "ip-forward":false,
              "ip-masq":false,
              "userland-proxy":true
      }
      
      OR
      
      {
              "log-driver": "json-file",
              "log-opts": {
                      "max-size": "10m",
                      "max-file": "4",
                      "labels": "production_status",
                      "env": "os,customer"
              },
              "bip":"198.18.1.1/24",
              "iptables":false,
              "ip-forward":false,
              "ip-masq":false,
              "userland-proxy":true
      }
      
      • libvirt와 docker 를 함께 운영하는 경우 docker 의 daemon.json 에서는 iptables를 false 로 하고 userland-proxy를 true 로 하는게 필자 경험상 필요해보입니다.
    • 추가적으로 multi architecture/platform docker build 환경 (docker buildx) 을 위해서 다음과 같이 추가적인 설치과정이 필요합니다. 결국 하기 명령은 docker 의 CLI plugin 으로 buildx 를 추가하는 것으로 이해하시면 됩니다. (선택사항)
      => Ubuntu 20.04 이전 버전인 경우
      $ DOCKER_BUILDKIT=1 docker build --platform=local -o . https://github.com/docker/buildx.git
      $ mkdir -p ~/.docker/cli-plugins
      $ mv buildx ~/.docker/cli-plugins/docker-buildx
      $ docker buildx create --use                                   /* 자세한 사용법은 'docker buildx create --help' 로 확인 후 적절히 추가 옵션을 주어 사용하실 수 있습니다. */
      
      => Ubuntu 22.04 이상 버전인 경우
      $ sudo apt install docker-buildx
      
      • docker buildx 가 일부 문제(bug)가 있을 경우 다음과 같은 조치가 되어야 할 수 있습니다. 이 명령은 default 대신 새로운 빌더를 추가하여 사용하게 되는 명령입니다. (선택사항, 특정 architecture/platform 빌드시에만 문제가 발생하는 경우 시도해볼만 합니다.)
        $ docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
        $ docker buildx create --name multiarch --driver docker-container --use
        $ docker buildx inspect --bootstrap
        
      • docker buildx 로 Dockerfile 은 다음과 같이 build 및 push를 할 수 있습니다. (선택사항, 참고, platform은 자신의 구성환경 및 목표에 맞게 지정하여 빌드)
        $ docker buildx build --no-cache --push --platform linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/riscv64,linux/s390x --tag "<image-tag-name>" .
        
  • 추가적으로 다음의 패키지 설치를 권장합니다. (권장사항, 만약 문제가 발생되고 이를 이해하기 어렵거나 스스로 해결하기 어렵다면 설치를 우선은 생략하세요.)
    $ sudo apt install firewalld
    $ sudo apt install dnsmasq
    $ sudo systemctl enable --now firewalld
    $ sudo systemctl restart libvirtd
    
    • firewalld 의 firewall-cmd 명령에 대한 개략적인 사용법
      => forward 를 허용하려면 (최신 버젼에서 추가된 옵션) : firewall-cmd [--permanent] [--zone=<zone>] --add-forward
      => 특정 인터페이스를 zone 에 합류 시키려면 : firewall-cmd [--permanent] [--zone=<zone>] --add-interface=<interface-name>
      => 특정 서비스를 zone 에 허용하려면 : firewall-cmd [--permanent] [--zone=<zone>] --add-service=<service-name>
      => 특정 포트를 zone 에 허용하려면 : firewall-cmd [--permanent] [--zone=<zone>] --add-port=<portid>[-<portid>]/<protocol>
      => IKE/NAT-T 허용 : firewall-cmd [--permanent] [--zone=<zone>] --add-service=ipsec
      => IPSec policy (out) 에 따른 허용 : firewall-cmd [--permanent] --direct --add-rule ipv4 nat POSTROUTING 0 -m policy --dir out --pol ipsec -j ACCEPT
      => IPSec policy (in) 에 따른 MSS 조정 : firewall-cmd [--permanent] --direct --add-rule ipv4 mangle PREROUTING 0 -m policy --pol ipsec --dir in -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1281:1536 -j TCPMSS --set-mss 1280
      => IPSec policy (out) 에 따른 MSS 조정 : firewall-cmd [--permanent] --direct --add-rule ipv4 mangle POSTROUTING 0 -m policy --pol ipsec --dir out -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1281:1536 -j TCPMSS --set-mss 1280
      => IPSec 출발지 대역만 Masquerade : firewall-cmd [--permanent] --direct --add-rule ipv4 nat POSTROUTING 0 -s 192.168.0.0/24 -j MASQUERADE
      => IPSec 목적지 대역만 Masquerade : firewall-cmd [--permanent] --direct --add-rule ipv4 nat POSTROUTING 0 -d 192.168.0.0/24 -j MASQUERADE
      => ESP 프로토콜 허용 : firewall-cmd [--permanent] [--zone=<zone>] --add-rich-rule='rule protocol value="esp" accept'
      => AH 프로토콜 허용 : firewall-cmd [--permanent] [--zone=<zone>] --add-rich-rule='rule protocol value="ah" accept'
      => IPCOMP 프로토콜 허용 : firewall-cmd [--permanent] [--zone=<zone>] --add-rich-rule='rule protocol value="ipcomp" accept'
      => IPEncap 프로토콜 허용 : firewall-cmd [--permanent] [--zone=<zone>] --add-rich-rule='rule protocol value="ipencap" accept'
      => 특정 출발지 대역 거부 : firewall-cmd [--permanent] [--zone=<zone>] --add-rich-rule='rule family="ipv4" source address="<address>/<prefix>" drop'
      => 특정 목적지 대역 거부 : firewall-cmd [--permanent] [--zone=<zone>] --add-rich-rule='rule family="ipv4" destination address="<address>/<prefix>" drop'
      => 특정 목적지 대역과 포트를 거부 : firewall-cmd [--permanent] [--zone=<zone>] --add-rich-rule='rule family="ipv4" destination address="<address>/<prefix>" port="23" protocol="tcp" drop'
      => 특정 포트 개방 (DNAT) : firewall-cmd [--permanent] [--zone=<zone>] --add-forward-port='port=<portid>:proto=<protocol>:toport=<portid>:toaddr=<to-address>'
      => Masquerade 허용 : firewall-cmd [--permanent] [--zone=<zone>] --add-masquerade
      => 특정 출발지 대역만 masquerade : firewall-cmd [--permanent] [--zone=<zone>] --add-rich-rule='rule family="ipv4" source address="<address>/<prefix>" masquerade'
      => 기본 정책을 REJECT가 아닌 DROP으로 처리하는 경우 : firewall-cmd [--permanent] [--zone=<zone>] --add-rich-rule='rule priority="32767" drop'
      
    • GeoIP DB를 사용하여 특정 국가별 차단등을 관리하고자 한다면 다음과 같이 설치 및 몇가지 제반사항을 진행해야 합니다. (선택적 권고사항, [https]참고링크[](https://codepre.com/how-to-block-ip-addresses-from-countries-with-geoip-addon-in-iptables.html))
      • Ubuntu 배포판 버젼이 18.04 이하인 경우
        $ sudo apt install xtables-addons-common libtext-csv-xs-perl perl
        $ cd /usr/lib/xtables-addons/
        $ sudo ./xt_geoip_dl
        $ sudo mkdir -p /usr/share/xt_geoip/
        $ sudo cp -f /usr/lib/xtables-addons/dbip-country-lite.csv /usr/share/xt_geoip/
        $ cd /usr/share/xt_geoip/
        $ sudo perl /usr/lib/xtables-addons/xt_geoip_build dbip-country-lite.csv
        554102 entries total
        ...
        $ sudo rm -f /usr/share/xt_geoip/dbip-country-lite.csv
        
      • Ubuntu 배포판 버젼이 22.04 이상인 경우 (Ubuntu 22.04부터는 /usr/libexec/xtables-addons/ 경로로 변경되었습니다.)
        $ sudo apt install xtables-addons-common libtext-csv-xs-perl perl
        $ cd /usr/libexec/xtables-addons/
        $ sudo ./xt_geoip_dl
        $ sudo mkdir -p /usr/share/xt_geoip/
        $ sudo cp -f /usr/libexec/xtables-addons/dbip-country-lite.csv /usr/share/xt_geoip/
        $ cd /usr/share/xt_geoip/
        $ sudo perl /usr/libexec/xtables-addons/xt_geoip_build dbip-country-lite.csv
        554102 entries total
        ...
        $ sudo rm -f /usr/share/xt_geoip/dbip-country-lite.csv
        
      • firewalld 를 사용하는 경우 이제 다음과 같은 명령을 통해서 출발지 IP주소가 중국(CN), 러시아(RU), 북한(KP)에 속하는 경우 차단할 수 있습니다.
        $ sudo firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -m geoip --src-cc CN,RU,KP -j DROP
        $ sudo firewall-cmd --reload
        $ sudo cat /etc/firewalld/direct.xml
        <?xml version="1.0" encoding="utf-8"?>
        <direct>
          <rule ipv="ipv4" table="filter" chain="INPUT" priority="0">-m geoip --src-cc CN,RU,KP -j DROP</rule>
        </direct>
        

1.6. KVM : passthrough

그래픽 카드(GPU)나 기타 PCI 장치를 passthrough 하는 방법을 소개합니다.

passthrough 란 KVM+QEMU 서버에서 해당 PCI 장치를 사용하지 않고 가상화 호스트에서 이 장치를 단독으로 사용할 수 있게 하는 방법입니다. (PCI 장치를 가상화 호스트에 PCI장치로 인식하고 단독으로 사용) 보통은 그래픽 장치나 오디오등의 미디어 장치, 그리고 Ethernet 장치등을 이렇게 사용합니다.

  • 먼저 필수적으로 BIOS 설정에서 "VT-d (Intel)" 또는 "AMD IOMMU (AMD)" 관련 옵션이 있으면 활성(Enable)해주세요.
  • 커널 부트 파라미터에 IOMMU 를 활성화 하도록 grub 설정파일을 수정합니다.
    • "/etc/default/grub" 파일을 편집기로 열어 GRUB_CMDLINE_LINUX_DEFAULT 항목을 다음과 같이 수정합니다.
      • Intel CPU 인 경우
        ...
        GRUB_CMDLINE_LINUX_DEFAULT="intel_iommu=on iommu=pt kvm.ignore_msrs=1 rd.driver.pre=vfio-pci vfio_iommu_type1.allow_unsafe_interrupts=1"
        ...
        
      • AMD CPU 인 경우
        ...
        GRUB_CMDLINE_LINUX_DEFAULT="amd_iommu=on iommu=pt kvm.ignore_msrs=1 rd.driver.pre=vfio-pci vfio_iommu_type1.allow_unsafe_interrupts=1"
        ...
        
      • 각 항목은 다음과 같은 의미를 가지고 있으며 자신의 환경에 맞는 옵션만 사용하시면 됩니다.
        • "intel_iommu=on" : Intel CPU 에서 IOMMU를 활성화 하는 기본 옵션입니다.
        • "amd_iommu=on" : AMD CPU 에서 IOMMU를 활성화 하는 기본 옵션입니다.
        • "iommu=pt" : 성능향상을 위한 좀더 세분화 옵션입니다.
        • "kvm.ignore_msrs=1" : KVM에서 MSR을 무시하는 옵션입니다.
          • 다음의 경로와 관련 있습니다. => "/sys/module/kvm/parameters/ignore_msrs"
        • "kvm.report_ignored_msrs=0" : KVM에서 MSR무시를 알리지 않는 옵션입니다.
          • 다음의 경로와 관련 있습니다. => "/sys/module/kvm/parameters/report_ignored_msrs"
        • "rd.driver.pre=vfio-pci" : ramdisk 로부터 vfio-pci module 을 올리도록 합니다. (Ubuntu 기반 배포판의 경우 꼭 추가해주어야 합니다.)
        • "vfio_iommu_type1.allow_unsafe_interrupts=1" : MSR 을 허용해주는 것으로 우선 이 옵션을 빼고 해보시고 MSR관련 오류가 나온다면 이 옵션을 추가해주시면 됩니다. (단, 이 옵션은 실행하는 가상호스트가 신뢰할 수 있을 때만 사용하셔야 합니다. 신뢰할 수 없는 가상호스트인 경우 이 옵션을 사용하지 않는게 좋습니다.)
    • 편집완료된 "/etc/default/grub" 설정파일을 다음과 같이 실행하여 반영합니다.
      $ sudo update-grub
      
      • 또는 다음의 명령도 동일한 명령입니다.
        sudo grub-mkconfig -o /boot/grub/grub.cfg
        
  • passthrough 할 장치의 장치 드라이버가 로드되지 않도록 blacklist 로 추가해주는게 좋습니다.
    • 만약 주 화면과 passthrough 할 그래픽 카드가 동일한 드라이버를 사용한다면 이 과정에 주의가 필요합니다.
    • SR-IOV Network 카드의 경우는 이 과정이 필요 없습니다.
    • nVidia 그래픽/비디오 카드의 경우 다음과 같이 blacklist 로 nouveau 드라이버를 지정하여 로드되지 않도록 할 수 있습니다.
      • "/etc/modprobe.d/blacklist-nouveau.conf" 파일을 만들고 다음과 같이 편집하여 저장합니다.
        blacklist nouveau
        options nouveau modeset=0
        
  • PCI 장치 중에서 passthrough 할 장치의 ID를 확인해야 합니다.
    $ sudo lspci -nnk
    ...
    <bus> <name> [<ID>]
    ...
    
    • nVidia Quadro FX1800 그래픽 카드인 경우 PCI ID가 "10de:0638"(VGA) 인것을 확인할 수 있습니다.
      $ sudo lspci -nnk
      ...
      07:00.0 VGA compatible controller [0300]: NVIDIA Corporation G94GL [Quadro FX 1800] [10de:0638] (rev a1)
      ...
      
    • nVidia GT730 그래픽 카드인 경우 PCI ID가 "10de:1287"(VGA)과 "10de:0e0f"(Audio) 인것을 확인할 수 있습니다.
      $ sudo lspci -nnk
      ...
      07:00.0 VGA compatible controller [0300]: NVIDIA Corporation GK208B [GeForce GT 730] [10de:1287] (rev a1)
      ...
      07:00.1 Audio device [0403]: NVIDIA Corporation GK208 HDMI/DP Audio Controller [10de:0e0f] (rev a1)
      ...
      
    • nVidia GT1030 그래픽 카드인 경우 PCI ID가 "10de:1d01"(VGA)과 "10de:0fb8"(Audio) 인것을 확인할 수 있습니다.
      $ sudo lspci -nnk
      ...
      07:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP108 [GeForce GT 1030] [10de:1d01] (rev a1)
      ...
      07:00.1 Audio device [0403]: NVIDIA Corporation GP108 High Definition Audio Controller [10de:0fb8] (rev a1)
      ...
      
  • "/etc/modprobe.d/vfio.conf" 파일을 만들고 다음과 같이 자신의 PCI ID로 편집하여 저장합니다. (PCI ID가 여러개인 경우 콤마(,) 로 구분하여 넣습니다.)
    options vfio-pci ids=<ID>[,<...>]
    #options vfio-pci disable_vga=1
    
    • nVidia Quadro FX1800 그래픽 카드인 경우
      options vfio-pci ids=10de:0638
      options vfio-pci disable_vga=1
      
    • nVidia GT730 그래픽 카드인 경우
      options vfio-pci ids=10de:1287,10de:0e0f
      options vfio-pci disable_vga=1
      
    • nVidia GT1030 그래픽 카드인 경우
      options vfio-pci ids=10de:1d01,10de:0fb8
      options vfio-pci disable_vga=1
      
  • initramfs 갱신을 위해서 다음의 명령을 실행합니다. (부팅에서 initramfs 기반 배포판이 아닌 경우이거나 Ubuntu가 아닌 배포판의 경우는 이 과정이 다를 수 있습니다.)
    $ sudo update-initramfs -u
    
  • grub과 initramfs 을 갱신했으므로 반영하기 위해서 재부팅이 필요합니다.
    $ sudo reboot
    
  • 재부팅 된 후 부팅메세지(dmsg)를 보시면 "DMAR" 또는 "IOMMU" 라는 문자열을 포함한 메세지가 확인된다면 준비된 것입니다. (이제 해당 PCI 장치는 가상머신에게 모든 권한을 위임할 준비가 된 자원이 됩니다. 환경에 따라서 약간 다른 메세지로 보일 수 있습니다.)
    $ sudo dmesg | grep -i -e DMAR -e IOMMU             # 또는 => sudo dmesg | grep -E "DMAR|IOMMU" 
    [    0.016937] ACPI: DMAR 0x00000000BF77E0C0 000110 (v01 AMI    OEMDMAR  00000001 MSFT 00000097)
    [    0.017009] ACPI: Reserving DMAR table memory at [mem 0xbf77e0c0-0xbf77e1cf]
    [    0.217765] DMAR: IOMMU enabled
    [    0.462452] DMAR-IR: This system BIOS has enabled interrupt remapping
    [    0.897740] DMAR: Host address width 40
    [    0.897744] DMAR: DRHD base: 0x000000fbffe000 flags: 0x1
    [    0.897755] DMAR: dmar0: reg_base_addr fbffe000 ver 1:0 cap c90780106f0462 ecap f020f6
    [    0.897760] DMAR: RMRR base: 0x000000000ed000 end: 0x000000000effff
    [    0.897763] DMAR: RMRR base: 0x000000bf7ed000 end: 0x000000bf7fffff
    [    0.897766] DMAR: ATSR flags: 0x0
    [    0.897788] DMAR: No SATC found
    [    0.897796] DMAR: dmar0: Using Queued invalidation
    [    0.907806] DMAR: Intel(R) Virtualization Technology for Directed I/O
    ...
    
  • 또한 vfio-pci 모듈이 잘 활성화(Enabled) 되었는지 확인하면 됩니다. (이 메세지는 실제 가상화 호스트가 구동되어 해당 장치가 passthrough활성화 될 때 확인가능합니다. 가상화 호스트 구동하지 않으면 안나옵니다.)
    $ sudo dmesg | grep -i vfio 
    [    8.015119] VFIO - User Level meta-driver version: 0.3
    [    8.034941] vfio-pci 0000:07:00.0: vgaarb: changed VGA decodes: olddecodes=io+mem,decodes=io+mem:owns=none
    [    8.052303] vfio_pci: add [10de:0638[ffff:ffff]] class 0x000000/00000000
    [  567.518237] vfio-pci 0000:07:00.0: enabling device (0140 -> 0143)
    [127997.152879] vfio-pci 0000:07:00.0: enabling device (0400 -> 0403)
    
  • 아래 화면은 제 그래픽 카드를 passthrough 설정하여 가상머신에서 사용하도록 설정하는 화면입니다.
    kvm+qemm+virt-manager+passthrough.png
    [PNG image (210.02 KB)]
    • passthrough 로 Windows 가상머신 장치관리자에 해당 장치가 보이게 됩니다.
      passthrough-to-windows.png
      [PNG image (24.75 KB)]

1.7. 유틸 사용법 및 기타 유용한 사항들

다른 VM disk image를 KVM용 qcow2 로 변환하는 방법 (qemu-utils 에 포함된 변환 도구, [https]Windows용 qemu-utils 다운로드 링크[](https://www.qemu.org/download/#windows))
# 사용법 : qemu-img convert -O <변환하고자 하는 포맷 이름> <변환할 파일명:source> <변환된 포맷으로 저장할 파일명:target>
예)
$ qemu-img convert -O qcow2 MyVMdisk1.vmdk MyVMdisk1.qcow2

이미지 변환 과정에서 크기를 최대한 줄이고자 한다면 "-c" 옵션도 함께 추가할 수 있습니다. (단, 이 경우 가상머신이 조금 느려질 수 있습니다.)
예)
$ qemu-img convert -c -O qcow2 MyVMdisk1.vmdk MyVMdisk1.qcow2

-p 옵션을 사용하면 변환시 진행률을 확인 할 수 있습니다.
  • 지원 가능한 변환 포맷 확인
    $ qemu-img --help |grep "Supported formats"
    Supported formats: blkdebug blkreplay blkverify bochs cloop dmg file ftp ftps host_cdrom host_device http https iscsi iser luks nbd null-aio null-co parallels qcow qcow2 qed quorum raw rbd replication sheepdog throttle vdi vhdx vmdk vpc vvfat
    



    명령행에서 가상머신 다루기 (명령행 번거롭습니다. virt-manager 사용을 권합니다.)
    $ virsh --help
    
  • 가상환경 목록 확인
    $ virsh list --all
     Id    Name                           State
    ----------------------------------------------------
     -     Windows                        shut off
    ...
    
  • 가상환경 실행/종료/재시작
    $ virsh start [--console] <Name>
    $ virsh shutdown <Name>
    $ virsh destroy <Name>
    $ virsh reboot <Name>
    
  • 가상환경의 console 접속 (console 정의가 설정된 가상환경과 해당사항을 지원하는 OS인 경우에 대한 제한적 사용)
    $ virsh console <Name>
    ...
    => ^] (Ctrl+']') 키를 누르면 Attach된 console에서 빠져나올 수 있습니다.
    

1.8. 문제 대응(TroubleShooting) 또는 유용한 사항(Tip)

1.8.1. 특별한 부하작업이 없음에도 가상머신의 CPU 부하가 큰 경우

  • 아무것도 하지 않는데도 불구하고 가상머신의 CPU 부하가 큰 경우 (또는 운영체제 부팅과정에서 Timer 관련 오류등이 있는 경우 시도해볼만한 설정, 권장)
    $ virsh edit "<가상머신 이름>"
    
    
    다음과 같이 clock 설정 부분의 내용을 동일하게 편집하고 저장하고 가상머신을 재시작 해봅니다.
    
    Guest 운영체제가 Windows 계열인 경우
    >>>
      <clock offset='localtime'>
        <timer name='hpet' present='no'/>
        <timer name='hypervclock' present='yes'/>
      </clock>
    <<<
    
    또는 Guest 운영체제가 Linux 계열인 경우
    >>>
      <clock offset='localtime'>
        <timer name='hpet' present='no'/>
        <timer name='kvmclock' present='yes'/>
      </clock>
    <<<
    

1.8.2. 가상머신 호스트 (서버) 와 게스트간 통신이 안되는 경우

  • 서버의 인터페이스를 Bridge 인터페이스로 설정이 필요할 수 있습니다.
  • 또는 게스트의 인터페이스를 macvlan bridge mode 로 설정할 필요가 있습니다.
  • Docker 를 함께 운영하는 경우 Docker의 network에 iptables false 설정이 필요할 수 있습니다.

1.8.3. VGA console 이 제공되지 않고 Serial console 만 제공하는 환경에서 Ubuntu 설치하기 위한 설치 이미지 만드는 방법

  • 사전에 결정해야 하는 것
    • UEFI(Universal Extensible Firmware Interface) 방식의 부팅 설치를 할 것인지 CSM(Compatibliity Support Module) 방식의 부팅 설치를 할 것인지에 따라서 USB 이미지를 만드는 방법 및 BIOS 설정 등에서 차이가 있습니다.
  • 설치하고자 하는 Ubuntu 배포판 iso 파일을 [https]rufus 유틸[](https://rufus.ie/)을 이용하여 USB로 만듭니다.
    • UEFI(Universal Extensible Firmware Interface, 최신 부팅 방식) 방식의 USB 부팅 디스크
      • 파티션은 GPT(GUID Partition Table) 형식을 선택합니다. (참고: 파티션의 이해)
      • 파일시스템 포맷은 지원 가능한 아무거나 선택할 수 있으나 편의상 FAT(권장) 또는 FAT32를 선택합니다.
      • 아주 옛날 하드웨어인 경우 UEFI 부팅을 지원하지 않을 수 있습니다만 요즘은 거의 지원합니다.
        • BIOS설정에서 UEFI 관련 항목을 활성화 해주셔야 합니다.
    • CSM(Compatibliity Support Module, 예전 부팅 방식) 방식의 USB 부팅 디스크
      • 파티션은 MBR(Master Boot Record) 형식을 선택합니다. (참고: 파티션의 이해)
      • 파일시스템 포맷은 FAT(권장) 또는 FAT32를 선택합니다.
    • USB 부팅 디스크를 만든 후 해당 USB 디스크 드라이브에서 *.cfg (grub.cfg, isolinux.cfg, txt.cfg, syslinux.cfg) 등을 찾아 Kernel boot parameter 로 'vga=normal console=tty0 console=ttyS0,115200n8' 이 되도록 적절한 수정을 하고 저장합니다.
      • UEFI 방식의 경우는 grub.cfg 만 찾아서 수정하시면 됩니다.
      • 중요한 것은 USB 부팅 디스크로 부팅시에 Linux kernel의 boot parameter 로 'console=ttyS0,115200n8' 가 주어지도록 하는게 핵심입니다.
        • syslinux 기반의 경우 syslinux.cfg 에서 'SERIAL 0 115200 0'가 추가되어야 합니다.
      • 참고) [https]How to install Ubuntu using serial console[](https://github.com/ynkjm/ubuntu-serial-install) (내용이 최신 배포판과는 다소 다를 수 있으나 맥락은 동일합니다.)
        • isolinux/txt.cfg
          default install
          label install
            menu label ^Install Ubuntu Server
            kernel /install/vmlinuz
            append vga=normal initrd=/install/initrd.gz -- console=tty0 console=ttyS0,115200n8 nosplash debug -
          
        • syslinux.cfg
          CONSOLE 0
          SERIAL 0 115200 0
          
          default menu.c32
          prompt 0
          menu title UNetbootin
          timeout 100
          
          label unetbootindefault
          kernel /ubnkern
          append vga=normal initrd=/ubninit nomodeset askmethod console=tty0 console=ttyS0,115200n8
          
        • boot/grub/grub.cfg
          menuentry "Install Ubuntu Server" {
              set gfxpayload=keep
              linux   /install/vmlinuz  file=/cdrom/preseed/ubuntu-server.seed vga=normal console=tty0 console=ttyS0,115200n8 ---
              initrd  /install/initrd.gz
              }
          

1.8.4. KVM+QEMU 가상머신내에서 가상머신을 구동하려는 경우 (nested 가상화)

  • 호스트 서버에서 "/etc/modprobe.d/kvm.conf" 파일을 만들고 다음과 같이 내용을 적어 kvm_intel 모듈에 nested 인자를 전달하도록 합니다.
    $ cat /etc/modprobe.d/kvm.conf
    options kvm_intel nested=Y
    
  • 그리고 'update-initramfs -u' 명령으로 ramdisk 를 갱신하고 재부팅하면 이후부터는 가상머신내에서 가상머신을 구동할 수 있습니다.

1.8.5. Ubuntu 배포판을 최신버젼의 배포판으로 업그레이드 하려면

  • 자신의 기존 설치된 환경의 Ubuntu 배포판을 최신 배포버젼으로 설치하려면 다음과 같이 실행해볼 수 있습니다. (실행 후 질의 응답을 잘 읽어보시면서 대응하면 어렵지 않게 간단히 업그레이드 하실 수 있습니다.)
    $ sudo do-release-upgrade
    

1.8.6. 가상머신에 설치된 OS를 Wake on LAN (WOL) 으로 기동하고 싶을 때

  • "/usr/local/bin/listen-virt-wol.sh" 파일에 다음의 내용을 편집하여 저장하고 실행퍼미션("sudo chmod +x /usr/local/bin/listen-virt-wol.sh")을 부여해줍니다.
    #!/bin/bash
    
    # 이 예제 스크립트는 포트가 9/UDP 인 WOL magic packet을 수신하여 가상머신을 기동해주는 것이며 적절히 자신의 환경에 맞도록 수정해야 할 수 있습니다.
    # WOL magic packet 을 전송하는 프로그램에 따라서 포트 번호가 다를 수 있습니다. (참고로 필자의 경우는 2304/UDP 로 변경해서 사용하고 있습니다.)
    # listen to udp port 9 for packets, check if it is a magic packet
    netcat -dkn -l 9 -u | stdbuf -o0 xxd -c 6 -p | stdbuf -o0 uniq | stdbuf -o0 grep -v 'ffffffffffff' | while read
    do
        echo "Got triggered with $REPLY"
        mac="${REPLY:0:2}:${REPLY:2:2}:${REPLY:4:2}:${REPLY:6:2}:${REPLY:8:2}:${REPLY:10:2}"
    
        # loop through libvirt machines
        for vm in $(virsh list --all --name)
        do
            # Get the MAC address and compare with the magic packet
            vmmac=$(virsh dumpxml $vm | grep "mac address" | awk -F\' '{ print $2}')
            if [ "$vmmac" = "$mac" ]
            then
                state=$(virsh list --all|awk -v vm=$vm '{ if ($2 == vm ) print $3 }')
                echo "Found $vm with $mac in $state state"
    
                # Dependent on the state, resume or start
                [ $state == "paused" ] && virsh -q resume $vm && virsh domtime --domain $vm --now
                [ $state == "shut" ] && virsh -q start $vm
            fi
        done
    done
    
  • "/etc/systemd/system/listen-virt-wol.service" 을 다음과 같이 편집하여 저장하고 서비스를 활성화("sudo systemctl enable listen-virt-wol.service") 및 시작("sudo systemctl start listen-virt-wol.service")합니다.
    [Unit]
    Description=Listen virt wake-on-lan
    Requires=network.target
    After=network.target
    
    [Service]
    Type=simple
    ExecStart=/usr/local/bin/listen-virt-wol.sh
    KillMode=control-group
    Restart=on-failure
    User=root
    Group=root
    
    [Install]
    WantedBy=multi-user.target
    

1.8.7. QEMU 에서 지원하는 NIC model 확인하는 방법

  • 다음과 같이 "qemu-system-<arch>" 명령에 "-net nic,model=?" 옵션을 통해서 지원가능한 모델명을 확인할 수 있습니다.
    $ qemu-system-x86_64 -net nic,model=?
    Supported NIC models:
    e1000
    e1000-82544gc
    e1000-82545em
    e1000e
    i82550
    i82551
    i82557a
    i82557b
    i82557c
    i82558a
    i82558b
    i82559a
    i82559b
    i82559c
    i82559er
    i82562
    i82801
    ne2k_pci
    pcnet
    pvrdma
    rtl8139
    tulip
    virtio-net-pci
    virtio-net-pci-non-transitional
    virtio-net-pci-transitional
    vmxnet3
    
  • 참고) https://computernewb.com/wiki/QEMU/Devices/Network

1.8.8. Guest OS 에서 virtio NIC를 사용하도록 구성할 때 TSO/GSO/LRO/GRO/ECN등을 off 하려면

  • 다음과 같이 "virsh edit <domain>" 을 통해서 interface tag 내에 다음과 같이 driver tag 로 host 또는 guest에 대한 설정을 반영하면 TSO/GSO/LRO/GRO/ECN 등이 비활성화 됩니다.
        <interface type='network'>
          <mac address='xx:xx:xx:xx:xx:xx'/>
          <source network='internal'/>
          <model type='virtio'/>
          <driver>
            <host tso4='off' tso6='off' lro='off' gro='off' ecn='off'/>
            <guest tso4='off' tso6='off' lro='off' gro='off' ecn='off'/>
          </driver>
          <address type='pci' domain='...' bus='...' slot='...' function='...'/>
        </interface>
    
    • 사실상 잘 만들어진 SW는 이 사항을 변경할 필요가 없습니다. 문제가 없다면 이 설정은 전혀 필요 없으며, 지나치게 느리거나 재전송이 일어난다고 파악되는 경우에만 시도할만한 설정입니다.
      • 요즘 OS나 SW는 거의 문제가 없지만, 간혹 옛날 버전에서 가장 많이 발생되는 SW적인 문제는 LRO/GRO를 off 함으로써 해결될 수 있습니다. (즉, 대부분의 문제는 Large segment 패킷 수신 처리를 어떻게 하는지 모르던 시절 구현된 SW에서 문제가 되는 현상을 의미합니다.)
      • 예) Guest OS 가 Unix/Linux 계열인 경우, 다음과 같이 ethtool 명령을 부팅시 실행하게 해주면 될 수 있습니다.
        $ sudo ethtool -K eth0 tso off lro off gro off ecn off
        
  • host vs guest 어느 쪽에 반영해야 하는지 현재 저도 명확하지 않은 듯 싶으나 수신 관련은 host 쪽, 송신 관련은 guest 쪽이라는 내용을 어디선가 본 듯 합니다. 아무튼 virtio driver source 를 보면 기능 flags로써 이러한 사항이 전달되어 작용되는 것으로 보입니다.
    => virtio net driver 일부 발췌. 여기서 VIRTIO_NET_F_GUEST_XXX 가 관여하는 것으로 추정됨. ethtool -k | -K 옵션은 여기서는 애매한 듯 합니다.
    ...
        if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
            virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) ||
            virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN))
            vi->big_packets = true;
    ...
    

1.9. 참고자료

Retrieved from https://www.minzkn.com:443/moniwiki/wiki.php/UbuntuVirtualMachineServerInstall
last modified 2024-02-10 18:42:43