Back
6 min read

Debian VM on SmartOS hypervisor

This is a second post of the series on minimal Linux VMs deployments on SmartOS hypervisor. Same as in case of Gentoo I decided to go with systemd and btrfs for system & service management and main/only filesystem respectively.

Environment outline

I’m trying to keep things relatively tidy, especially on my production and semi-production boxes. Hence, I have two directories – one for storing ISOs and templates of VMs:

  • /opt/iso
  • /opt/templates

For installation purposes I’m going to use SystemRescueCD as I want to perform installation via debootstrap:

cd /opt/iso
curl -kLO http://downloads.sourceforge.net/project/systemrescuecd/sysresccd-x86/4.3.1/systemrescuecd-x86-4.3.1.iso

Feel free to use any other LiveCD that suits you. grml might be even better choice as it’s Debian-based.
And here’s json template for Debian box:

{
  "autoboot": false,
  "brand": "kvm",
  "ram": "512",
  "vcpus": "4",
  "alias": "12-debian",
  "resolvers": ["8.8.8.8", "8.8.4.4"],
  "nics": [
    {
     "nic_tag": "dmz0",
     "ip": "192.168.0.12",
     "gateway": "192.168.0.1",
     "netmask": "255.255.255.0",
     "allow_ip_spoofing": "1",
     "model": "virtio",
     "primary": true
    },
    {
     "nic_tag": "lan",
     "ip": "10.0.0.12",
     "netmask": "255.255.255.0",
     "model": "virtio"
    }
  ],
  "disks": [
    {
      "boot": true,
      "model": "virtio",
      "size": 10240
    }
  ]
}

You may want to read a bit more about certain parts of configuration provided above in my post about Gentoo.

Generating & booting VM

Once template is prepared, VM generating is fairly easy:

vmadm create < /opt/templates/debian.json
Successfully created VM b0a9eb23-2cae-4d25-bb04-5556825a86c1

Note down or export the UUID as it will come in handy later on:

debian=b0a9eb23-2cae-4d25-bb04-5556825a86c1
echo $debian
b0a9eb23-2cae-4d25-bb04-5556825a86c1

Copy ISO to the root of the newly generated VM:

cp /opt/iso/systemrescuecd-x86-4.3.1.iso /zones/$debian/root/debian.iso

Now it’s time to boot it up with CD as first booting device:

vmadm boot $debian order=cd,once=d cdrom=/debian.iso,ide  

If, like me, you are using ipf as firewall, remember to open VNC port for connection (cause even though SSH is enabled by default in SystemRescueCD, you still need to set password for root account), to open port for SSH for the virtual machine (2222 for example) and to set NAT on that port to point to VM.

Check VNC port vmadm info $debian vnc:

{
  "vnc": {
    "host": "94.23.237.217",
    "port": 61997,
    "display": 56097
  }
}

Now open SSH and VNC in /etc/ipf/ipf.conf:

[...]
# Allow SSH access to Gentoo VM
pass in quick proto tcp from any to any port = 2222 flags S/FSRPAU keep state keep frags  
[...]
# Allow VNC access to Gentoo VM
pass in quick proto tcp from any to any port = 52753 flags S/FSRPAU keep state keep frags  
[...]

Set NAT in /etc/ipf/ipnat.conf:

[...]
# SSH -> Gentoo VM
rdr e1000g0 0.0.0.0/0 port 2222 -> 192.168.0.12 port 22  

Reload rules:

/usr/sbin/ipf -E -Fa -v -f /etc/ipf/ipf.conf
/usr/sbin/ipnat -FC -v -f /etc/ipf/ipnat.conf

Confirm new settings via:

ipfstat -io  
ipnat -l

Launch VNC client, connect to the VM and installation shall begin (:

Debian installation

Remember to connect via VNC client in following manner: <hypervisor-ip>:<VNC port for VM> (where VNC port is the one that was gathered via vmadm info command earlier on). Once connected make sure that both network interfaces are up and running and that at least one can reach outside world.

If both prerequisites are met, it’s time to start SSH and to set password for the root account:

service sshd start  
passwd

Cool, let’s carry on with installation through SSH:

ssh -p 2222 -l root <ip address of a hypervisor>

Keep in mind that 2222 is only an example and you need to set it accordingly in NAT (look up). You may also close the VNC connection and port (unless for any given reason you wish to keep it – it may come in handy when things will go south during SSH connection) right after establishing connectin via SSH.

Partitioning

Determine disk(s) name(s):

lsblk

NAME  MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sr0    11:0    1 389.3M  0 rom  /livemnt/boot
sr1    11:1    1  1024M  0 rom  
vda   252:0    0    10G  0 disk
loop0   7:0    0 275.1M  1 loop /livemnt/squashfs

In my case, I have only one disk called /dev/vda that is 10G big.

parted -a optimal /dev/vda  
mklabel gpt  
unit mib  
mkpart gpt_bios 1 3  
set 1 bios_grub on  
mkpart swap 3 2051  
mkpart btrfs 2051 -1  
q

Above I’m using parted to create gpt partition table. There’s part of the disk for gpt handling (gpt_bios that’s 2M big) with flag for bios_grub, swap partition (2G big) and rest is for btrfs to handle.
And confirm the layout:

parted /dev/vda p
Model: Virtio Block Device (virtblk)
Disk /dev/vda: 10.7GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:

Number  Start   End     Size    File system  Name      Flags
 1      1049kB  3146kB  2097kB               gpt_bios  bios_grub
 2      3146kB  2151MB  2147MB               swap
 3      2151MB  10.7GB  8586MB               btrfs

OK, let’s create and activate swap partition on vda2 and create btrfs file system on vda3:

mkswap /dev/vda2  
swapon /dev/vda2  
mkfs.btrfs /dev/vda3

btrfs subvolumes

OK, swap and btrfs created. Now it’s time to configure subvolumes and mount them properly:

mkdir /mnt/{debian,target}
mount -t btrfs -o rw,noatime,nodiratime,space_cache /dev/vda3 /mnt/target  
cd /mnt/target  
btrfs subvolume create @
btrfs subvolume create @boot
btrfs subvolume create @home  
btrfs subvolume create @var  
btrfs subvolume create @varlog  
mount -t btrfs -o rw,noatime,nodiratime,space_cache,subvol=@ /dev/vda3 /mnt/debian  
mkdir -p /mnt/debian/{boot,home,var}  
mount -t btrfs -o rw,noatime,nodiratime,space_cache,nodev,nosuid,subvol=@home /dev/vda3 /mnt/debian/home  
mount -t btrfs -o rw,noatime,nodiratime,space_cache,nodev,nosuid,noexec,subvol=@boot /dev/vda3 /mnt/debian/boot  
mount -t btrfs -o rw,noatime,nodiratime,space_cache,subvol=@var /dev/vda3 /mnt/debian/var  
mkdir -p /mnt/debian/var/log  
mount -t btrfs -o rw,noatime,nodiratime,nodev,nosuid,noexec,space_cache,subvol=@varlog /dev/vda3 /mnt/debian/var/log

Confirm that all subvolumes have properly set mountpoints:

mount | grep btrfs
/dev/vda3 on /mnt/target type btrfs (rw,noatime,nodiratime,space_cache)
/dev/vda3 on /mnt/debian type btrfs (rw,noatime,nodiratime,space_cache,subvol=@)
/dev/vda3 on /mnt/debian/home type btrfs (rw,noatime,nodiratime,nodev,nosuid,space_cache,subvol=@home)
/dev/vda3 on /mnt/debian/boot type btrfs (rw,noatime,nodiratime,nodev,nosuid,noexec,space_cache,subvol=@boot)
/dev/vda3 on /mnt/debian/var type btrfs (rw,noatime,nodiratime,space_cache,subvol=@var)
/dev/vda3 on /mnt/debian/var/log type btrfs (rw,noatime,nodiratime,nodev,nosuid,noexec,space_cache,subvol=@varlog)

Let’s clean it up:

cd  
umount /mnt/target  
rmdir /mnt/target

I took subvolume naming convention from Ubuntu and ever since I’m using it pretty much everywhere where I’m dealing with btrfs. Feel free to try any other or stick to this one if it appeals to you too.

Debootstrap deployment

Once disks & partitions are dealt with, it’s time for OS deployment:

debootstrap --arch amd64 testing /mnt/debian http://ftp.fr.debian.org/debian/

Right after it finish, environment is ready for configuration.

chroot

To avoid any unpleasant surprises, be sure to mount and bind proc, /sysand /dev:

mount -t proc proc /mnt/debian/proc  
mount --rbind /sys /mnt/debian/sys  
mount --rbind /dev /mnt/debian/dev
LANG=C.UTF-8 chroot /mnt/debian /bin/bash
export TERM=xterm-color

OK, it’s time to configure APT – personally I dislike the default option forcing me to install everything from recommended section of the packge upon installation. Hence:

cat << EOF > /etc/apt/apt.conf.d/02recommends
APT::Install-Recommends "0";
EOF

It’s time to install some vital stuff:

apt-get update
apt-get install btrfs-tools dbus locales openssh-server vim-nox

Quick fix for df/systemd setting:

ln -sf /proc/self/mounts /etc/mtab

Set up locales and timezone:

dpkg-reconfigure locales tzdata

Install kernel:

apt-get install linux-image-amd64

There’s a known bug with 3.13+ kernels and btrfs being default filesystem on a root partition. Here’s a fix:

cat << EOF >> /etc/initramfs-tools/modules
libcrc32c
EOF

Be sure to update initrd:

update-initramfs -u -k all

GRUB installation

apt-get install grub2

And here’s quick config.

cat << EOF > /etc/default/grub
GRUB_DEFAULT=0
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR=`lsb_release -i -s 2&gt; /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="quiet init=/lib/systemd/systemd"
GRUB_CMDLINE_LINUX=""
EOF

Note GRUB_CMDLINE_LINUX_DEFAULT having special init parameter providing path to systemd.
Regenerate config:

update-grub

Deploy filesystem configuration to /etc/fstab:

cat << EOF > /etc/fstab  
/dev/vda3   /       btrfs   rw,noatime,nodiratime,space_cache,subvol=@ 0 1
/dev/vda3   /home   btrfs   rw,nodev,nosuid,noatime,nodiratime,space_cache,subvol=@home 0 1
/dev/vda3   /boot   btrfs   rw,nodev,nosuid,noexec,noatime,nodiratime,space_cache,subvol=@boot 0 1
/dev/vda3   /var    btrfs   rw,noatime,nodiratime,space_cache,subvol=@var 0 1
/dev/vda3   /var/log   btrfs   rw,nodev,nosuid,noexec,noatime,nodiratime,space_cache,subvol=@varlog 0 1
/dev/vda2   none    swap    sw 0 0
EOF

Setting up networking

I could use DHCP to handle networking for me, but that would require additional daemon which I don’t really need. That’s why I decided to stick with static configuration:

cat << EOF > /etc/network/interfaces
auto lo
iface lo inet loopback

allow-hotplug eth0
iface eth0 inet static
        address 192.168.0.12
        netmask 255.255.255.0
        gateway 192.168.0.1
        broadcast 192.168.0.255

allow-hotplug eth1
iface eth1 inet static
        address 10.0.0.12
        netmask 255.255.255.0
EOF

Finishing touches

Before reboot make sure to set password for root account. You may also want to turn on ssh daemon:

passwd
systemctl enable ssh

This is it – exit, unmount & reboot:

exit  
cd  
umount -l /mnt/debian/dev{/shm,/pts,}  
umount -l /mnt/debian{/boot,/proc,}  
reboot

After reboot

Set hostname:

hostnamectl set-hostname debian

Summary

Once everything is done and you are able to connect to your VM, you should have fairly plain system as a starting point. OS is ready to serve its purpose and is ideal for further adjustments and enhancements. Enjoy! (: