LXD
Differences Between Docker and Linux Containers
Docker and Linux Containers (such as LXC) both use the same underlying Linux technologies i.e., chroot, cgroups, namespaces, etc. They differ in purpose: Docker focuses on lightweight application containers (typically for microservices), while Linux Containers is intended for full operating system containers.
Docker containers usually run a single process. In contrast, LXC containers behave more like virtual machines, offering a full OS environment.
Originally, Docker used LXC under the hood, but starting with version 0.9, it introduced its own runtime: libcontainer.
Docker emphasized application packaging, automation, and portability: leveraging Dockerfiles, layered filesystems, and compliance with the OCI standard. LXC, on the other hand, targets full system environments.
Linuxcontainers.org project provides LXD, a powerful tool for managing both Linux Containers and virtual machines, offering a CLI experience similar to Docker.
Personally, I prefer LXD for creating virtual machines in development due to its flexibility and Docker-like interface.
Commands
Below we will discuss commands for managing VMs. Same commands will apply for Linux Containers.
Initialization
Initialize LXD for first time use:
lxd init
Images & Remote Image Servers
List remote repository/servers available to pull images.
lxc remote list
List images from a particular remote repository
lxc image list REPOSITORY_NAME:
Search images using keyword MATCH from a remote repository
lxc image list REPOSITORY_NAME: MATCH
# lxc image list ubuntu-minimal:noble
Copy an image from remote repository.
lxc image copy REPOSITORY_NAME:IMAGE_ALIAS_OR_FINGERPRINT local: --alias ubuntu-focal
# lxc image copy ubuntu-minimal:52dd513b467a local: --alias ubuntu24
# lxc image copy ubuntu-minimal:ec0518e181c5 local: --alias ubuntu22
Now, List images locally
lxc image list
Delete a local image:
lxc image delete IMAGE_ALIAS_OR_FINGERPRINT
(Also checkout lxc image export and lxc image import)
Container & VM Management
List all containers/virtual machine
lxc list
Launch/run a virtual machine (use virtual machine image type)
lxc launch REPOSITORY_NAME:IMAGE_NAME VM_NAME
# lxc launch ubuntu24 myvm
Open shell in a virtual machine
lxc exec VM_NAME /bin/bash
# lxc exec myvm /bin/bash
Open console in a virtual machine
lxc console VM_NAME
Stop a virtual machine
lxc stop VM_NAME
Start a virtual machine
lxc start VM_NAME
Restart a virtual machine
lxc restart VM_NAME
Delete a virtual machine
lxc stop VM_NAME
lxc delete VM_NAME
Copy an instance to create a new instance.
lxc copy VM_NAME NEW_CONTAINER_COPY_NAME
Migrate or move an instance to different name/location
lxc move VM_NAME NEW_NAME
lxc move VM_NAME HOST:NEW_NAME
Configure VM/Containers
Set limit for memory of a container/virtual machine
lxc config set VM_NAME limits.memory 1GB
Set limit for cpu for a container/virtual machine
lxc config set VM_NAME limits.cpu 2
Set CPU Pinning for a container/virtual machine
lxc config set VM_NAME limits.cpu 2,3-5
Show all config for a container/virtual machine
lxc config show VM_NAME
Edit config for a container/virtual machine
lxc config edit VM_NAME
List devices attached to a container:
lxc config device list CONTAINER_NAME
Remove a device:
lxc config device remove CONTAINER_NAME DEVICE_NAME
Profiles
A profile contains config, storage volumes, network interfaces details. They are templates to spin-up new instances. They are alternative to manually modifing config for each instance. List profiles
lxc profile list
Get details of a profile
lxc profile show PROFILE_NAME
Copy a profile
lxc profile copy PROFILE_NAME NEW_PROFILE_NAME
Use profile to launch an instance launch/run a container/virtal machine
lxc launch REPOSITORY_NAME:IMAGE_NAME CONTAINER_NAME --profile PROFILE_NAME
Edit a profile
lxc profile edit PROFILE_NAME
Copying Files with Host
COPY a file from host to instance
lxc file push /path/to/file CONTAINER_NAME/target/path/for/file
COPY a file from instance to host
lxc file pull CONTAINER_NAME/path/to/file /new/path/on/host
Mount a directory from host to instance
lxc config device add CONTAINER_NAME NEW_DEVICE_NAME disk source=PATH_ON_HOST(/home/ubuntu) path=TARGET_PATH_IN_CONTAINER
LXD inside LXD
For running lxd inside lxd, make sure following settings are configured to the parent lxd instance
lxc config set CONTAINER security.priviledged true
lxc config set CONTAINER security.nesting true
Snapshots
Create a snapshot of a container
lxc snapshot CONTAINER_NAME NAME
Get details/status of a container; this also shows all snapshots that container has.
lxc info CONTAINER_NAME
Delete a snapshot of a container
lxc delete CONTAINER_NAME/SNAPSHOT_NAME
Restore a snapshot, i.e. rollback container to previous state
lxc restore CONTAINER_NAME SNAPSHOT_NAME
Network Management
List Networks
lxc network list
Show network details
lxc network show NETWORK_NAME
Create a new bridge network
lxc network create lxdbr1
Attach container/virtual machine to a network
lxc network attach NETWORK_NAME CONTAINER_NAME
Attach container/virtual machine from a network
lxc network detach NETWORK_NAME CONTAINER_NAME
DNS to ping between containers/virtual machines. Service discovery similar to docker and k8s:
lxc exec CONTAINER_1 -- ping CONTAINER_2_NAME.lxd
Storage Management
List storage pools:
lxc storage list
Show details of a storage pool:
lxc storage show POOL_NAME
Create a new storage pool:
lxc storage create POOL_NAME zfs size=10GB
Delete a storage pool:
lxc storage delete POOL_NAME
Cloud-init
Launch container/virtual machine with cloud-init
lxc launch IMAGE_NAME VM_NAME --config=user.user-data="$(cat my-cloud-init-data.yaml)"
Next, Verify cloud-init:
lxc exec VM_NAME bash
# 1. Check cloud-init status
$ cloud-init status --wait
# 2. Fetch cloud-init data
$ cloud-init query userdata
# 3. Validate cloud-init schema
$ cloud-init schema --system --annotate
# 4. Verify changes were applied