Search code examples
linuxubuntudockerapt-getdpkg

Restoring package state without upgrade to keep Docker Container small


As a step of a Dockerfile I need to install the build-essential package (if not available) and run make. To keep the footprint of the container nice and small; I would also like to remove build-essential and all resulting dependencies when done.

Simply removing it with apt-get remove followed by autoremove does not work; most packages installed (100mb or so) are left behind, probably as they are listed as recommended or suggested packages by others. Also; this approach may risk removing build-essential from a base image that did already contain it (and still should), unless checking for that case explicitly.

Another approach is to check the list of install packages and revert to that state after the make. My almost working solution is a script containing:

dpkg --get-selections > /before
apt-get -y install build-essential
make -C <path to Makefile>
dpkg --clear-selections
dpkg --set-selections < /before 
apt-get -y dselect-upgrade

This successfully restores package state and removes whatever packages were installed, while keeping any existing stuff in place. Great. However; existing packages on the system with pending updates are also updated -- which I would very much like to avoid at this stage as this adds unnecessary weight to this specific docker layer.

The following packages will be upgraded:
  apt apt-utils base-files coreutils cpio dpkg gcc-4.9-base ifupdown
  initscripts isc-dhcp-client isc-dhcp-common libapt-inst1.5 libapt-pkg4.12
  libc-bin libdrm2 libffi6 libgcc1 libgcrypt11 libgnutls-openssl27 libgnutls26
  libpng12-0 libssl1.0.0 libudev1 login multiarch-support ntpdate passwd
  sysv-rc sysvinit-utils udev
30 upgraded, 0 newly installed, 38 to remove and 0 not upgraded.
Need to get 11.3 MB of archives.
...

The question is; how can I restore the package state (read: remove all new packages installed by build-essential) without causing any packages to be updated?


Solution

  • Managed to solve it myself:

    dpkg --get-selections > /before
    apt-get -y install build-essential
    make -C <path to Makefile>
    dpkg --clear-selections
    cat /before | sed 's/install/hold/' | dpkg --set-selections
    apt-get -y dselect-upgrade
    dpkg --set-selections < /before
    

    The key difference is to set all packages not to be removed to to 'hold' (and then restore it to be polite to future upgrades).