Skip to content

Instantly share code, notes, and snippets.

@danofsteel32
Last active September 21, 2025 14:26
Show Gist options
  • Select an option

  • Save danofsteel32/1b2ad176cab52b518f71c9cad0bfac8c to your computer and use it in GitHub Desktop.

Select an option

Save danofsteel32/1b2ad176cab52b518f71c9cad0bfac8c to your computer and use it in GitHub Desktop.
Helper script for creating Incus containers that can be used for Ansible development.
#!/usr/bin/env bash
# MIT License
# Copyright (c) 2025 Dan Davis
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# For all available distros see https://images.linuxcontainers.org/
DISTRO="${DISTRO:-almalinux}"
RELEASE="${RELEASE:-8}"
CONTAINER_NAME="${CONTAINER_NAME:-$DISTRO$RELEASE}"
# TODO: allow specifying a username instead of hardcoded 'deploy' user
# Create an almalinux8 container
incus launch images:"${DISTRO}/${RELEASE}" "${CONTAINER_NAME}"
sleep 4
# Create a user to run the playbook
incus exec "${CONTAINER_NAME}" -- adduser -ms /bin/bash deploy
# Install minimum packages needed to run ansible playbooks
incus exec "${CONTAINER_NAME}" -- dnf install openssh-server sudo python3 firewalld -y
sleep 1
# Setup deploy user to run sudo w/o password
incus exec "${CONTAINER_NAME}" -- sh -c "echo 'deploy ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/deploy-user"
incus exec "${CONTAINER_NAME}" -- chmod 0440 /etc/sudoers.d/deploy-user
# Enable + start the sshd service
incus exec "${CONTAINER_NAME}" -- systemctl enable --now sshd.service
# Workaround for bugged nftables on almalinux 8
# without this, running firewall-cmd --reload will fail because of an exception in python-nftables
if [[ "$DISTRO" == "almalinux" ]] && [[ "$RELEASE" == "8" ]]; then
incus exec "${CONTAINER_NAME}" -- sed -i 's/FirewallBackend=nftables/FirewallBackend=iptables/' /etc/firewalld/firewalld.conf
fi
# Enable + start the firewalld service
incus exec "${CONTAINER_NAME}" -- systemctl enable --now firewalld.service
# Create ssh key pair for deploy user
ssh-keygen -t rsa -b 2048 -N "" -q -f ./deploy-key
# Make sure .ssh dir exists
incus exec "${CONTAINER_NAME}" -- mkdir -p /home/deploy/.ssh
# Copy pub key to container
incus file push ./deploy-key.pub "${CONTAINER_NAME}/home/deploy/.ssh/authorized_keys"
# Fix permissions on .ssh dir
incus exec "${CONTAINER_NAME}" -- chown -R deploy:deploy /home/deploy/.ssh
incus exec "${CONTAINER_NAME}" -- chmod 0700 /home/deploy/.ssh
incus exec "${CONTAINER_NAME}" -- chmod 0600 /home/deploy/.ssh/authorized_keys
# Create a snapshot of the system in pristine condition
incus snapshot create "${CONTAINER_NAME}" clean
ip=$(incus list | grep "${CONTAINER_NAME}" | awk '{print $6}')
echo ""
echo "Setup complete! Here is how to ssh and run ansible playbooks:"
echo ""
echo " ssh -i ./deploy-key deploy@${ip}"
echo " ansible-playbook -u deploy -i ${ip}, --key-file ./deploy-key playbook.yaml"
echo ""
echo "If you bork something you can restore to a clean slate by running:"
echo ""
echo " incus snapshot restore ${CONTAINER_NAME} clean"
echo ""
echo "To delete the container run:"
echo ""
echo " incus delete ${CONTAINER_NAME} --force"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment