When using a Continuous Integration workflow using Docker there is often the need to automatically install packages. On Debian and its derivatives like Ubuntu this is usually done using the apt command. Unfortunately that command is meant to be used interactively by the user behind the keyboard. Hopefully this is not the case in a CI workflow. If you try to use this command in a script it will print a warning that this is not supported.

To fix this issue we have to use the slightly lower level apt-get utility. In contrast to the apt utility, apt-get supports being used from the command line.

Updating the Package Repositories

Our first hurdle is updating the package repositories. Where we normally would use apt update we instead use apt-get update. This will still result in a lot of output we don't care about. To fix this we can use the --quiet=<level> option. This results in the following command: apt-get update --quiet=2.

Installing the Package

Instead of the usual apt install <package> we have to start with apt-get install <package>. This still won't install the package if there is not user present as it will prompt a Y/n question on wether to install the listed packages. To automatically answer yes to that question we can add the --yes option to our command line: apt-get install --yes <package>.

This will cause it to progress a bit further but you might see that it'll sometimes hang after downloading the packages. This is the step where packages can ask the user questions on how they should be configured. Fortunately most packages have sensible defaults so we can decide to use those. If the defaults of the package you want to install aren't sensible enough you can set them beforehand using debconf-set-selections.

To configure apt-get to not ask us any questions we have to set the frontend using an environment variable called DEBIAN_FRONTEND. Specifically, we want to use the noninteractive frontend. This results in the following command: DEBIAN_FRONTEND=noninteractive apt-get install --yes <package>

Full example

Lets say we want to install the build-essential package. These would be the full CI statements we would have to run inside Docker. (Be sure not to run noninteractive --yes apt-get install commands on machines you're not ready to reinstall)

# Make sure we don't silently continue when a command fails
set -euo pipefail

# Update the package repositories
apt-get update --quiet=2
# Install the package
DEBIAN_FRONTEND=noninteractive apt-get install --yes build-essential