Proxmox Sanallaştırma Ortamı İçinde Debian Kurulu Bir Sanal Makine ve Küme Oluşturma Lab Çalışması

 

"Gitlab Repo: "gitlab.com/msenturk/cluster_in_proxmox"

 

Benim kullandığım test ortamı şu şekilde:

  • Sanallaştırma sistemi Debian-Buster üzerinde Proxmox 6.
  • Ağ yapılandırması bir tane gerçek ağ arayüzü ve üç tane de sanal köprüden oluşuyor. İşlemleri yapacağımız ağ arayüzü, Iptables ile Masquerade yapılarak kurulmuş ve internete çıkabilen NAT ağının tanımlandığı vmbr2.
  • NAT ağına bağlanan makinelerin IP alabilmesi için Dnsmasq DHCP sunucusu.
  • Temel paketler: dnsmasq, resolvconf, debootstrap, vmdebootstrap, qemu-system, tree.

 

Anlatılacak konu başlıkları:

  1. Debootstrap ve chroot kullanımı

    • Bir Debian kök dosya sistemi oluşturmak
    • Oluşturulan kök dosya sistemine gerçek aygıtları bağlamak
    • Chroot ile bu sistemin içine girerek işlemler yapmak
  2. Vmdebootstrap kullanımı

    • Boot edilebilir bir imaj oluşturup makineyi Qemu ile ayağa kaldırmak
    • Boot edilebilir bir imaj oluşturup makineyi Proxmox ile ayağa kaldırmak
  3. Dnsmasq kullanımı

    • DHCP konfigürasyonunun yapılması
    • Static-DHCP konfigürasyonunun yapılması
  4. Sanal makinelerle bir küme oluşturmak

 

 

1. Debootstrap ve chroot kullanımı

Bir Debian kök dosya sistemi oluşturmak

Debootstrap aracını kullanarak Arch, Debian, Ubuntu işletim sistemleri için istediğiniz bir işlemci mimarisi için kök dosya sistemleri oluşturabilir, istediğiniz paketleri bu sistem içerisine kurabilir ve konfigürasyon yapabilirsiniz.

Örneğin arm64 mimarisini kullanarak bir Debian kök dosya sistemi oluşturmak için şu komutu kullanabilirsiniz:

# Boş bir dizin oluşturun
mkdir -p /tmp/stable-chroot

# Dosya sistemini oluşturun
debootstrap --arch=arm64 buster /tmp/stable-chroot http://deb.debian.org/debian/
...
I: Configuring libnftnl11:arm64...
I: Configuring vim-tiny...
I: Configuring ifupdown...
I: Configuring bsdmainutils...
I: Configuring whiptail...
I: Configuring libnetfilter-conntrack3:arm64...
I: Configuring iptables...
I: Configuring tasksel-data...
I: Configuring tasksel...
I: Configuring libc-bin...
I: Configuring systemd...
I: Base system installed successfully.

 

İşlemci mimarisini öğrenmek için gereken /proc/cpuinfo dosyası sistemde bulunmadığı için lscpukomutu ile bunu ARM64 sonucunu göremezsiniz. Bunun yerine dosya sistemi içindeki ikilik dosyaların özelliklerine bakabilirsiniz.

file /tmp/stable-chroot/bin/ls
/tmp/stable-chroot/bin/ls: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=9ecc063cc78a0a8c15f950e5e8fc4a6954c734dc, stripped

 

Komutun çıktısında ARM aarch64 ifadesini görebilirsiniz.

 

 

Oluşturulan kök dosya sistemine gerçek aygıtları bağlamak

Debootstrap'in yaptığı işlem sadece kök dosya sistemini oluşturmaktı. Yani tam bir işletim sistemi kurulumu değil. Eğer /tmp/stable-chroot/ dizininin içindeki sys, proc, boot gibi alt dizinlerin içine bakacak olursanız boş olduğunu görebilirsiniz.

tree /tmp/stable-chroot/{sys,proc,boot}
/tmp/stable-chroot/sys
/tmp/stable-chroot/proc
/tmp/stable-chroot/boot

0 directories, 0 files

 

 

GNU/Linux çekirdeğinin ve uyumlu dosya sistemlerinin özellikleri sayesinde ana makinenin gerçek aygıtlarını, oluşturduğumuz bu kök dosya sistemine bağlayarak kullanabiliriz.

mount proc  /tmp/stable-chroot/proc -t proc
mount sysfs /tmp/stable-chroot/sys  -t sysfs
cp /etc/hosts   /tmp/stable-chroot/etc/hosts
cp /proc/mounts /tmp/stable-chroot/etc/mtab

Bu dizinleri bağlayıp dosyaları kopyalamak temel olarak yeterlidir. /tmp/stable-chroot/proc dizininin altındaki dosyaları listelerseniz ana makinedeki /proc dizini ile aynı olduğunu görebilirsiniz.

ls /tmp/stable-chroot/proc

 

 

Chroot ile bu sistemin içine girerek işlemler yapmak

Chroot, "Change Root" kelimelerinin kısaltmasıdır. Farklı bir kök dosya sistemine geçiş yapmanızı ve terminal komutlarını çalıştırabilmenizi sağlar. Temel kullanımı chroot <yeni_kök_dosya_sistemi> <komutlar> şeklindedir.

chroot /tmp/stable-chroot /bin/apt update

 

Eğer ana sisteminiz internete bağlı ise repoların güncellendiğini görmelisiniz.

Hit:1 http://deb.debian.org/debian buster InRelease
Reading package lists... Done
Building dependency tree... Done
All packages are up to date.

 

 

apt update yerine /bin/bash yazarsanız yeni kök dosya sistminde çalışan bir kabuk oturumu açmış olacaksınız.

chroot /tmp/stable-chroot /bin/bash

 

Bu kabukta çalıştırdığınız komutlar, /tmp/stable-chroot dizini altındaki dosyaları ve aygıtları etkiler. Yani bir paket kurulumu yaparsanız, ana makineye bir etkisi olmaz. Ancak bağlı olan aygıtları etkiler. Bunu en kolay ps aux komutu ile görebilirsiniz. Ana makinenin işlemleri ekranda listelenecektir. Aynı şekilde ip a komutu ile de ana makinedeki ağ arayüzlerini listeleyebilirsiniz. Son olarak uname -r komutu ile ana makinenin çekirdek sürümünü de görebilirsiniz.

"Peki farkı nasıl anlayabilirim?" derseniz, cat /etc/machine-id komutunu hem ana sistemin terminalinde hem de chroot ile giriş yaptığınız terminalde çalıştırın. İki ID'nin farklı olduğunu görebilirsiniz. İkna olmadıysanız grep '^root' /etc/shadow komutu ile kök kullanıcının parolasına bakın. Boş olması gerekiyor. Yahut grep 'PRETTY_NAME' /etc/os-release komutu ile Debian 10 sonucunu almalısınız. Eğer Debian Bullseye içinde Proxmox 7 kullanıyorsanız farklı olduğunu görebilirsiniz.

Kök dosya sisteminin farklı olduğu, çekirdek ve aygıtların ortak olduğu, buna benzer bir durumu bir Docker konteynırının içindeyken de görmüş olabilirsiniz. Konteyner sistemi de aslında aynı mantığa dayanıyor. Sadece güvenlik, izolasyon ve kaynak kısıtlaması için ilave aygıtlar ve katmanlar kullanılıyor.

 

 

2. Vmdebootstrap kullanımı

İsterseniz bu sistemi GRUB2 kurarak boot edilebilir hale getirebilirsiniz. Ancak bir disk aygıtı olmadığı için MBR kaydını yapamazsınız. Bu sorunu, dd aracı ile bir disk imajı oluşturup, kök dosya sistemini bu imajın içine kopyalayarak çözebilirsiniz. Bu defa da gerçek aygıtlar olmadığı için yine başarısız olacaksınız. Bu durumda vmdebootstrap aracı yardımımıza koşuyor.

Devam etmeden önce chroot ile bağlı olduğunuz sistemden exit komutu ile çıkın ve dosya sistemini rm -rf /tmp/stable-chroot komutu ile silin.

Vmdebootstrap, Debootstrap ile aynı işi görmesinin yanısıra boot edilebilir bir disk imajı oluşturmamızı sağlayacak. Oluşturacağımız bu sistemi hem sanal makineler içinde hem de bir diske yazdırarak canlı olarak kullanabiliriz.

 

 

Boot edilebilir bir imaj oluşturup makineyi Qemu ile ayağa kaldırmak

 

vmdebootstrap \
    --distribution="buster" \
    --hostname debian-test \
    --root-password="top_secret" \
    --user="new_user/top_secret" \
    --image /tmp/bootable_deb.qcow2 \
    --size 16GiB \
    --log="/tmp/bootstrap.log" \
    --sparse \
    --grub \
    --no-extlinux \
    --sudo \
    --convert-qcow2 \
    --enable-dhcp \
    --package openssh-server \
    --package curl \
    --verbose \
    --serial-console

 

 

İnternet hızınıza bağlı olarak yaklaşık 2 dk içinde tam bir Debian Buster kurmuş olacaksınız.

 

Kullandığımız parametrelerin açıklaması kısaca şöyle:

--distribution="buster"
    Buster, Bullseye gibi bir Debian kök sistem seçiyoruz.

--hostname debian-test
    Kurulan sisteme bir isim veriyoruz.

--root-password="top_secret"
    Root kullanıcısının parolası.

--user="new_user/top_secret"
    İlave bir kullanıcı ekleyip parolasını belirliyoruz.

--image /tmp/bootable_deb.qcow2
    Oluşturulacak imajın yeri.

--size 16GiB
   Oluşturulacak imajın disk boyutu.

--log="/tmp/bootstrap.log"
    İşlem günlüğünün yeri.

--sparse
    Oluşan disk imajının boş kısımlarını kaldırıyoruz.
    Bunu yapmazsanız /tmp/bootable_deb.qcow2 imajının boş kısımları sıfırlarla doldurulur ve dosya 16G büyüklüğünde olur.

--grub
    Önyükleme için GRUB tercih ediyoruz.

--no-extlinux
    Extlinux istemiyoruz.

--sudo
    Oluşturduğumuz kullanıcıya sudo yetkisi veriyoruz.

--convert-qcow2
    Oluşturulan disk imajını Qcow2 formatına dönüştürüyoruz.
    Bunu seçmezseniz Raw olarak oluşacak.

--enable-dhcp
    Ağ yapılandırmasını DHCP ile IP alacak şekilde oluşturacak.

--package openssh-server
--package curl
    İlave olarak kurulmasını istediğimiz paketleri bu şekilde belirtebiliyoruz.

--verbose
    Yapılan işlemler hakkında ekrana bilgi basmasını istiyoruz.

--serial-console
   Kurduğumuz sistemi sanallaştırma ortamında kullanacağımız için serial-console kullanılabilecek şekilde yapılandırıyoruz.
   Bu seçeneği Proxmox üzerinde koşturulacak makinelerde kullanmayın. Muhtemelen açılmayacaktır.

 

Creating disk image
Creating partitions
Creating filesystem ext4
Mounting /dev/mapper/loop0p1 on /tmp/tmpUWQOzd
Debootstrapping buster [amd64]
Setting root password
Removing udev persistent cd and net rules
Enabling systemd-networkd for DHCP
Enabling systemctl-resolved for DNS
Updating the initramfs
Configuring grub2
Umounting /tmp/tmpUWQOzd
Converting raw image to qcow2
Cleaning up

 

 

Şimdi bu imajı kullanarak Qemu ile bir sanal makine ayağa kaldıralım.

 

qemu-system-x86_64 \
    -drive file=/tmp/bootable_deb.qcow2,format=qcow2 \
    -nographic \
    -m 2G

 

...
[  OK  ] Started Permit User Sessions.
[  OK  ] Started Getty on tty5.
[  OK  ] Started Getty on tty2.
[  OK  ] Started Getty on tty4.
[  OK  ] Started Serial Getty on ttyS0.
[  OK  ] Started Getty on tty6.
[  OK  ] Started Getty on tty3.
[  OK  ] Started Getty on tty1.
[  OK  ] Reached target Login Prompts.
[  OK  ] Started OpenBSD Secure Shell server.
[  OK  ] Reached target Multi-User System.
[  OK  ] Reached target Graphical Interface.
  Starting Update UTMP about System Runlevel Changes...
[  OK  ] Started Update UTMP about System Runlevel Changes.

Debian GNU/Linux 10 debian-test ttyS0

debian-test login:

Aynı terminal içinde bir makinenin açılışını görüyor olmalısınız. Yukarıda belirttiğimiz kullanıcı adı (new_user veya root) ve parolayı (top_secret) kullanarak sisteme giriş yapabilirsiniz.

 

Linux debian-test 4.19.0-17-amd64 #1 SMP Debian 4.19.194-1 (2021-06-10) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
root@debian-test:~#

 

 

vmdebootstrap komutuna verdiğimiz parametrelerde curl paketini kurmasını istemiştik. Hem paketlerin kurulduğunu hem de internete çıkabildiğinizi doğrulamak için şu komutu çalıştırın:

curl ifconfig.me

 

Eğer internete çıkış yaparken kullandığınız IP adresini görüyorsanız her şey yolunda demektir. poweroff komutu ile makineyi kapatabilirsiniz.

 

 

Boot edilebilir bir imaj oluşturup makineyi Proxmox ile ayağa kaldırmak

 

Şimdi Proxmox sanallaştırma ortamında kullanabileceğimiz bir imaj daha oluşturalım.

vmdebootstrap \
    --distribution="buster" \
    --hostname debian-test \
    --root-password="top_secret" \
    --user="new_user/top_secret" \
    --image /tmp/bootable_deb_proxmox.qcow2 \
    --size 16GiB \
    --log="/tmp/bootstrap.log" \
    --sparse \
    --grub \
    --no-extlinux \
    --sudo \
    --convert-qcow2 \
    --enable-dhcp \
    --package openssh-server \
    --package curl \
    --verbose

 

Yukarıdaki parametrelerde --image hedefinin dışında bir farklılık daha var. --serial-console parametresini kaldırdık. Buna dikkat etmezseniz, imajı Proxmox içinde bir sanal makine ile kullanmak istediğinizde makine açılmayacaktır.

Oluşturduğunuz imaj bir kenarda dursun. Önce bir sanal makine oluşturalım. VmID olarak 999 kullandım. 3 haneli başka bir sayı da yazabilirsiniz.

 

# /var/lib/vz/images dizini, Proxmox'un local-storage içinde makine imajlarının tutulduğu yer.
# Sizin sisteminizde farklı bir dizinde veya depolama alanında olabilir.
mkdir -p /var/lib/vz/images/999

# Proxmox, kontrolü kolaylaştırmak için belli türdeki dosyaların belli yerlerde tutulmasını istiyor.
# Disk imajını, sanal makine disklerinin olması gerektiği yere kopyalayın.
cp -v \
    /tmp/bootable_deb_proxmox.qcow2 \
    /var/lib/vz/images/999/vm-999-disk-0.qcow2

 

 

Disk alanı hazır olduğuna göre Proxmox üzerinde bir sanal makine oluşturabilirsiniz.

# Rastgele bir MAC adresi oluşturuyoruz.
# İsterseniz ${generate_MAC} değişkeni yerine elle bir adres belirtebilirsiniz.
generate_MAC="$(od -An -N6 -tx1 /dev/urandom | sed -e 's/^  *//' -e 's/  */:/g' -e 's/:$//' -e 's/^\(.\)[13579bdf]/\10/')"

# qm aracı ile bir sanal makine konfigürasyonu oluşturuyoruz.
qm create 999 \
    --name vm999 \
    --net0 virtio="${generate_MAC}",bridge=vmbr2,firewall=1 \
    --virtio0 "local:999/vm-999-disk-0.qcow2",size=16G \
    --bootdisk virtio0 \
    --ostype l26 \
    --memory 2048 \
    --onboot no \
    --sockets 1 \
    --cores 4 \
    --scsihw virtio-scsi-pci

 

 

Kullandığımız parametrelerin açıklaması kısaca şöyle:

qm create 999
    999 ID numarasını kullanarak bir makine oluştur.

--name vm999
    Sanal makineye bir isim ver.

--net0 virtio="00:00:00:00:00:10",bridge=vmbr2,firewall=1
    Ağ arayüzü seçeneklerini belirle.
    Bridge olarak sisteminizde hangi arayüzü kullanıyorsanız onu seçin.

--virtio0 local:999/vm-999-disk-0.qcow2,size=16G
    Bağlanacak diskin konumu ve boyutu.

--bootdisk virtio0
    Boot aygıtı.

--ostype l26
    l26 Linux işletim sistemi.

--memory 2048
    Tahsis edilecek bellek boyutu 2 GB.

--onboot no
    Sistem başlangıcında otomatik açılmasını istiyorsanız "yes" olarak değiştirin.

--sockets 1
    Tahsis edilecek işlemci soket sayısı (Genelde 1).

--cores 4
    Tahsis edilecek işlemci çekirdek sayısı.

--scsihw virtio-scsi-pci
    SCSI aygıtı

 

 

Proxmox ortamında tanımlanmış makineleri listelemek için:

qm list

 

Proxmox ortamında tanımlanmış bir makineyi başlatmak için:

qm start 999

 

Proxmox ortamında tanımlanmış bir makineyi durdurmak için:

qm stop 999

 

Proxmox ortamında tanımlanmış bir makineyi klonlamak için:

# Oluşturmak istediğimiz sanal makine ID'lerini bir dizi içinde tanımlıyoruz.
declare -ag VM_IDS=(100 101 102 103 104)

# VM_IDS dizisini kullanarak bir for döngüsü çalıştırıyoruz.
for i in ${VM_IDS[@]}
do
    qm clone 999 ${i} \
        --description vm${i} \
        --name vm${i} \
        --format qcow2 \
        --full true \
        --storage local 1>/dev/null && echo "vm${i} hazır!"
done

 

 

Proxmox ortamında tanımlanmış bir makineyi imha etmek için:

qm stop 999 && \
    qm destroy 999 \
        --destroy-unreferenced-disks true \
        --purge true

 

 

Proxmox ortamında tanımlanmış tüm makineleri imha etmek için:

# Proxmox içinde tanımlanmış sanal makinelerin listesini alıyoruz.
vm_list=($(qm list | awk '{print $1}' | tr -s '\n' ' ')); unset 'vm_list[0]'

# Listeyi for döngüsü ile kullanıp makineleri imha ediyoruz.
for i in ${vm_list[@]}
do
    qm stop ${i} && \
    qm destroy ${i} \
        --destroy-unreferenced-disks true \
        --purge true
done

 

 

3. Dnsmasq kullanımı

DHCP konfigürasyonunun yapılması

Dnsmasq paketini ilk kurduğunuzda /etc/dnsmasq.conf dosyasının içeriğine bakarsanız oldukça karmaşık olduğunu görebilirsiniz. Aslında DHCP sunucusu için gereken yapılandırma çok basit.

 

# DHCP Sunucusunun hizmet vereceği ağ arayüzü
interface=vmbr2

# Dağıtılacak adres aralığı ve kira süresi
dhcp-range=10.0.2.100,10.0.2.254,12h

# Dnsmasq çalışma modu 3 (router)
dhcp-option=vmbr2,3,10.0.2.1

# Gateway adresi
server=10.0.2.1@vmbr2

# Kiralama dosyası
dhcp-leasefile=/var/lib/misc/dnsmasq.leases

 

Yukarıdaki bloğu, kendi ağ yapılandırmanıza göre düzenleyip /etc/dnsmasq.conf dosyasına yazın. Ve servisi yeniden başlatın.

systemctl restart dnsmasq.service

 

Sanal makineyi ayağa kaldırdığınızda 10.0.2.100-10.0.2.254 aralığında bir adres aldığını göreceksiniz.

 

 

Static-DHCP konfigürasyonunun yapılması

Tek bir sanal makine için statik IP adresi tanımlamak kolaydır. Ancak bir cluster (küme) ayağa kaldırmanız gerektiğinde işler biraz karışabilir. DHCP ile verilen IP adreslerini elle belirlemek de mümkün. Bu şekilde bir Static-DHCP yapılandırması oluşturabiliriz.

Bu kısımda Adres Çözümleme Protokolü'nün (ARP) nasıl çalıştığını bilmeniz iyi olur. Ancak burada değinmeyeceğim.

DHCP'nin nasıl çalıştığını canlı canlı görmek için ise en basit yol, DHCP sunucusu çalışmakta iken servis günlüğünü izlemek.

 

Bu komutu sunucu içinde bir terminale yapıştırın.

journalctl -f -u dnsmasq.service

Başka bir terminalden veya Proxmox arayüzünden DHCP ile IP alacak şekilde yapılandırılmış bir sanal makineyi ayağa kaldırırsanız şöyle bir sohbetle karşılaşacaksınız:

Oct 09 21:38:36 P3 dnsmasq-dhcp[29982]: DHCPDISCOVER(vmbr2) 00:00:00:00:00:10
Oct 09 21:38:36 P3 dnsmasq-dhcp[29982]: DHCPOFFER(vmbr2) 10.0.2.105 00:00:00:00:00:10
Oct 09 21:38:36 P3 dnsmasq-dhcp[29982]: DHCPREQUEST(vmbr2) 10.0.2.105 00:00:00:00:00:10
Oct 09 21:38:36 P3 dnsmasq-dhcp[29982]: DHCPACK(vmbr2) 10.0.2.105 00:00:00:00:00:10 debian-test

 

Açıklaması kısaca şöyle:

VM: DHCPDISCOVER
'Merhaba. Ben 00:00:00:00:00:10. Boşta IP var mı?'

Dnsmaq: DHCPOFFER
'Merhaba 00:00:00:00:00:10. 10.0.2.105 var. Sana uyar mı?'

VM: DHCPREQUEST
'Ben 00:00:00:00:00:10. Evet 10.0.2.105 bana uyar, ver.'

Dnsmasq: DHCPACK
'Ey 00:00:00:00:00:10, nam-ı diğer debian-test 10.0.2.105 artık senin.'
'Hayrını gör.'

 

DHCP çalışma mantığını anladıysanız neye ihtiyacımız olduğunu biliyor olmalısınız: MAC adresine.

 

Sanal makineyi oluştururken bir MAC adresi belirtmediyseniz rastgele bir adres tanımlanmış olacaktır. Bunu konfigürasyon dosyasının içinden okuyabiliriz.

# Direkt olarak MAC adresini almak için:
awk -F'[=,]' '/^net0/{print $2}' /etc/pve/qemu-server/999.conf

# Ağ yapılandırmasını almak için:
grep '^net0' /etc/pve/qemu-server/999.conf

 

 

Şimdi yapmanız gereken tek şey, Dnsmaq'a hangi MAC adreslerine hangi IP adreslerini vereceğini tanımlamak. Bunun için tekrar /etc/dnsmasq.conf dosyasını bir metin editörü ile açıp aşağıdaki satırı kendi yapılandırmanıza göre düzenleyip ekleyin.

Sözdizimi bu şekilde:

>'dhcp-host=' + 'MAC ADRESİ' + ',' + 'IP ADRESİ'

 

dhcp-host=00:00:00:00:00:10,10.0.2.100

 

Ve servisi tekrar başlatın.

systemctl restart dnsmasq.service

 

 

Sanal makinenin tekrar IP adresi alması için networking servisini ya da makineyi tekrar başlatabilirsiniz.

 

qm stop 999 && sleep 2; qm start 999

 

Servis günlüğünü izlemeye devam ederseniz aynı konuşmanın 10.0.2.100 olarak tekrarlandığını görebilirsiniz.

 

 

4. Sanal makinelerle bir küme oluşturmak

Buraya kadar olan tüm işlemleri terminalden yapabildiğimize göre her şeyi otomatize etmek de tabii ki mümkündür. Tüm öğrendiklerinizi kullanarak 5 makineden oluşan bir cluster oluşturup statik IP ataması yapan bir betik yazabilirsiniz.

 

NOT: Betiği koşturmadan önce üst kısımdaki değişkenleri, kaynaklarınıza ve yapılandırmanıza göre düzenleyin.

 

#!/bin/bash
_init_deb(){
    SECONDS=0

    declare -g vm_ID="998"                      # Virtual machine ID
    declare -g vm_NAME="debian-skel"            # Virtual machine name
    declare -g vm_HNAME="debian-test"           # Virtual machine hostname
    declare -g vm_RELEASE="buster"              # Debian release code name (buster, bullseye)

    declare -g vm_SIZE="64"                     # Virtual machine qcow2 disk size (G)
    declare -g vm_RAM="2048"                    # Virtual machine RAM size (G)
    declare -g vm_CORE="4"                      # Virtual machine cpu core count
    declare -g vm_NET="vmbr2"                   # Virtual machine network interface

    declare -g root_pass=''                     # If you leave blank, the password will be created.
    declare -g new_user_pass=''                 # If you leave blank, the password will be created.

    declare -ag VM_IDS=(100 101 102 103 104)    # These VMs will be created (ID range: 100..254)

    # Generate MAC address
    declare -g mac_addr="$(od -An -N6 -tx1 /dev/urandom | sed -e 's/^  *//' -e 's/  */:/g' -e 's/:$//' -e 's/^\(.\)[13579bdf]/\10/')"

    # Generate root password
    test -z "${root_pass}" \
        && declare -g root_pass="$(tr -dc [:alnum:] < /dev/urandom | head -c 10)"

    # Generate new_user password
    test -z "${new_user_pass}" \
        && declare -g new_user_pass="$(tr -dc [:alnum:] < /dev/urandom | head -c 10)"

    _create_debian_image(){
        echo -e "\nDebootstrapping ${vm_ID} ...\n"

        vmdebootstrap \
        --distribution="${vm_RELEASE}" \
        --log="/tmp/bootstrap.log" \
        --verbose \
        --size ${vm_SIZE}GiB \
        --sparse \
        --grub \
        --no-extlinux \
        --root-password="${root_pass}" \
        --user="new_user/${new_user_pass}" \
        --sudo \
        --convert-qcow2 \
        --hostname ${vm_HNAME} \
        --enable-dhcp \
        --image /var/lib/vz/images/${vm_ID}/vm-${vm_ID}-disk-0.qcow2 \
        --package openssh-server \
        --package curl && \
            echo -e "
            \nBootstrap succeed!
            \tVirtual machine ID:\t${vm_ID}
            \tVirtual machine name:\t${vm_NAME}
            \tVirtual machine MAC:\t${mac_addr}
            \tDisk usage:\t\t$(du -sh /var/lib/vz/images/${vm_ID}/vm-${vm_ID}-disk-0.qcow2 | awk '{print $1}')
            \n\tRoot password:\t\t${root_pass}
            \tnew_user password:\t${new_user_pass}
            \nProcess completed in $((SECONDS/60)) min $((SECONDS%60)) sec\n
            " | \
                sed 's/    //g' || \
                { echo -e "\nBootstrap failed! \n" && tail /tmp/bootstrap.log && return || exit; }
    }

    _create_vm(){
        echo -e "\nCreating ${vm_ID} ...\n"

        qm create ${vm_ID} \
            --name ${vm_NAME} \
            --net0 virtio="${mac_addr}",bridge=${vm_NET},firewall=1 \
            --virtio0 local:${vm_ID}/vm-${vm_ID}-disk-0.qcow2,size=${vm_SIZE}G \
            --bootdisk virtio0 \
            --ostype l26 \
            --memory ${vm_RAM} \
            --onboot no \
            --sockets 1 \
            --cores ${vm_CORE} \
            --scsihw virtio-scsi-pci
    }

    _clone_vm(){
        echo -e "\n${vm_ID} is clonning ...\n"

        for i in ${VM_IDS[@]}
        do
            qm clone ${vm_ID} ${i} \
                --description vm${i} \
                --format qcow2 \
                --full true \
                --name vm${i} \
                --storage second-disk 1>/tmp/pers && echo "${i} is ready"
        done
    }

    _set_static_IP(){
        echo -e "\nSet dhcp-static IP configuration\n"

        # Purge DNSmasq config
        sed '/^dhcp-host.*/d' -i /etc/dnsmasq.conf
        rm -f                    /var/lib/misc/dnsmasq.leases

        # Edit dnsmasq.conf
        for i in ${VM_IDS[@]}
        do
            current_MAC="$(awk -F'[=,]' '/^net0/{print $2}' /etc/pve/qemu-server/${i}.conf)"
            current_IP="$(ip r s dev ${vm_NET} | awk -v _id=${i} -F\. '{print $1"."$2"."$3"."_id}')"

            echo "dhcp-host=${current_MAC},${current_IP}" >> /etc/dnsmasq.conf && \
            echo "${current_IP} appended to dnsmasq.conf"
        done
    }

    _start_vms(){
        echo -e "\nStart VMs\n"

        for i in ${VM_IDS[@]}
        do
            qm start ${i} && echo "${i} started"
            sleep 0.5
        done
    }

    mkdir -p /var/lib/vz/images/${vm_ID}
    touch    /tmp/bootstrap.log

    # Check disk
    test -e "/var/lib/vz/images/${vm_ID}/vm-${vm_ID}-disk-0.qcow2"  && \
        { echo -e "\n ${vm_ID} is already exists\n"      && return || exit; }

    # Check VM_ID
    qm list | awk '{print $1}' | grep ${vm_ID}                      && \
        { echo -e "\n ${vm_ID} vmID is already in use\n" && return || exit; }

    clear

    _create_debian_image                && \
    _create_vm                          && \
    _clone_vm                           && \
    _set_static_IP                      && \
     systemctl restart dnsmasq.service  && \
    _start_vms                          && \
    echo -e "\nProcess completed in $((SECONDS/60)) min $((SECONDS%60)) sec\n"
};

_init_deb

 

Yaklaşık 3-4 dk içinde makineler ayağa kalkmış ve SSH ile bağlanılabilir durumda olacaktır.