vagrant-lxd
This is a Vagrant plugin that adds the ability to manage containers with LXD or Incus.
Features
The following features are currently supported:
- VM management (create, suspend, destroy, etc.)
- IPv4 networking
- Synced folders
- Snapshots (via
vagrant snapshot) - Box Packaging (via
vagrant package)
The following features are not expected to work yet:
- Forwarded ports
- Static IP addresses
- IPv6 networking
Supported Versions
The plugin requires at least the following software versions:
- Vagrant 2.2
- LXD 3.8
- Incus 0.2
Despite its name, this plugin works with Incus as well as LXD. You can
generally replace "LXD" with "Incus" (and lxc with incus) when reading
this documentation and it'll remain correct, although a few important
differences have been noted.
Installation
From Rubygems
You can install the latest version of the plugin directly from
rubygems.org with the vagrant plugin command:
$ vagrant plugin install vagrant-lxd
From Git
Installing from this repository is a three-step process.
Use Bundler to install development dependencies:
$ bundle installBuild the gem:
$ bundle exec rake buildInstall it as a Vagrant plugin:
$ vagrant plugin install pkg/vagrant-lxd-<version>.gem
Usage
Quick Start
First, make sure that you've configured LXD correctly for use with Vagrant.
Once LXD is set up, you can use vagrant up --provider lxd to create
container-backed machines. This plugin reuses the lxc box format, so
VM images from Vagrant Cloud should work without modification:
$ vagrant init --minimal hibox/jammy64
$ vagrant up --provider lxd
Configuration
Below is an example Vagrantfile showing most of the provider's
configurable values, along with their defaults. The hibox/jammy64
box is available on the Vagrant Cloud, so you should be able to copy
this file and adjust it as you see fit.
Vagrant.configure('2') do |config|
config.vm.box = 'hibox/jammy64'
config.vm.provider 'lxd' do |lxd|
lxd.api_endpoint = 'https://127.0.0.1:8443'
lxd.timeout = 10
lxd.name = nil
lxd.nesting = nil
lxd.privileged = nil
lxd.ephemeral = false
lxd.profiles = ['default']
lxd.project = 'default'
lxd.environment = {}
lxd.config = {}
end
end
Client Authentication
The LXD API uses client certificates to authenticate requests.
By default, the plugin will first try to use files from
~/.config/lxc/client.crt and client.key, if they exist. Otherwise,
it will generate a new 4096-bit RSA certificate (and accompanying
private key) in Vagrant's data directory. When using the plugin for the
first time, you will need to add this certificate to server's trust store
by running:
$ lxc config trust add ~/.vagrant.d/data/lxd/client.crt
If you're using Incus, the command is slightly different:
$ incus config trust add-certificate ~/.vagrant.d/data/lxd/client.crt
If you would rather use an existing certificate, you can specify the files for the plugin to use with the following settings:
config.vm.provider 'lxd' do |lxd|
lxd.client_certificate = '/path/to/client.crt'
lxd.client_key = '/path/to/client.key'
end
Synced Folders
In order to use shared folders, you must first add your user ID to the host machine's subuid(5) and subgid(5) files:
$ echo root:$(id -u):1 | sudo tee -a /etc/subuid
$ echo root:$(id -g):1 | sudo tee -a /etc/subgid
For more information about these commands, and user/group ID mapping in general, we recommend this article.
Changing the Guest User ID
When setting up shared folders, this plugin assumes that the UID and GID
of the vagrant user in the guest machine are both 1000. If you're
using a non-standard box where these are different, you can override
the default with the vagrant_uid and vagrant_gid settings.
config.vm.provider 'lxd' do |lxd|
lxd.vagrant_uid = 500
lxd.vagrand_gid = 1000 # defaults to vagrant_uid
end
Disk Device Configuration
Synced folders are mounted as disk devices within the guest. You
can configure them by adding settings to folder's config hash, which
is passed through to LXD. The hash values should all be strings:
config.vm.synced_folder '/foo', '/bar', config: {
readonly: 'true',
recursive: 'false',
}
Shared LXD Containers
It's possible to share a single LXD container between multiple Vagrant VMs by "attaching" them to the container by name.
For example, to associate the "default" VM with a preexisting LXD
container called "my-container", use the vagrant lxd attach command:
$ lxc list -cn # list available containers
+--------------+
| NAME |
+--------------+
| my-container |
+--------------+
$ vagrant lxd detach default # detach from current container, if necessary
==> default: Machine is not attached to a container, skipping...
$ vagrant lxd attach default my-container
==> default: Attaching to container 'my-container'...
Please note that in order for this feature to work you must ensure that Vagrant uses the same SSH key to connect to the machine in all cases. The easiest way to do this is to disable Vagrant's default behaviour of automatically generating a unique key for each machine by adding the following setting in your Vagrantfile:
config.vm.insert_key = false
Refer to Vagrant's documentation for more information about this setting.
Nested Containers
In order to run Linux containers on an LXD-backed machine, it must be
created with the nesting and privileged properties set to true.
These correspond to the security.nesting and security.privileged
configuration items for LXD, respectively. Refer to LXD's instance
options documentation for details.
config.vm.provider 'lxd' do |lxd|
lxd.nesting = true
lxd.privileged = true
end
Note that enabling these options will invalidate any user and group ID mappings you may have configured for synced folders, since privileged containers use the same UID and GID space as the host machine.
Adding Devices
You can attach arbitrary devices to the container with the devices
setting. This should be a map of device names to configuration hashes,
where the hash keys and values are valid device configuration
settings.
For example, the following configuration uses a proxy device to
forward local X11 traffic from the container to the host, allowing you
to run graphical applications transparently from within the guest:
# e.g. vagrant ssh -c 'DISPLAY=:0 firefox'
config.vm.provider 'lxd' do |lxd|
lxd.devices = {
x11: {
type: 'proxy',
mode: '0777',
bind: 'container',
listen: 'unix:/tmp/.X11-unix/X0',
connect: 'unix:/tmp/.X11-unix/X0',
'security.uid': Process.uid.to_s,
'security.gid': Process.gid.to_s,
}
}
end
Note that disk devices should be configured as synced folders rather than ad-hoc devices.
Container Configuration
You can pass custom key/value configuration using the config setting. This
should be a map of instance settings, which will be wired
directly through to the container:
config.vm.provider 'lxd' do |lxd|
lxd.config = {
'linux.kernel_modules': 'ip_tables,ip6_tables,netlink_diag,nf_nat,overlay',
}
end
Not all instance settings make sense in the Vagrant context, and some will or won't work based on your LXD host's configuration, so making sure the config is valid is up to you.
LXD Projects
Since version 3.8, LXD has supported projects as a way to segment an LXD server. Each project has its own set of containers, profiles, images, and so on.
This plugin allows the project for a container to be set on a per-machine
basis. If project is unset, the container will be created in the "default"
project. Different machines in the same Vagrantfile can use different projects:
config.vm.define 'default' do |box|
box.vm.provider 'lxd' do |lxd|
lxd.project = 'default'
end
end
config.vm.define 'custom-project-machine' do |box|
box.vm.provider 'lxd' do |lxd|
lxd.project = 'example'
end
end
Configuring LXD projects is out of scope for this README, but note that each project must include a network device and root disk for this plugin to work correctly. The following commands should get you started with a new project:
lxc project create example
lxc project switch example
lxc profile device add default eth0 nic name=eth0 parent=lxdbr0 nictype=bridged
lxc profile device add default root disk path=/ pool=default
Hacking
To run Vagrant with the plugin automatically loaded, you can use the
bundle exec command:
$ bundle exec vagrant <command>
Contributing
- Fork it from https://gitlab.com/catalyst-it/vagrant-lxd
- Create a feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a Merge Request at https://gitlab.com/catalyst-it/vagrant-lxd/merge_requests