How to Install Debian/Ubuntu Packages Without Starting Services in Chroot Environments


2 views

When managing LXC container templates, installing packages in chroot environments creates an annoying issue - services automatically start during installation. This results in multiple duplicate service instances running on the host system, as recently happened when I needed to install rsyslog across several templates:

for template in /var/lib/libvirt/filesystems/{debian,ubuntu}*_template; do
    chroot $template apt-get install rsyslog
done

While Debian policy suggests services shouldn't start in chroot environments, in practice many packages still launch their services during installation. The issue stems from maintainer scripts (postinst) that don't properly check for chroot environments before starting services.

Here are several effective approaches to prevent service startup during package installation:

# Method 1: Using policy-rc.d
cat < /path/to/chroot/usr/sbin/policy-rc.d
#!/bin/sh
exit 101
EOF
chmod +x /path/to/chroot/usr/sbin/policy-rc.d

The second method uses environment variables:

# Method 2: Environment variable approach
chroot $template /bin/bash -c "export RUNLEVEL=1; apt-get -y install package-name"

For more complex scenarios, consider mounting a custom policy-rc.d:

# Method 3: Temporary mount solution
mount --bind /path/to/custom/policy-rc.d $template/usr/sbin/policy-rc.d
chroot $template apt-get install package
umount $template/usr/sbin/policy-rc.d

Some packages require special handling. For example, with exim4:

debconf-set-selections <<< "exim4-config exim4/dc_eximconfig_configtype select local"
chroot $template apt-get -o Dpkg::Options::="--force-confold" install exim4

For systems using systemd, additional precautions are needed:

# Prevent systemd units from starting
ln -s /dev/null $template/etc/systemd/system/package.service
chroot $template systemctl daemon-reload

When building LXC container templates on Debian/Ubuntu systems, a common pain point emerges: package installations automatically start associated services, even in chroot environments. This creates multiple running instances of services like rsyslog or exim4 when you're just trying to prepare container templates.

The default package installation process in Debian-based systems follows this sequence:

1. Package files are extracted
2. Pre-installation scripts run
3. Main package files installed
4. Post-installation scripts run (often including service activation)
5. Service gets enabled in default runlevel

Method 1: Using policy-rc.d

The cleanest approach is creating a /usr/sbin/policy-rc.d script in your chroot environment before installation:

#!/bin/sh
exit 101

Then make it executable:

chmod +x /usr/sbin/policy-rc.d

Method 2: APT Configuration Approach

Create or modify /etc/apt/apt.conf.d/ with:

DPkg::Pre-Invoke {"if [ -x /usr/sbin/policy-rc.d ]; then /usr/sbin/policy-rc.d || true; fi";};
DPkg::Post-Invoke {"if [ -x /usr/sbin/policy-rc.d ]; then /usr/sbin/policy-rc.d || true; fi";};

Method 3: Package-Specific Solutions

Some packages respect environment variables:

DEBIAN_FRONTEND=noninteractive \\
NEEDRESTART_MODE=a \\
apt-get install -y --no-install-recommends rsyslog

For your LXC template scenario, here's a complete solution:

for template in /var/lib/libvirt/filesystems/{debian,ubuntu}*_template; do
    # Create policy-rc.d
    echo -e '#!/bin/sh\nexit 101' > $template/usr/sbin/policy-rc.d
    chmod +x $template/usr/sbin/policy-rc.d
    
    # Install package with prevention measures
    chroot $template env DEBIAN_FRONTEND=noninteractive \\
        apt-get install -y --no-install-recommends rsyslog
    
    # Cleanup (optional)
    rm $template/usr/sbin/policy-rc.d
done

After installation, verify no services are running:

ps aux | grep rsyslog
service --status-all

If services still start, check for:

  • Missing policy-rc.d executable permissions
  • Package-specific init systems (systemd units might bypass traditional methods)
  • Incorrect chroot environment setup