This is how I prepare a template to run Docker. It includes persistence for configuration and volumes and images for /etc/docker/
, /var/lib/containerd/
and /var/lib/docker/
using bind-dirs on the /rw
volume, and integrates with the way Qubes does services, i.e. Docker service will start only if it’s listed in the AppVM settings. Since I do it on a dedicated template I guess this part is optional, but why not
I have it in /srv/user_salt/templates/docker.sls
and apply to a dedicated template to not mix Docker (and the extra software you’ll see) with my “daily” template, and apply it with
sudo qubesctl --show-output --skip-dom0 --targets=fedora-41-docker state.apply templates.docker saltenv=user
# cat /srv/user_salt/templates/docker.sls
# -*- coding: utf-8 -*-
# vim: set syntax=yaml ts=2 sw=2 sts=2 et :
{% set gui_user = salt['cmd.shell']('groupmems -l -g qubes') %}
hashicorp stable repo:
pkgrepo.managed:
- name: hashicorp
- enabled: True
- humanname: "Hashicorp Stable - $basearch"
- baseurl: "https://rpm.releases.hashicorp.com/fedora/$releasever/$basearch/stable"
- gpgcheck: 1
- gpgkey: https://rpm.releases.hashicorp.com/gpg
- require_in:
- pkg: install work packages
{% for type in ['stable', 'test', 'nightly'] %}
docker {{ type }} repo:
pkgrepo.managed:
- name: "docker-ce-{{ type }}"
- humanname: "Docker CE {{ type | capitalize }} - $basearch"
- enabled: {{ type == 'stable' }}
- baseurl: "https://download.docker.com/linux/fedora/$releasever/$basearch/{{ type }}"
- gpgcheck: 1
- gpgkey: https://download.docker.com/linux/fedora/gpg
- require_in:
- pkg: install work packages
{% for component in ['debuginfo', 'source'] %}
docker {{ type }} {{ component}} repo:
pkgrepo.managed:
- name: "docker-ce-{{ type }}-{{ component }}"
- humanname: "Docker CE {{ type | capitalize }} - {{ component | capitalize }}{% if component == 'debuginfo' %} $basearch{% endif %}"
- enabled: False
- baseurl: "https://download.docker.com/linux/fedora/$releasever/{{ component }}{% if component == 'debuginfo' %}-$basearch{% endif %}/{{ type }}"
- gpgcheck: 1
- gpgkey: https://download.docker.com/linux/fedora/gpg
- require_in:
- pkg: install work packages
{% endfor %}
{% endfor %}
hashicorp test repo:
pkgrepo.managed:
- name: hashicorp-test
- enabled: False
- humanname: "Hashicorp Test - $basearch"
- baseurl: "https://rpm.releases.hashicorp.com/fedora/$releasever/$basearch/test"
- gpgcheck: 1
- gpgkey: https://rpm.releases.hashicorp.com/gpg
- require_in:
- pkg: install work packages
install work packages:
pkg.installed:
- pkgs:
- ansible
- python3-ara
- vault
- docker-ce
- docker-ce-cli
- containerd.io
- docker-compose-plugin
- pkg_verify: True
prepare docker for use:
file.managed:
- name: /etc/qubes-bind-dirs.d/35_containers.conf
- makedirs: True
- contents:
- "binds+=( '/var/lib/containerd/' )"
- "binds+=( '/var/lib/docker/' )"
- "binds+=( '/etc/docker/' )"
- require:
- pkg: install work packages
service.enabled:
- name: docker.socket
- require:
- pkg: install work packages
group.present:
- name: docker
- addusers:
- user
- require:
- pkg: install work packages
{% for service in ['socket', 'service'] %}
allow docker {{ service }} to be started by qubes settings:
file.managed:
- name: /etc/systemd/system/docker.{{ service }}.d/30_qubes.conf
- makedirs: True
- contents:
- "[Unit]"
- "ConditionPathExists=/var/run/qubes-service/docker"
- user: root
- group: root
- mode: 0644
- require:
- pkg: install work packages
- file: prepare docker for use
{% endfor %}