Systemd & LXC Compatibility Rules
Systemd Sandboxing Requirements
Services installed from Debian packages (Netdata, rsyslog, etc.) often ship systemd unit files with sandboxing directives (
LogNamespace,ProtectSystem,ProtectHome,ProtectControlGroups,BindReadOnlyPaths,RuntimeDirectory) that require mount namespace creation.Inside LXC containers, these fail with exit code 226 (NAMESPACE).
Two-Part Fix for Systemd Compatibility
Container feature: ALWAYS add
nesting=1to LXC containers running services with systemd sandboxing. Without it,unshare(CLONE_NEWNS)is forbidden and ANY namespace-requiring directive fails.Systemd drop-in override: Even with
nesting=1, some directives likeLogNamespacestill fail. Deploy a drop-in override in the configure role AND bake it into the image:# /etc/systemd/system/<service>.service.d/lxc-override.conf [Service] LogNamespace= ProtectSystem=false ProtectHome=false ProtectControlGroups=false BindReadOnlyPaths=
Systemd Override Rules
NEVER use empty strings for boolean-like settings (
ProtectSystem=doesn't work). UseProtectSystem=false.For
LogNamespace, empty string IS correct (it means "no namespace").ALWAYS bake the override into the image via
build-images.sh. The configure role MUST NOT deploy it — the override is base system config, not host-specific topology.Previous bug: Netdata service exited 226/NAMESPACE in a privileged LXC container. Root cause:
LogNamespace=netdatain the Netdata systemd unit created a journal namespace, which requiresCLONE_NEWNSforbidden inside LXC even withnesting=1.
Host Metrics via Bind Mounts
Monitoring agents (Netdata) that read host CPU, memory, disk, and temperature need access to the HOST's
/procand/sys, not the container's.Requirements:
- Privileged container (
lxc_ct_unprivileged: false). Unprivileged containers use UID mapping that prevents reading host procfs files. - Nesting feature (
features: nesting=1). Required for systemd sandboxing. - Bind mount entries: Pass full Proxmox mount specs to
proxmox_lxc:lxc_ct_mount_entries: - "/proc,mp=/host/proc,ro=1" - "/sys,mp=/host/sys,ro=1" - Image config: Bake
/host/procand/host/syspaths into the monitoring agent's config during image build.
- Privileged container (
Per-Feature Scenario Requirements
Per-feature Molecule scenarios MUST include all groups that affect the role's branching logic. The role's
when:conditions check group membership — if a group is missing, the wrong branch executes.Previous bug: rsyslog-lxc scenario had
homeinmonitoring_nodesonly. The LAN/WAN detection checkedrouter_nodesmembership, found it missing, took the WAN path, and failed becauseansible_default_ipv4was undefined.Fix: add
router_nodesto the per-feature scenario's platform groups for hosts that need the LAN path.
LXC Package Management
ALWAYS use
install_recommends: falsewhen installing packages in LXC containers. Many packages Recommend kernel-related metapackages that pull in 70+ MB kernel images, filling the small LXC disk.Broken apt in an LXC container means the baseline is wrong. The fix belongs in
proxmox_lxc(shared provisioning), NOT in individual configure roles.Previous bug:
wireguard-toolsRecommendswireguardmetapackage which depends onlinux-image-rt-amd64. Withoutinstall_recommends: false, apt pulled in a 70MB kernel image that filled the 1GB container disk (No space left on device).
IP Query Pattern for Multi-Node Services
- Pattern for querying actual IP in verify tasks:
- name: Get container IP from Proxmox config
ansible.builtin.shell:
cmd: |
set -o pipefail
pct config {{ ct_id }} | grep -oP 'ip=\K[^/,]+'
executable: /bin/bash
register: _ct_ip_query
changed_when: false
- Verify tasks MUST query the actual container IP from
pct configinstead of recomputing it. This avoids index drift between scenarios.