I stumbled upon a great project from Canonical called Multipass which allows you to run lightweight virtual machines on your laptop/workstation and it's super fast!
It's using the native hypervisors of all supported platforms, so you can run Multipass on Mac, Linux and Windows.
I've found Multipass super helpful with development work, running a mini local cloud, running proof of concepts, and the best of all is that I don't have to spend money as it's all running on your workstation.
What we will be doing
In this tutorial we will be doing the following:
- Install Multipass on Mac
- Setup our
cloud-init.yaml
that we will use to bootstrap our VM - Overview of Mutlipass commands
- Exec into our VM and look at the outputs of our bootstrap
- Using the Multipass CLI for scripting from our host
Install Multipass
I will be installing Multipass for Mac, but if you are looking to install on Linux or Windows, you can have a look at this document
$ brew cask install multipass
Verify that our installation succeeded:
$ multipass version
multipass 1.0.0+mac
Preparing the bootstrap process
The awesome thing about multipass is that we can use cloud-init to streamline our bootstrap process.
First create a ssh key:
$ ssh-keygen -b 2048 -f ~/.ssh/multipass -t rsa -q -N ""
Create the cloud-init file that we will be using:
$ touch ./cloud-init.yaml
We need to provide the ssh public key to our cloud-init file in order for us to ssh to our multipass vm with our ssh private key.
$ cat ~/.ssh/multipass.pub
ssh-rsa AAAAB3.......hh32R [ruan@mbp]
Copy the contents of your public key and add the full content to your cloud-init file:
$ cat ./cloud-init.yaml
#cloud-config
ssh_authorized_keys:
- ssh-rsa AAAAB3.......hh32R ruan@mbp
Next we want our bootstrap process to update our package repositories and install 2 packages:
$ cat ./cloud-init.yaml
...
package_update: true
packages:
- curl
- jq
I will also provide an example on how to write content to a file, bootcmd and rundcmd.
Bootcmd will happen early in the bootprocess and runcmd will run after. So when you will be running commands such as installing packages for example you will be using runcmd:
$ cat ./cloud-init.yaml
...
write_files:
- content: |-
my dummy content
owner: ubuntu:ubuntu
path: /home/ubuntu/file.txt
permissions: '0644'
bootcmd:
- echo $(whoami) > /root/boot.txt
runcmd:
- cp /root/boot.txt /home/ubuntu/boot_moved.txt
- chown ubuntu:ubuntu /home/ubuntu/boot_moved.txt
- curl -s http://dummy.restapiexample.com/api/v1/employees | jq '.data[] | select(.id == "1") | .employee_name' > /home/ubuntu/api_output.txt
The full content of our cloud-init.yaml will be as follows:
#cloud-config
ssh_authorized_keys:
- ssh-rsa ssh-rsa AAAAB3.......hh32R ruan@mbp
package_update: true
packages:
- curl
- jq
write_files:
- content: |-
my dummy content
owner: ubuntu:ubuntu
path: /home/ubuntu/file.txt
permissions: '0644'
bootcmd:
- echo $(whoami) > /root/boot.txt
runcmd:
- cp /root/boot.txt /home/ubuntu/boot_moved.txt
- chown ubuntu:ubuntu /home/ubuntu/boot_moved.txt
- curl -s http://dummy.restapiexample.com/api/v1/employees | jq '.data[] | select(.id == "1") | .employee_name' > /home/ubuntu/api_output.txt
In summary the VM will boot, the ssh configuration will be updated to allow us to use our private ssh key to ssh.
Update our package repository, install curl and jq.
Write contents to a file located at /home/ubuntu/file.txt
, write the output of the command whoami to /root/boot.txt
, then copies the boot file to /home/ubuntu/boot_moved.txt
, updates the permissions for the ubuntu user
Then run's a curl command to a API endpoint and redirects the output to /home/ubuntu/api_output.txt
Boot your VM with Multipass
I will be using Ubuntu Bionic image for my VM, if you are looking for something else, you can find other images by doing:
$ multipass find
Image Aliases Version Description
snapcraft:core core16 20200221 Snapcraft builder for Core 16
snapcraft:core18 20200221 Snapcraft builder for Core 18
16.04 xenial 20200218.1 Ubuntu 16.04 LTS
18.04 bionic,lts 20200218 Ubuntu 18.04 LTS
I will be creating a VM with 1 CPU, 512MB of Memory and a Disk on 1GB. You do not have to specify the values if you want the defaults:
$ multipass launch bionic \
--name multipass-demo \
--cpus 1 \
--mem 512m \
--disk 1G \
--cloud-init ./cloud-init.yaml
Launched: multipass-demo
Overview of your VM
Let's have a look at our running multipass VMs:
$ multipass list
Name State IPv4 Image
multipass-demo Running 192.168.64.8 Ubuntu 18.04 LTS
To get information about your VMs load, disk usage memory and IP address:
$ multipass info multipass-demo
Name: multipass-demo
State: Running
IPv4: 192.168.64.8
Release: Ubuntu 18.04.4 LTS
Image hash: 3c3a67a14257 (Ubuntu 18.04 LTS)
Load: 0.24 0.23 0.09
Disk usage: 1.1G out of 2.0G
Memory usage: 71.4M out of 481.7M
We can also run commands from the host on the VM:
$ multipass exec multipass-demo -- df -h /
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 2.0G 1.2G 842M 58% /
Access your Multipass VM
You can access your VM by using exec or ssh, to exec into your VM:
$ multipass exec multipass-demo -- /bin/bash
[multipass-demo]:~$
To SSH into your VM, get the IP address:
$ multipass info multipass-demo | grep 'IPv4'
IPv4: 192.168.64.8
Then use your private key to SSH to your VM:
$ ssh -i ~/.ssh/multipass [email protected]
[ubuntu@multipass-demo]:~$
Once you are logged in, have a look at the content that was published by our commands from the cloud-init:
$ cat file.txt
my dummy content
$ cat boot_moved.txt
root
$ cat api_output.txt
"Tiger Nixon"
Scripting with Multipass
We will assign 3 variables, host's hostname, VM hostname and VM IP:
$ MY_HOSTNAME=$(hostname)
$ MULTIPASS_VM_HOSTNAME=$(multipass exec multipass-demo -- cat /etc/hostname)
$ MULTIPASS_VM_IP=$(multipass info multipass-demo | grep 'IPv4' | awk '{print $2}')
See if you can access those environment variables:
$ echo $MY_HOSTNAME
Ruan-MPB
$ echo $MULTIPASS_VM_HOSTNAME
multipass-demo
$ echo $MULTIPASS_VM_IP
192.168.64.8
Run a basic script to write a file with the environment variables content to the VM:
$ multipass exec multipass-demo -- bash -c "echo -e \"- Hostname: ${MY_HOSTNAME} \n\- VM Hostname: ${MULTIPASS_VM_HOSTNAME} \n- VM IP: ${MULTIPASS_VM_IP}\" > /tmp/output.txt"
Read the file that we created:
$ multipass exec multipass-demo -- cat /tmp/output.txt
- Hostname: Ruan-MPB
- VM Hostname: multipass-demo
- VM IP: 192.168.64.8
Delete the VM
To delete the VM:
$ multipass stop multipass-demo
$ multipass delete multipass-demo
$ multipass purge
Thank You
Hope you found this useful, I really enjoy Multipass and helped me a lot to do proof of concepts and development work, where I did not have to spend money on cloud instances.
Comments