Doc suggestion: How to use custom blueprints

Hey all,
I would appreciate your feedback on the document below, as well as any tips you might have!
Thanks :black_cat:


See also: Blueprint

This document explains how to create and use custom blueprints. With this approach, users can control the initialisation process to run Multipass instances for their needs.
The result should enable the user to spin up various instances with different toolsets.

Step 1: Create a minimal viable blueprint

The first step is to create a local catalogue of blueprints.

mkdir ~/blueprints
touch ~/blueprints/custom.yaml

Edit custom.yaml with the following content:

description: My custom VM configuration
version: latest
runs-on: 
  - amd64

instances:
  custom:
    image: 22.04
    limits:
      min-cpu: 4
      min-mem: 4G
      min-disk: 20G
    timeout: 1800
    cloud-init:
      vendor-data: |
        package_update: true

To use this new blueprint, run:

multipass launch file://blueprints/custom.yaml  # only from ~ 

This command will create an instance named custom based on Ubuntu 22.04 LTS, with 4 CPU cores, 4 GB of memory and 20 GB of disk space.

See more: multipass launch

Step 2: Define the toolset to use

In this part, we will create a blueprint with a Python development toolset. We will need:

  • git
  • pyenv for managing Python versions
  • pipx for managing Python-related tools

First, either rename custom.yaml to python.yaml or create a new file with the previous content. Then, add the following content to the vendor-data section:

# previous content
    cloud-init:
	  vendor-data: |
	    package_update: true

		packages:
		- build-essential
        - libssl-dev
        - zlib1g-dev
        - libbz2-dev
        - libreadline-dev
        - libsqlite3-dev
        - curl
        - libncursesw5-dev
        - xz-utils
        - tk-dev
        - libxml2-dev
        - libxmlsec1-dev
        - libffi-dev
        - liblzma-dev
        - git
        - pipx

		runcmd:
		- |
          sudo -u ubuntu bash -c "$(curl -fsSL https://pyenv.run)"
          sudo -u ubuntu /home/ubuntu/.pyenv/bin/pyenv init 2>> /home/ubuntu/.bashrc
          sudo -u ubuntu /home/ubuntu/.pyenv/bin/pyenv install 3.10.13
          sudo -u ubuntu echo 3.10.13 > /home/ubuntu/.pyenv/version
          sudo -u ubuntu pipx ensurepath
          sudo -u ubuntu pipx install black
          sudo -u ubuntu pipx install tox
          sudo -u ubuntu pipx install ruff
          sudo -u ubuntu pipx install pyright


This packages list comes from pyenv’s recommended build environment.
The runcmd subsection accomplishes the following:

  • installing pyenv, adding it to the PATH and making Python 3.10.13 the default version
  • using pipx to install several quality of code tools in their own environment

Let’s inspect this blueprint to validate that we got everything we planned.

multipass launch file://blueprints/python.yaml
multipass shell python
python -V

    Python 3.10.13

pipx list

venvs are in /home/ubuntu/.local/pipx/venvs
apps are exposed on your $PATH at /home/ubuntu/.local/bin
   package black 24.2.0, installed using Python 3.10.12
    - black
    - blackd
   package pyright 1.1.351, installed using Python 3.10.12
    - pyright
    - pyright-langserver
    - pyright-python
    - pyright-python-langserver
   package ruff 0.2.2, installed using Python 3.10.12
    - ruff
   package tox 4.13.0, installed using Python 3.10.12
    - tox

We might want to automate some checks by adding a health-check section to python.yaml.

# previous content
    cloud-init:
	  vendor-data: |
		  # ...
	  health-check: |
		  set -e
		  python -V
		  pipx list

Step 3: Improve user experience

This configuration works as expected, but there is room for improvement. First, we will automate mounting a directory to exchange files between the host and the guest VM.

Add workspace: true to the python section in the python.yaml file:

description: My custom Python VM configuration
version: latest
runs-on: 
  - amd64

instances:
  python:
    image: 22.04
    workspace: true
    limits:
      min-cpu: 4
      min-mem: 4G
      min-disk: 20G
     # ...

A ~/multipass/python folder will be created on the host and mounted in the VM upon instantiation.

One limit of our blueprint is that it will use the same default name for all instances, which is not allowed by Multipass. Using the full path to the blueprint is cumbersome as well. We can address both issues by creating a new shell alias.

alias vm_py="multipass launch file:///home/user/blueprints/python.yaml -n"

Using vm_py now requires a distinct name for the new VM, and can still accept other multipass launch parameters.

Conclusion

You have now created a personal catalogue of custom blueprints. They are available as easily as vm_py, vm_rust, etc. as long as the proper aliases are created. Further refinements could be made: how about replacing the alias by a bash function that instantiates the VM, then transfers files over to the VM (think dot files, vim configuration, not-sensitive credentials)?

Hi @abatisse!

We’re really sorry to not have replied to you sooner. This fell through the cracks :slightly_frowning_face:

I think this how-to is good, but I’m reluctant to publish it to our docs website. The reason is twofold. First, these custom Blueprints only work on Linux at this time and putting up something like this that excludes our macOS and Windows users may cause confusion. Second, the whole Blueprints ecosystem is still in a state of flux and so I want to be very measured on how we communicate Blueprints. Right now, the docs only describe launching Blueprints in general and also has a page that goes a little more in-depth for the Docker Blueprint.

I think for now, we can leave this post in the Multipass discourse, but we are going to refrain from adding it to docs website. I hope you understand and we do appreciate you contribution for sure!