Skip to content

Pulp Runbook - Functional Operations

GitLab uses Pulp to store and distribute RPM and DEB packages for different RHEL-based and Debian-based OS distributions. This runbook covers the functional operation perspective of Pulp and our usage patterns.

[[TOC]]

Pulp uses three key components for package management:

  1. Repository - A collection of packages that maintains multiple versions based on changes made during its lifetime.

  2. Publication - A distributable snapshot of a repository pointing to a specific repository version. All our repositories are configured to automatically create a new publication whenever a new package is uploaded.

  3. Distribution - The endpoint through which a repository is made accessible to users. Each distribution has a base path defined relative to the Pulp instance root. Distributions can point to either:

    • A specific publication, or
    • A repository (always pointing to the publication of the latest repository version) - this is what we use

Terminology note: To avoid confusion, this document uses “Pulp repository” and “Pulp distribution” when referring to Pulp-specific concepts. “OS distribution” refers to systems like “Debian Trixie”, “Ubuntu Noble”, or “AlmaLinux 9”.

APT and RPM repositories differ in their structure and naming pattern, as described below. Pulp distributions and their corresponding repositories have the same names, and the name is indicative of the final URL where they get served from.

Background: Theoretically, an APT repository can hold packages for different architectures and OS distributions, provided there are no duplicate packages.

Our challenge: Packages for a GitLab version created by omnibus-gitlab for different OS distributions all share the same version string but have different content (and checksums). This makes them duplicate packages that would overwrite each other in a single repository. We have 10 years of packages versioned this way that must remain accessible to customers.

Our solution: One Pulp repository per OS distribution for each component:

  • Example repositories: gitlab-gitlab-ee-debian-trixie, gitlab-gitlab-ce-ubuntu-noble
  • Each repository holds packages for different architectures (APT repositories segregate metadata by architecture)

Access pattern:

https://packages.gitlab.com/<organization>/<namespace>/<os>/<distribution>

Example sources.list entry:

deb https://packages.gitlab.com/gitlab/gitlab-ee/debian/trixie trixie main

Structure: Each architecture of each OS version gets its own Pulp repository. This allows serving packages for each architecture at different endpoints, saving users from downloading metadata for other architectures. This matches the standard structure used by upstream EL distributions.

Access pattern:

https://packages.gitlab.com/<organization>/<namespace>/<os>/<version>/<architecture>

Example repo configuration:

baseurl=https://packages.gitlab.com/gitlab/gitlab-ee/el/9/$basearch

Pulp repositories and distributions are managed by code.

To add a new OS distribution:

  1. Edit the YAML configuration file
  2. Add the new OS to the relevant components

Important: Repository deletion must be done manually to prevent accidental data loss.

Prerequisites:

Terminal window
pulp deb content upload \
--file=<path_to_file> \
--repository=<pulp-repository> \
--distribution=<os-distribution> \
--component=main

Example:

Terminal window
pulp deb content upload \
--file=gitlab-ee_18.0.0-ee.0_amd64.deb \
--repository=gitlab-gitlab-ee-debian-trixie \
--distribution=trixie \
--component=main

Note: The --distribution flag is required even though there’s a Pulp repository per OS distribution. This ensures Pulp properly generates metadata files for each OS distribution.

Terminal window
pulp rpm content upload \
--file=<path_to_file> \
--repository=<pulp-repository>

Example:

Terminal window
pulp rpm content upload \
--file=gitlab-ee-18.0.0-ee.0.el9.x86_64.rpm \
--repository=gitlab-gitlab-ee-el-9-x86_64

Important: The uploaded file must match the architecture corresponding to the repository.

Note: RPM uploads don’t require --distribution or --component flags because RPM internals create metadata files from all packages in a repository without a concept of “distributions”.

Check user management documentation for details on creation and management of users and roles in Pulp.

Terminal window
pulp deb repository list --limit=1000
pulp rpm repository list --limit=1000

Note: Use --offset flag to implement pagination.

Terminal window
pulp deb distribution list --limit=1000
pulp rpm distribution list --limit=1000

Note: Use --offset flag to implement pagination.

Terminal window
pulp deb content list --limit=1000
pulp rpm content list --limit=1000

Note: Use --offset flag to implement pagination.

Terminal window
pulp deb content list --package=gitlab-ee --limit=1000
pulp rpm content list --name=gitlab-ee --limit=1000

Note: Additional filters are available - check --help for each command.

Validate a Specific Package Version Exists

Section titled “Validate a Specific Package Version Exists”

To verify a specific package version exists in Pulp’s content store:

Prerequisites:

Terminal window
pulp deb content list \
--package=<package-name> \
--version="<exact-version>" \
--field version \
--field relative_path

Examples:

Validate a stable release:

Terminal window
pulp deb content list \
--package=gitlab-ee \
--version="18.10.0-ee.0" \
--field version \
--field relative_path

Validate a release candidate:

Terminal window
pulp deb content list \
--package=gitlab-ee \
--version="18.10.0-rc42.ee.0" \
--field version \
--field relative_path

Validate a nightly build:

Terminal window
pulp deb content list \
--package=gitlab-ee \
--version="18.10+stable.2398694953.4845434f-0" \
--field version \
--field relative_path

Validate an auto-deploy package:

Terminal window
pulp deb content list \
--package=gitlab-ee \
--version="18.10.202603181806-6ee48bcc3b8.f3f3da516cc" \
--field version \
--field relative_path

For RPM packages, both --version and --release fields are needed for precise matching:

Terminal window
pulp rpm content list \
--name=<package-name> \
--version="<version>" \
--release="<release>" \
--field version \
--field release \
--field location_href

Examples:

Validate a stable release:

Terminal window
pulp rpm content list \
--name=gitlab-ee \
--version="18.10.0" \
--release="ee.0.el9" \
--field version \
--field release \
--field location_href
OutputMeaning
[] (empty)Package not in Pulp — never uploaded, or incorrect version string
Records presentContent exists in the store
Content exists but 404 on downloadPackage not added to repository/publication — see Troubleshooting

GitLab DEB packages use these version formats:

Release TypeExample Version
Stable release18.10.0-ee.0
Release candidate18.10.0-rc42.ee.0
Stable branch auto-deploy18.10+stable.<pipeline_id>.<commit>-0
Nightly build18.10.YYYYMMDDHHMM-<gitlab_commit>.<omnibus_commit>
Release nightly18.10.0+rnightly.<pipeline_id>.<commit>-0

GitLab RPM packages use separate version and release fields:

Release TypeVersionRelease
Stable release18.10.0ee.0.<os> (e.g., ee.0.el9)
Release candidate18.10.0rc42.ee.0.<os> (e.g., rc42.ee.0.el9)

Note: The --version flag requires an exact match. If unsure of the exact version string, omit the --version flag and use --limit=20 to examine available versions.

If you need to verify a package is actually downloadable (not just present in the content store):

For DEB packages:

Terminal window
# Get the relative_path from content list
pulp deb content list \
--package=gitlab-ee \
--version="18.10.0-ee.0" \
--field relative_path
# Test download (replace with your distribution base URL and filename)
curl -I "https://packages.gitlab.com/gitlab/gitlab-ee/debian/pool/bookworm/main/g/gitlab-ee/<filename>.deb"

For RPM packages:

Terminal window
# Get the location_href from content list
pulp rpm content list \
--name=gitlab-ee \
--version="18.10.0" \
--release="ee.0.el9" \
--field location_href
# Test download (replace with your distribution base URL and filename)
curl -I "https://packages.gitlab.com/gitlab/gitlab-ee/el/9/x86_64/<filename>.rpm"
HTTP StatusMeaning
200 OKPackage is downloadable
404 Not FoundPackage not in publication — see Troubleshooting

Note: All GitLab Pulp repositories have autopublish: true enabled. If a package exists in content but returns 404 on download, this typically indicates a publication or distribution configuration issue rather than a missing upload.

If auto-publish fails, manually create a publication:

Terminal window
pulp deb publication create --repository=<pulp-repository-name>
pulp rpm publication create --repository=<pulp-repository-name>
Terminal window
pulp task list --state=waiting
pulp task list --state=running
pulp task list --state=failed
Terminal window
pulp task show --href=<pulp-task-href>