APT

Linux distributions organise system files on disk into collections called packages. Packages can be comprised of binaries (e.g. find, ls, grep), shared libraries, configuration files (e.g. /etc/hosts, /etc/passwd) and directories.

Each package has some associated metadata, including a version number, which is committed to a database when the package is installed. This allows us to query the version of a package, the files installed by each package, find the package that owns a given file and even identify changes to a package's default configuration. To allow reuse, packages can have dependencies on other packages.

Distribution of packages takes place via repositories which contain copies of these packages and indexes describing their names and versions. By comparing the version numbers we have locally with those in the repository index we can identify packages in need of updates.

When we refer to APT we're usually referring to two things:

  • dpkg, the Debian PacKaGe manager, which manages *.deb packages and their installed files on-disk. You can think of this as the low level tool that does most of the heavy lifting; you won't directly interact with it often.
  • APT and frontends like apt, apt-get and aptititude which allow us to fetch these packages from repositories.

Refreshing repository metadata

Data about the packages available in each repository is cached locally to improve query time. This data needs to be periodically refreshed:

$ sudo apt update
Hit:1 http://archive.ubuntu.com/ubuntu bionic InRelease
Get:2 http://archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB]
Get:3 http://archive.ubuntu.com/ubuntu bionic-backports InRelease [74.6 kB]
Get:4 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]
[snip]
Fetched 18.0 MB in 6s (3102 kB/s)
Reading package lists... Done
Building dependency tree
Reading state information... Done
126 packages can be upgraded. Run 'apt list --upgradable' to see them.

Show information about an installed package

$ apt show <package>

$ apt show bash
Package: bash
Version: 4.4.18-2ubuntu1.2
Priority: required
Essential: yes
Section: shells
Origin: Ubuntu
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Original-Maintainer: Matthias Klose <doko@debian.org>
Bugs: https://bugs.launchpad.net/ubuntu/+filebug
Installed-Size: 1626 kB
Pre-Depends: libc6 (>= 2.15), libtinfo5 (>= 6)
Depends: base-files (>= 2.1.12), debianutils (>= 2.15)
Recommends: bash-completion (>= 20060301-0)
Suggests: bash-doc
Conflicts: bash-completion (<< 20060301-0)
Replaces: bash-completion (<< 20060301-0), bash-doc (<= 2.05-1)
Homepage: http://tiswww.case.edu/php/chet/bash/bashtop.html
Task: minimal
Supported: 5y
Download-Size: 614 kB
APT-Sources: http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 Packages
Description: GNU Bourne Again SHell
 Bash is an sh-compatible command language interpreter that executes
 commands read from the standard input or from a file.  Bash also
 incorporates useful features from the Korn and C shells (ksh and csh).
 .
 Bash is ultimately intended to be a conformant implementation of the
 IEEE POSIX Shell and Tools specification (IEEE Working Group 1003.2).
 .
 The Programmable Completion Code, by Ian Macdonald, is now found in
 the bash-completion package.

N: There are 2 additional records. Please use the '-a' switch to see them.

List available updates

Be sure to refresh the repository metadata ahead of listing updates to ensure the latest updates are available.

$ apt list --upgradable
Listing... Done
apport/bionic-updates,bionic-security 2.20.9-0ubuntu7.9 all [upgradable from: 2.20.9-0ubuntu7.6]
apt/bionic-updates 1.6.12 amd64 [upgradable from: 1.6.10]
apt-utils/bionic-updates 1.6.12 amd64 [upgradable from: 1.6.10]
base-files/bionic-updates 10.1ubuntu2.7 amd64 [upgradable from: 10.1ubuntu2.4]
[snip]

Applying updates

Updating packages is referred to as "upgrading" in APT. There are two modes:

  • upgrade will only replace installed packages with newer versions.
  • dist-upgrade will perform all of the operations an upgrade will do, additionally installing additional packages and removing obsolete packages whose dependencies cannot be met. This will upgrade any packages that upgrade says have been "kept back".

The only difference between the two in normal operation is that Linux kernel updates will not be installed during an upgrade, but will with a dist-upgrade.

$ sudo apt upgrade
lcarrier@HLC002155:~$ sudo apt-get upgrade apt
Reading package lists... Done
Building dependency tree
Reading state information... Done
Calculating upgrade... Done
The following package was automatically installed and is no longer required:
  libfreetype6
Use 'sudo apt autoremove' to remove it.
The following packages have been kept back:
  ubuntu-wsl wslu
The following packages will be upgraded:
  apport apt apt-utils base-files bash bind9-host bsdutils bzip2 cloud-init
  curl dbus distro-info-data dmeventd dmsetup dnsutils dpkg e2fsprogs fdisk
  file friendly-recovery gcc-8-base grep initramfs-tools initramfs-tools-bin
  initramfs-tools-core iputils-ping iputils-tracepath landscape-common
[snip]
124 upgraded, 0 newly installed, 0 to remove and 2 not upgraded.
Need to get 53.1 MB of archives.
After this operation, 1159 kB disk space will be freed.
Do you want to continue? [Y/n]
Get:1 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 base-files amd64 10.1ubuntu2.7 [60.3 kB]
Get:2 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 bash amd64 4.4.18-2ubuntu1.2 [614 kB]
Get:3 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 bsdutils amd64 1:2.31.1-0.4ubuntu3.4 [60.3 kB]
Get:4 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 dpkg amd64 1.19.0.5ubuntu2.3 [1136 kB]
[snip]
Fetched 75.3 MB in 15s (4911 kB/s)
Extracting templates from packages: 100%
Preconfiguring packages ...
(Reading database ... 28645 files and directories currently installed.)
Preparing to unpack .../base-files_10.1ubuntu2.7_amd64.deb ...
Unpacking base-files (10.1ubuntu2.7) over (10.1ubuntu2.4) ...
Setting up base-files (10.1ubuntu2.7) ...
Installing new version of config file /etc/issue ...
Installing new version of config file /etc/issue.net ...
Installing new version of config file /etc/lsb-release ...
Installing new version of config file /etc/update-motd.d/50-motd-news ...
(Reading database ... 28645 files and directories currently installed.)
Preparing to unpack .../bash_4.4.18-2ubuntu1.2_amd64.deb ...
Unpacking bash (4.4.18-2ubuntu1.2) over (4.4.18-2ubuntu1.1) ...
Setting up bash (4.4.18-2ubuntu1.2) ...
update-alternatives: using /usr/share/man/man7/bash-builtins.7.gz to provide /usr/share/man/man7/builtins.7.gz (builtins.7.gz) in auto mode
(Reading database ... 28645 files and directories currently installed.)
Preparing to unpack .../bsdutils_1%3a2.31.1-0.4ubuntu3.4_amd64.deb ...
Unpacking bsdutils (1:2.31.1-0.4ubuntu3.4) over (1:2.31.1-0.4ubuntu3.3) ...
Setting up bsdutils (1:2.31.1-0.4ubuntu3.4) ...
(Reading database ... 28645 files and directories currently installed.)
Preparing to unpack .../dpkg_1.19.0.5ubuntu2.3_amd64.deb ...
Unpacking dpkg (1.19.0.5ubuntu2.3) over (1.19.0.5ubuntu2.1) ...
Setting up dpkg (1.19.0.5ubuntu2.3) ...
[snip]
Selecting previously unselected package libogg0:amd64.
Preparing to unpack .../09-libogg0_1.3.2-1_amd64.deb ...
Unpacking libogg0:amd64 (1.3.2-1) ...
Selecting previously unselected package x11-common.
Preparing to unpack .../10-x11-common_1%3a7.7+19ubuntu7.1_all.deb ...
dpkg-query: no packages found matching nux-tools
Unpacking x11-common (1:7.7+19ubuntu7.1) ...
Selecting previously unselected package libice6:amd64.
Preparing to unpack .../11-libice6_2%3a1.0.9-2_amd64.deb ...
Unpacking libice6:amd64 (2:1.0.9-2) ...
Selecting previously unselected package libsm6:amd64.
Preparing to unpack .../12-libsm6_2%3a1.2.2-1_amd64.deb ...
Unpacking libsm6:amd64 (2:1.2.2-1) ...
[snip]
Setting up iputils-ping (3:20161105-1ubuntu3) ...
Setting up libxi6:amd64 (2:1.7.9-1) ...
Setting up libxcb-present0:amd64 (1.13-2~ubuntu18.04) ...
Setting up libglvnd0:amd64 (1.0.0-2ubuntu2.3) ...
[snip]
Processing triggers for libc-bin (2.27-3ubuntu1) ...
Processing triggers for systemd (237-3ubuntu10.31) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
Processing triggers for rsyslog (8.32.0-1ubuntu4) ...
invoke-rc.d: could not determine current runlevel
[snip]
$ sudo apt dist-upgrade
Reading package lists... Done
Building dependency tree
Reading state information... Done
All packages are up to date.

If you want to upgrade specific packages, specify them by name:

sudo apt upgrade <package> [package] [package]

Removing outdated packages

Some packages (most notable the Linux kernel) are versioned in a way that allows multiple versions to be installed alongside one another, where the other is no longer used.

This is how we avoid filling /boot with older kernels.

$ sudo apt autoremove
Building dependency tree
Reading state information... Done
The following packages will be REMOVED:
  linux-azure-cloud-tools-5.0.0-1020 linux-azure-cloud-tools-5.0.0-1022 linux-azure-headers-5.0.0-1020
  linux-azure-headers-5.0.0-1022 linux-azure-tools-5.0.0-1020 linux-azure-tools-5.0.0-1022
0 upgraded, 0 newly installed, 6 to remove and 16 not upgraded.
After this operation, 187 MB disk space will be freed.
Do you want to continue? [Y/n]
(Reading database ... 143612 files and directories currently installed.)
Removing linux-azure-cloud-tools-5.0.0-1020 (5.0.0-1020.21~18.04.1) ...
Removing linux-azure-cloud-tools-5.0.0-1022 (5.0.0-1022.23~18.04.1) ...
Removing linux-azure-headers-5.0.0-1020 (5.0.0-1020.21~18.04.1) ...
Removing linux-azure-headers-5.0.0-1022 (5.0.0-1022.23~18.04.1) ...
[snip]

Cleaning cached package files

Downloaded package (*.deb) files are cached in /var/lib/apt/cache to speed up future reinstallation operations.

In disk-constrained environments (e.g. when building Docker images or VM templates) you'll want to clean these directories to free up space. It's usually unnecessary in day-to-day administration, though.

$ sudo apt autoclean
Reading package lists... Done
Building dependency tree
Reading state information... Done

Repositories

Repositories are defined in two locations which are given equal precedence:

  • /etc/apt/sources.list defines the system repositories. We can add additional entires to this file but it's considered better practice to use drop-ins.
  • /etc/apt/sources.list.d/*.list contains drop-in definitions.

Repository definitions are done in a single line, e.g.:

deb https://apt.example.com/debian bionic main
deb [arch=amd64] https://apt.example.com/debian xenial main

For more details on formatting see sources.list(5).

Pinning packages

By default APT will upgrade all packages to their latest versions in any enabled repository during upgrade operations. This isn't always desirable:

  • Sometimes a service is expected to be at the same version across a cluster of servers.
  • We might want to use an older version of a package from a vendor's repository rather than the latest one available in the distribution.

"Pinning" is the act of limiting this behaviour to keep a package at a specific version or source repository.

APT frontends will read files placed in /etc/apt/preferences.d formatted as follows:

Package: my-package
Pin: version 1.2.3
Pin-Priority: 500

You can see the current policy for all repositories and pinned packages as follows:

$ apt policy
Package files:
 100 /var/lib/dpkg/status
     release a=now
 500 http://security.ubuntu.com/ubuntu bionic-security/multiverse amd64 Packages
     release v=18.04,o=Ubuntu,a=bionic-security,n=bionic,l=Ubuntu,c=multiverse,b=amd64
     origin security.ubuntu.com
 500 http://security.ubuntu.com/ubuntu bionic-security/universe amd64 Packages
     release v=18.04,o=Ubuntu,a=bionic-security,n=bionic,l=Ubuntu,c=universe,b=amd64
     origin security.ubuntu.com
 500 http://security.ubuntu.com/ubuntu bionic-security/restricted amd64 Packages
     release v=18.04,o=Ubuntu,a=bionic-security,n=bionic,l=Ubuntu,c=restricted,b=amd64
     origin security.ubuntu.com
[snip]
Pinned packages:
     my-package -> 1.2.3 with priority 500

And for a specific package -- in this case for my-package which is pinned at version 1.2.3 when 1.2.4 is available in a third-party repository:

$ apt policy my-package
my-package:
  Installed: 1.2.3
  Candidate: 1.2.3
  Version table:
     1.2.4 500
        500 https://apt.example.com/debian/ bionic/main amd64 Packages
 *** 1.2.3 900
        100 /var/lib/dpkg/status

Children
  1. Migrating from apt-key to signed-by

Backlinks