Creating a Multipass instance for use with VSCode
- Multipass has been installed.
- VSCode (Visual Studio Code) has been installed.
- Git has been installed.
- Remote - SSH extension for VSCode has been installed.
- GPG-Indicator extension for VSCode has been installed (if you use GnuPG to sign your commits).
- You know how to use VSCode with a Git provider such Gitlab, GitHub, BitBucket, or SourceHut.
For systems using Oracle VirtualBox as the driver for Multipass
For example because your system does not support Hyper-V (for Windows host), or because you need VirtualBox for other reasons and this conflicts with the default hypervisor.
For Windows systems
PsExecfrom SysInternals installed. This can be installed from the Microsoft Store (https://apps.microsoft.com/store/detail/sysinternals-suite/9P7KNL5RWT25) or via Chocolatey.
Base instance creation
- Create a cloud-init YAML file to provision the instance (e.g.
vscode-dev.yaml) [Note 1].
- Launch Multipass using the
cloud-initYAML file (e.g.
Change to directory containing
Execute the following command:
For Windows, in a PowerShell:
multipass launch -c 4 -d 40G -m 4G -n hugo-dev --cloud-init .\vscode-dev.yaml --timeout 2400 lts
For Linux, in a bash shell:
multipass launch -c 4 -d 40G -m 4G -n hugo-dev --cloud-init ./vscode-dev.yaml --timeout 2400 lts
See [Note 2]
Additional steps when using Oracle VirtualBox as the driver for Multipass on Windows
Change to the location containing the PsExec command (unless you have added it to your path). For example:
Forward a port (in this case
22222) on the local machine to Multipass instance’s SSH
PsExec -s $Env:VBOX_MSI_INSTALL_PATH\VBoxManage.exe controlvm "primary" natpf1 "sshvs,tcp,,22222,,22"
Steps for accessing the Multipass instance from VSCode
From the ‘Command Palette’ (Window: Ctrl+Shift+P), select “Remote-SSH: Connect to Host…” (alternatively use the ‘remote’ icon in the bottom-left corner of the full VSCode window)
Scroll to the bottom of the list, and select “Configure SSH Hosts…”
.ssh/configfile in your home directory (Linux) or your user profile directory (Windows).
Add a section such as:
Host mp-dev Hostname 18.104.22.168 Port 22 User ubuntu IdentityFile ~/.ssh/your-ssh-private-key AddKeysToAgent yes
22.214.171.124is the IP address of the instances (for non-VirtualBox-based Multipass), or
127.0.0.1for VirtualBox-based Multipass AND change
Port 22to the port you used above (
Port 22222in the example above).
Select the host you defined (
mp-devin the example)
Wait while VSCode adds and launches the VS Code server on the remote.
Recommended additional steps
Create a git-backed workspace
- Create a new git repository on your hosting service of choice (e.g. Gitlab, GitHub, BitBucket, SourceHut, etc).
- Clone the project repository into your home directory (e.g.
- In VSCode select
- Create a new folder named
.vscodein the folder created by step
File|Save Workspace As…
- Save the workspace into the
.vscodefolder you created.
Add extensions you wish to use to the remote, where possible
- Add the extensions you want to use locally (see Extension Marketplace).
- For the extensions you want in your remote workspace, on the
‘Install in SSH: mp-dev-workspace
button in theExtensions
sidebar windows (wheremp-dev-workspace` is the name of your actual workspace).
- In addition, for those same extensions, click on the settings icon (gear)
for each extension and select
Add to Workspace Recommendations.
- Select the
mp-dev-workspaceworkspace from the list (for example), and click
- Commit the resulting changes to the
.vscodedirectory and push you new commits to your hosting service.
- Reopen the workspace.
- You extensions should now be present on the remote.
Recommendation for users with multiple devices
For any repositories you wish to include in your workspace, use them as Git submodules. This makes it much easier to sync difference devices (e.g a laptop and a desktop with both your extensions and your code/content).
Since VSCode does not automate the addition and use of submodules, you will need to note the following:
Do not add a repository to the workspace directory by cloning to the workspace directory. Instead use a command such as:
git submodule add --name cool-submodule \ -- https://gitlab.com/useryou/a-cool-submodule.git a-cool-submodule
Make sure you keep your submodules and the base repo commits up to date and pushed to your hosting service so that you can move your work to your other device(s) at any time.
If you clone the workspace repository to a new device using the VSCode GUI, you will so need to do the following:
- Open a terminal in your workspace on the new device
git submodule update --init --recursive -- .
You should now have your full set of code on the new device.
If you clone the repository to a new device using the command line, use:
git clone --recursive …
Outline of contents in sample
cloud-init YAML file
- Packages to add (and related configuration) using
apt: This is arguably the most important part as without it one only gets a bare-bones instance.
- SSH public key for the private key you will use to access the instance. This helps secure your connection and makes it more convenient by using a public/private keypair instead of entering a password for every connection to the remote host.
- Files to add to the instance: This should be kept to a minimum due to size limitations (see [Note 1]). The author uses this for configuration on which he relies.
- Commands to run for additional provisioning:
In the example there are two main sections:
- Copying files from step
3.to their final destination and setting permissions and owner:group correctly. The author uses this order because
write_filescopies the files to the instance before users are created, and most of the files he adds are intended for the default user.
- Adding software for which the default
aptrepositories do not have the desired version (usually
aptis fairly old versions of packages like
Node.js) or for which there is no version in the default
- Copying files from step
Base64 gzipped content
Example Base64 gzipped content
In the example cloud-init YAML file you will notice sections like:
content: | H4sIAAAAAAAAA5WTXU+DMBSG7/srTnAZV9B7TS+WuYgXc2aZ3phlKR9bG+lHaCEas/9uUeaYEJTL vu+Th3OaQnNODSSa+ImGgPuIfgWiIr6oWkEhiF+IVlBx4ksqlY9Q9qZVYeHhebm7vV8TbxKtlgsc ykp4CL1AYMCbNCV2YWiYB1uYTiHsKeAKNowbyBVNDbj0ZPhoyCOOqWG7RAmdZ5Yr2ZINMB0v/EIQ Eq8pLyDQtaheoWMJU7cQ34ObKAVcmgLnKqE5PigccwnbG7AskwjgcbaJSAe4dt66OXoOaS6tPqM9 b2krWuCUWor1u2VK9pp7mH/Jf/bqOlvVKFX4veGA8UyMEvdf6mU7blKpRXDIVfzHuJfY4Ceac/R0 t9rNZ/NoUb9/zJTIcBmX0paYlQcVJDRh2Ql2zGa1JvW/gz4BNjw2aX4DAAA= encoding: gz+b64
Reasons for using Base64 gzipped content
There two main reasons for use Base64 gzipped content in your
- The file you want to include contains binary, or text data that does not
‘play well’ with YAML encoding. For example a
tarfile of a subdirectory.
- To keep the size of the
cloud-initfile smaller. Many cloud providers impose a size limit (e.g. AWS was (is?) 16KB, OVH (OpenStack-based) was (is?) 32KB) on the userdata (cloud-init YAML in this case) one can pass to the instance being created. Using Gzip reduces the size of the file, and using base64 encoding ensures the resulting binary data is not mangled by the YAML parser.
Note: Be very careful not to include private information (‘secrets’) in this file in public repositories, as Base64 is just a different encoding, it is not encryption.
Placeholders in the sample YAML for private data
A final note for the Base64 gzipped content. In some cases the example does not provide actual data because the data would contain private information (‘secrets’) which do not belong in a public repository.
For example there is this placeholder:
Linux: Create file from existing ~/.gnupg with the following command: tar -czf - ~/.gnupg | base64 and copy the output into this content section (with correct indentation) instead of this instructional text.
I recommend copy
vscode-dev-secrets.yaml so that
.gitignore in this repo will prevent storing the version that includes
-c 4you may wish to adjust the 4 (number of CPU cores to give the instance) depending on your hardware.
- Likewise for
3Gmemory size may need to be adjusted for your use case and hardware.
40 Gfor the virtual hard drive may be too large for the storage you have, or too small for your development use case.
- The timeout (
--timeout 2400) means that the instance is allowed to take up to 40 minutes to finish initializing (including
cloud-init). The default is
300(seconds = 5 minutes) which this author finds too short a time when using
cloud-initto provision the instance, on his hardware.