This document explains in detail what happens when you run sudo apt install postgresql-16
on Ubuntu. We'll examine everything from command processing to having a running PostgreSQL server.
Note: Skip to the end for a quick overview.
When you hit Enter after typing sudo apt install postgresql-16
:
-
The shell processes the command:
- Tokenizes input into:
sudo
,apt
,install
,postgresql-16
- Locates
sudo
executable in PATH (typically/usr/bin/sudo
) - Creates a child process to run this command:
pid = fork() if (pid == 0) { // Execute `/usr/bin/sudo` in child process execve("/usr/bin/sudo", [ "sudo", // argv[0] - program name "apt", // argv[1] - first argument "install", // argv[2] - second argument "postgresql-16", // argv[3] - third argument NULL // argv[4] - array terminator ], env // Current environment variables ); } else { // Parent process (bash) waitpid(pid, &status, 0); }
- Tokenizes input into:
-
sudo
verifies user permissions and elevates the process privileges to root:- Reads main sudoers file
/etc/sudoers
:# User privilege specification root ALL=(ALL:ALL) ALL # Allow members of group sudo to execute any command %sudo ALL=(ALL:ALL) ALL # Example user entry username ALL=(ALL:ALL) ALL @includedir /etc/sudoers.d
- Reads additional configurations
/etc/sudoers.d/*
:# User rules for ubuntu ubuntu ALL=(ALL) NOPASSWD:ALL
- If the user has sufficient privileges to run this command, the system changes the UID (user ID) from current user (UID=1000) to root (UID=0), giving it root privileges for the duration of the process.
- Reads main sudoers file
-
Sudo executes
apt
:pid_t childPid = fork(); if (childPid == 0) { // Execute `/usr/bin/apt` in child process execve("/usr/bin/apt", [ "apt", // argv[0] - program name "install", // argv[1] - first argument "postgresql-16", // argv[2] - second argument NULL // argv[3] - array terminator ], cleaned_env // Sanitized env vars with updated $USER (root) ); } else { // Parent process (sudo) waitpid(childPid, &status, 0); }
Note:
- Parent process waits for child process to finish with
waitpid()
- Child process inherits stdout/stderr, allowing output to terminal
# Before sudo:
bash (UID=1000) # bash running with current user ID (1000)
└── sudo (UID=1000 → 0) # sudo starts with current UID (1000) but escalates to root (0)
# After sudo:
bash (UID=1000) # Bash running with current UID (1000)
└── sudo (UID=0) # sudo running with root UID (0)
└── apt (UID=0) # apt starts with root UID (0)
To install PostgreSQL, APT (Advanced Package Tool) needs to:
- Find where to download it from
- Make sure the download source is trustworthy
- Figure out what additional software (dependencies) is needed
- Check if there's enough space
- Prepare for download and ask for user input
- Download the packages and verify checksums
APT reads its "address book" of software sources. APT needs to know which servers have the software it needs to install.
-
Read sources configuration:
# Primary source file /etc/apt/sources.list.d/ubuntu.sources: Types: deb URIs: http://archive.ubuntu.com/ubuntu/ Suites: noble noble-updates noble-backports Components: main universe restricted multiverse Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg
-
Build repository URLs:
# URL Pattern: {URI}/dists/{Suite}/{Component}/binary-{Architecture}/Packages.gz # Actual URLs: http://archive.ubuntu.com/ubuntu/dists/noble/main/binary-amd64/Packages.gz http://archive.ubuntu.com/ubuntu/dists/noble/universe/binary-amd64/Packages.gz http://archive.ubuntu.com/ubuntu/dists/noble-updates/main/binary-amd64/Packages.gz ...
APT downloads a Release file and verifies it's really from Ubuntu.
The InRelease file contains repository metadata (checksums) and is signed by a GPG key to ensure its authenticity. APT fetches this file from the repository and verifies its signature before trusting the metadata for package installation or upgrade.
-
Download and verify release files:
# Download InRelease file # URL: http://archive.ubuntu.com/ubuntu/dists/{Suite}/InRelease curl http://archive.ubuntu.com/ubuntu/dists/noble/InRelease # Content excerpt of InRelease: -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 Origin: Ubuntu Label: Ubuntu Noble Suite: noble Version: 24.04 Codename: noble Date: Thu, 14 Mar 2024 12:04:32 UTC Architectures: amd64 arm64 armhf i386 Components: main restricted universe multiverse Description: Ubuntu Noble 24.04 MD5Sum: 262e2d... 7165069 main/binary-amd64/Packages 61fdc2... 1808488 main/binary-amd64/Packages.gz d9a7b0... 1401160 main/binary-amd64/Packages.xz SHA1: b81dce... 7165069 main/binary-amd64/Packages 41679a... 1808488 main/binary-amd64/Packages.gz cfb5fc... 1401160 main/binary-amd64/Packages.xz SHA256: 8f6f71... 7165069 main/binary-amd64/Packages e0d7e4... 1808488 main/binary-amd64/Packages.gz 2a6a19... 1401160 main/binary-amd64/Packages.xz -----BEGIN PGP SIGNATURE----- [signature data] -----END PGP SIGNATURE-----
-
Verify repository InRelease file signature:
# Using Ubuntu's keyring gpgv \ --keyring=/usr/share/keyrings/ubuntu-archive-keyring.gpg \ # Official Ubuntu public keys to sign package metadata /var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_noble_InRelease # Location of InRelease file # If verification fails: E: Release file not valid yet (invalid for another Xh XXmin XXs) # or E: GPG error: http://archive.ubuntu.com noble InRelease: Invalid signature
APT downloads and reads detailed information about all available packages to find what exactly it needs and its specifications.
-
APT downloads the
Packages.gz
to/var/lib/apt/lists
and verifies the data integrity using checksums in InRelease file. -
Parse
Packages.gz
repository downloaded above:# Example package entry - like a product description: # Entry taken from http://archive.ubuntu.com/ubuntu/dists/noble/main/binary-amd64/Packages.gz Package: postgresql-16 Architecture: amd64 Version: 16.2-1ubuntu4 Priority: optional Section: database Origin: Ubuntu Maintainer: Ubuntu Developers <[email protected]> Original-Maintainer: Debian PostgreSQL Maintainers <[email protected]> Bugs: https://bugs.launchpad.net/ubuntu/+filebug Installed-Size: 43800 Provides: postgresql-16-jit-llvm (= 17), postgresql-contrib-16 Depends: locales | locales-all, postgresql-client-16, postgresql-common (>= 252~), ssl-cert, tzdata, debconf (>= 0.5) | debconf-2.0, libc6 (>= 2.38), libgcc-s1 (>= 3.3.1), libgssapi-krb5-2 (>= 1.14+dfsg), libicu74 (>= 74.1-1~), libldap2 (>= 2.6.2), libllvm17t64, liblz4-1 (>= 0.0~r130), libpam0g (>= 0.99.7.1), libpq5 (>= 16~~), libselinux1 (>= 3.1~), libssl3t64 (>= 3.0.0), libstdc++6 (>= 5.2), libsystemd0, libuuid1 (>= 2.16), libxml2 (>= 2.7.4), libxslt1.1 (>= 1.1.25), libzstd1 (>= 1.5.5), zlib1g (>= 1:1.1.4) Recommends: sysstat Breaks: dbconfig-common (<< 2.0.22~) Filename: pool/main/p/postgresql-16/postgresql-16_16.2-1ubuntu4_amd64.deb Size: 15452168 MD5sum: a0ddd38a3ce650de38cbd1fa4960861f SHA1: 55098507be06aa3bbdb7d0fef855338c6195e0fd SHA256: 7f25383e8f39ca99f4886b7b2cbb31c62534ac924e3a61da3f0e8e6456091e69 SHA512: 181d452698e0895c5f54d916a4ee2f2bf6899175e9f5a7d0049723026db9360da0a3f4001f34e3015bc0e0d90d92a63eb161b50d62085cc2c87f0a559e317fe2 Homepage: http://www.postgresql.org/ Description: The World's Most Advanced Open Source Relational Database Task: postgresql-server Postgresql-Catversion: 202307071 Description-md5: d7367291c15795e56aa78252604f9ced
APT figures out what other software PostgreSQL needs to work properly.
-
Build dependency graph:
postgresql-16 ├── postgresql-client-16 # Needed to connect to database │ ├── libpq5 # Core PostgreSQL library │ └── ssl-cert # For secure connections ├── postgresql-common # Shared PostgreSQL utilities └── System libraries # Basic system requirements
-
Version Resolution: Check the availability and details of the package
postgresql-16
in the APT repositories configured on the system:$ apt-cache policy postgresql-16 # Output format postgresql-16: Installed: <installed_version> # Installed version (if any) Candidate: <candidate_version> # Version chosen to install (higher priority or version) Version table: # Lists all available versions of postgresql-16 <version_num> <priority> # Default priority is 500 <priority> <repository_url> <distribution>/<repository_section> <architecture> <file> # Actual output postgresql-16: Installed: (none) Candidate: 16.4-0ubuntu0.24.04.2 Version table: 16.4-0ubuntu0.24.04.2 500 500 http://ap-south-1.ec2.archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages 16.4-0ubuntu0.24.04.1 500 500 http://security.ubuntu.com/ubuntu noble-security/main amd64 Packages 16.2-1ubuntu4 500 500 http://ap-south-1.ec2.archive.ubuntu.com/ubuntu noble/main amd64 Packages
APT calculates total download size and checks if you have enough space.
-
Calculate requirements:
# Create download queue Need to get 23.1 MB of archives. After installation: 85.3 MB will be used. Download Queue: 1. postgresql-16 (16.2 MB) 2. postgresql-client-16 (4.8 MB) 3. postgresql-common (2.1 MB)
-
Check free space:
# Verify space in: /var/cache/apt/archives/ # Temporary download storage /var/lib/postgresql/ # Where PostgreSQL will live /etc/postgresql/ # Where settings will be stored
-
Prepare download locations:
# Create/verify directories mkdir -p /var/cache/apt/archives/partial # Set up download resume markers touch /var/cache/apt/archives/partial/postgresql-16_16.2-1ubuntu1_amd64.deb.dl
At this point, APT has:
- Verified repository authenticity
- Located all required packages
- Resolved dependencies
- Calculated disk space requirements
- Prepared for download
The next phase begins once the user confirms the installation prompt.
-
Download packages:
# Download to cache /var/cache/apt/archives/ └── partial/ # Temporary download location └── postgresql-16_16.2-1ubuntu1_amd64.deb # After download completion, move to /var/cache/apt/archives/postgresql-16_16.2-1ubuntu1_amd64.deb
-
Verify packages:
# Check SHA256 sum against Packages file sha256sum postgresql-16_16.2-1ubuntu1_amd64.deb # Verify package signatures if available dpkg-sig --verify postgresql-16_16.2-1ubuntu1_amd64.deb
-
Pre-installation:
# Create system user/group useradd --system \ --home /var/lib/postgresql \ --shell /bin/bash \ postgres # Create directories mkdir -p /etc/postgresql/16/main mkdir -p /var/lib/postgresql/16/main mkdir -p /var/log/postgresql
-
Package Extraction:
# Extract package contents dpkg-deb -x postgresql-16_16.2-1.deb / # Main directories: /etc/postgresql/16/ # Configuration files /usr/lib/postgresql/16/ # Binaries /usr/share/postgresql/16/ # Shared files /var/lib/postgresql/16/ # Data directory
-
Database Cluster Creation:
# pg_createcluster execution 1. Initialize data directory (initdb) 2. Generate configuration files 3. Set up system tables 4. Configure authentication
-
Systemd Configuration:
# Create service files /lib/systemd/system/[email protected] # Service template /lib/systemd/system/postgresql.service # Main service # Enable service systemctl enable postgresql@16-main systemctl start postgresql@16-main
-
Process Hierarchy:
systemd └── postgres (postmaster) ├── postgres: logger process │ └── Writes to /var/log/postgresql/postgresql-16-main.log ├── postgres: checkpointer process │ └── Flushes dirty buffers to disk ├── postgres: background writer │ └── Writes dirty shared buffers ├── postgres: WAL writer │ └── Writes WAL buffers to disk ├── postgres: autovacuum launcher │ └── Cleans up dead tuples ├── postgres: stats collector │ └── Collects database statistics └── postgres: logical replication launcher └── Handles logical replication
-
Memory Allocation:
# For 1GB RAM system: shared_buffers = 128MB # 25% reduced for small RAM work_mem = 4MB # Per operation memory maintenance_work_mem = 64MB # For maintenance operations wal_buffers = 4MB # WAL writing buffer
-
Disk Organization:
/var/lib/postgresql/16/main/ ├── base/ # Databases │ ├── 1/ # template1 │ ├── 13067/ # template0 │ └── 13068/ # postgres ├── global/ # Shared objects ├── pg_wal/ # Write-ahead logs ├── pg_xact/ # Transaction status └── postgresql.conf # Configuration
-
System Catalog Creation:
# Creates system databases CREATE DATABASE template0; CREATE DATABASE template1; CREATE DATABASE postgres; # Creates system tables CREATE TABLE pg_class; # Relation catalog CREATE TABLE pg_attribute; # Column catalog CREATE TABLE pg_proc; # Function catalog
-
User Authentication Setup:
# pg_hba.conf configuration local all postgres peer local all all peer host all all 127.0.0.1/32 md5
After installation completes:
-
PostgreSQL Server State:
- Running as service (postgresql@16-main)
- Listening on port 5432
- Managing shared memory segments
- Processing client connections
- Writing to WAL files
- Performing background maintenance
-
System Configuration:
- Default databases created
- System catalog populated
- PostgreSQL superuser account configured
- Basic security settings applied
- Logging enabled
The installation process involves multiple components:
- APT handles package management
- dpkg handles package extraction
- pg_createcluster initializes the database
- systemd manages the service
- postmaster manages the running instance
System Requirements and Performance:
- Installation time: 2-5 minutes on a system with 1 vCPU
- Initial disk usage: ~100MB
- Runtime memory usage: ~200MB
- Idle CPU usage: <1%
- Add a sequence diagram.
- Review postgres preinst, installation, postinst steps and add more details.