This gist belongs to the blog post Incus/LXD as an Alternative to Vagrant for DevOps Testing.
Created
March 7, 2025 06:10
-
-
Save cs224/e120e094fc2114d84eb43618262c328c to your computer and use it in GitHub Desktop.
Incus/LXD as an Alternative to Vagrant for DevOps Testing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
config: | |
boot.autostart: "false" | |
# Enable nested containers (needed for Docker-in-LXD). | |
security.nesting: "true" | |
user.user-data: | | |
#cloud-config | |
output: | |
all: '| tee -a /var/log/cloud-init-output.log' | |
apt_update: true | |
apt_upgrade: true | |
packages: | |
- openssh-server | |
- ca-certificates | |
- curl | |
- wget | |
- emacs-nox | |
- wajig | |
- unzip | |
- p7zip-full | |
- make | |
- apt-file | |
- tree | |
users: | |
- name: ubuntu | |
groups: sudo | |
shell: /bin/bash | |
sudo: ALL=(ALL) NOPASSWD:ALL | |
ssh_authorized_keys: | |
- @@SSH_KEY@@ | |
description: "Profile for devops container with cloud-init (script-generated)" | |
devices: {} | |
name: devops-profile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# | |
# incus-profile-install.sh | |
# | |
# Create/update an Incus profile named "devops-profile" using a Cloud-Init template. | |
# | |
# Usage: | |
# ./incus-profile-install.sh [optional-profile-name] | |
# | |
# By default, this script: | |
# - reads SSH key from ~/.ssh/id_rsa.pub | |
# - substitutes it into incus-cloud-init.yaml.in | |
# - applies the result to an Incus profile named "devops-profile" (or $1 if provided) | |
set -eu | |
# 1) Decide the profile name (default: devops-profile) | |
PROFILE_NAME="${1:-devops-profile}" | |
# 2) Where is your SSH key? | |
SSH_KEY_PATH="${HOME}/.ssh/id_rsa.pub" | |
# 3) Template input and final output | |
TEMPLATE_FILE="incus-cloud-init.yaml.in" | |
OUTPUT_FILE="incus-cloud-init.yaml" | |
# --- Check that the SSH key file exists --- | |
if [[ ! -f "${SSH_KEY_PATH}" ]]; then | |
echo "ERROR: SSH key not found at ${SSH_KEY_PATH}" | |
exit 1 | |
fi | |
# --- Check that our template file exists --- | |
if [[ ! -f "${TEMPLATE_FILE}" ]]; then | |
echo "ERROR: Template file ${TEMPLATE_FILE} not found." | |
exit 1 | |
fi | |
# --- Read the public key from file --- | |
SSH_KEY_CONTENT="$(cat "${SSH_KEY_PATH}")" | |
# --- Substitute the placeholder in the template --- | |
# Using '|' as a sed delimiter to avoid issues if the key has slashes | |
sed "s|@@SSH_KEY@@|${SSH_KEY_CONTENT}|g" "${TEMPLATE_FILE}" > "${OUTPUT_FILE}" | |
echo "Generated ${OUTPUT_FILE} with your SSH key." | |
# --- Create or update the Incus profile --- | |
# We can check if the profile exists by trying to show it | |
if incus profile show "${PROFILE_NAME}" >/dev/null 2>&1; then | |
echo "Profile '${PROFILE_NAME}' exists. Updating it..." | |
incus profile edit "${PROFILE_NAME}" < "${OUTPUT_FILE}" | |
else | |
echo "Profile '${PROFILE_NAME}' does not exist. Creating it..." | |
incus profile create "${PROFILE_NAME}" < "${OUTPUT_FILE}" | |
fi | |
echo "Done. Profile '${PROFILE_NAME}' is updated with new Cloud-Init data." |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
config: | |
boot.autostart: "false" | |
# Enable nested containers (needed for Docker-in-LXD). | |
security.nesting: "true" | |
user.user-data: | | |
#cloud-config | |
output: | |
all: '| tee -a /var/log/cloud-init-output.log' | |
apt_update: true | |
apt_upgrade: true | |
packages: | |
- openssh-server | |
- ca-certificates | |
- curl | |
- wget | |
- emacs-nox | |
- wajig | |
- unzip | |
- p7zip-full | |
- make | |
- apt-file | |
- tree | |
# Create an 'ubuntu' user with passwordless sudo & your SSH key | |
users: | |
- name: ubuntu | |
groups: sudo | |
shell: /bin/bash | |
sudo: ALL=(ALL) NOPASSWD:ALL | |
ssh_authorized_keys: | |
- @@SSH_KEY@@ | |
# Additional commands to run after packages are installed | |
runcmd: | |
# 1) Prepare Docker's official apt repo, install Docker CE | |
- | | |
sudo install -m 0755 -d /etc/apt/keyrings | |
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc | |
sudo chmod a+r /etc/apt/keyrings/docker.asc | |
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo \"${UBUNTU_CODENAME:-$VERSION_CODENAME}\") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null | |
sudo apt-get update | |
# Install Docker + plugins | |
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin | |
# Optionally allow 'ubuntu' user to use Docker without sudo: | |
sudo usermod -aG docker ubuntu | |
# 2) Install Kopia | |
- | | |
sudo install -m 0755 -d /etc/apt/keyrings | |
curl -s https://kopia.io/signing-key | gpg --dearmor | sudo tee /etc/apt/keyrings/kopia-keyring.gpg >/dev/null | |
echo "deb [signed-by=/etc/apt/keyrings/kopia-keyring.gpg] http://packages.kopia.io/apt/ stable main" | sudo tee /etc/apt/sources.list.d/kopia.list | |
sudo apt-get update | |
sudo apt-get install -y kopia | |
# 3) Install Rclone (script from rclone.org) | |
- | | |
curl https://rclone.org/install.sh | sudo bash | |
description: "Recovery test profile with Docker, Kopia, Rclone, extra packages" | |
devices: {} | |
name: recovery-test-profile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# | |
# incus-recovery-profile-install.sh | |
# | |
# Creates or updates an Incus profile called "recovery-test-profile" | |
# using a Cloud-Init YAML template that includes Docker/Kopia/Rclone setup. | |
# | |
# Usage: | |
# ./incus-recovery-profile-install.sh [optional-profile-name] | |
# | |
# This script: | |
# - reads SSH key from ~/.ssh/id_rsa.pub | |
# - substitutes @@SSH_KEY@@ in incus-recovery-cloud-init.yaml.in | |
# - applies the result to an Incus profile named "recovery-test-profile" | |
# (or $1 if provided) | |
set -eu | |
# 1) Decide the profile name (default: recovery-test-profile) | |
PROFILE_NAME="${1:-recovery-test-profile}" | |
# 2) Where is your SSH key? | |
SSH_KEY_PATH="${HOME}/.ssh/id_rsa.pub" | |
# 3) Template input and final output | |
TEMPLATE_FILE="incus-recovery-cloud-init.yaml.in" | |
OUTPUT_FILE="incus-recovery-cloud-init.yaml" | |
# --- Check that the SSH key file exists --- | |
if [[ ! -f "${SSH_KEY_PATH}" ]]; then | |
echo "ERROR: SSH key not found at ${SSH_KEY_PATH}" | |
exit 1 | |
fi | |
# --- Check that our template file exists --- | |
if [[ ! -f "${TEMPLATE_FILE}" ]]; then | |
echo "ERROR: Template file ${TEMPLATE_FILE} not found." | |
exit 1 | |
fi | |
# --- Read the public key from file --- | |
SSH_KEY_CONTENT="$(cat "${SSH_KEY_PATH}")" | |
# --- Substitute the placeholder in the template --- | |
# Using '|' as a sed delimiter to avoid issues if the key has slashes | |
sed "s|@@SSH_KEY@@|${SSH_KEY_CONTENT}|g" "${TEMPLATE_FILE}" > "${OUTPUT_FILE}" | |
echo "Generated ${OUTPUT_FILE} with your SSH key." | |
# --- Create or update the Incus profile --- | |
if incus profile show "${PROFILE_NAME}" >/dev/null 2>&1; then | |
echo "Profile '${PROFILE_NAME}' exists. Updating it..." | |
incus profile edit "${PROFILE_NAME}" < "${OUTPUT_FILE}" | |
else | |
echo "Profile '${PROFILE_NAME}' does not exist. Creating it..." | |
incus profile create "${PROFILE_NAME}" < "${OUTPUT_FILE}" | |
fi | |
echo "Done. Profile '${PROFILE_NAME}' is updated with new Cloud-Init data." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment