GitLab CI
On a privileged GitLab runner, OmniPackage works the same way as on your machine. The job container has podman. OmniPackage starts one container per distro inside it with podman run --mount .... You do not need a special runtime or a Docker-in-Docker service.
Requirements
- Privileged jobs. On a self-hosted runner, set
privileged = trueunder[runners.docker](or[runners.kubernetes]) inconfig.toml. GitLab.com hosted Linux runners already allow privileged jobs, because they support Docker-in-Docker. - A job image with podman. The examples use
quay.io/podman/stable. It hascurl, and it stores containers in the/var/lib/containersvolume, so nested containers work.
With the shell executor on a host that has podman or docker, you need neither. Remove image: and run the same commands.
Pipeline
flowchart LR
G["generate"] -->|release.yml| R["release child pipeline<br/>one job per distro"]
G -->|prime.yml| P["prime child pipeline<br/>one job per distro"]
P -->|push| REG[("GitLab Container Registry")]
REG -.->|pull| R
R -->|upload| S3[("S3 repository")]
The generate job reads builds: with omnipackage info --list-distros. It writes a child pipeline with one job per distro. This works like the GitHub Actions matrix: when you add a build target to config.yml, you get a new job.
.gitlab-ci.yml:
include:
- local: .gitlab/omnipackage.yml
variables:
OMNIPACKAGE_REPOSITORY: My packages
OMNIPACKAGE_IMAGE_CACHE: ""
workflow:
rules:
- if: $CI_COMMIT_TAG
- if: $CI_PIPELINE_SOURCE == "schedule"
- if: $CI_PIPELINE_SOURCE == "web"
stages: [generate, run]
generate:
extends: .omnipackage
stage: generate
script:
- |
for kind in release prime; do
echo "include: [{local: .gitlab/omnipackage.yml}]" > "$kind.yml"
for distro in $(omnipackage info . --list-distros); do
printf '%s:%s:\n extends: .omnipackage-%s\n variables:\n DISTRO: "%s"\n' "$kind" "$distro" "$kind" "$distro" >> "$kind.yml"
done
done
artifacts:
paths: [release.yml, prime.yml]
release:
stage: run
needs: [generate]
trigger:
include:
- artifact: release.yml
job: generate
strategy: depend
rules:
- if: $CI_PIPELINE_SOURCE != "schedule"
prime:
stage: run
needs: [generate]
trigger:
include:
- artifact: prime.yml
job: generate
strategy: depend
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
- if: $CI_PIPELINE_SOURCE == "web"
when: manual
allow_failure: true
.gitlab/omnipackage.yml has the job templates for both child pipelines:
.omnipackage:
image: quay.io/podman/stable
before_script:
- curl -fsSL https://repositories.omnipackage.org/omnipackage-rs/stable/install.sh | sh -s -- -y
.omnipackage-release:
extends: .omnipackage
resource_group: omnipackage-$DISTRO
script:
- omnipackage release . --repository "$OMNIPACKAGE_REPOSITORY" --distros "$DISTRO" ${OMNIPACKAGE_IMAGE_CACHE:+--image-cache "$OMNIPACKAGE_IMAGE_CACHE"}
.omnipackage-prime:
extends: .omnipackage
script:
- omnipackage prime . --image-cache gitlab --distros "$DISTRO"
For fedora_42, the release child pipeline gets this job:
Notes:
- Triggers. Tags and manual runs ("Run pipeline") release packages. Schedules only prime the image cache. Change
workflow:rulesif you need other triggers. For example, add$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCHand a separaterepositories:entry to publish every push to the default branch, like the GitHub setup. resource_groupruns only one release job per distro at a time, even across pipelines. This is like the GitHub concurrency group. Two jobs that write to the same repository at the same time break its metadata.- Variables. GitLab passes top-level
variables:to child pipelines. SetOMNIPACKAGE_REPOSITORYandOMNIPACKAGE_IMAGE_CACHEonce, in.gitlab-ci.yml. - Architecture. Packages are built for the runner's CPU. For aarch64, use runner tags (for example
saas-linux-small-arm64), thestable-aarch64install URL, and a separaterepositories:entry. Arch and Manjaro are x86_64 only. - Storage errors. If podman fails with overlay mount errors, add
STORAGE_DRIVER: vfsto.omnipackage. It is slower, but it works on any filesystem.
Image cache on GitLab Container Registry
image_caches:
- name: gitlab
provider: registry
image_tag: omnipackage-cache
registry:
url: "${CI_REGISTRY}"
namespace: "${CI_PROJECT_PATH}"
username: "${CI_REGISTRY_USER}"
password: "${CI_REGISTRY_PASSWORD}"
The images are $CI_REGISTRY_IMAGE/<distro_id>:omnipackage-cache. GitLab sets all four variables in every job. The job token can push to and pull from the project's own registry. The namespace must be lowercase. If your project path has capital letters, write the namespace by hand.
Steps:
- Run the pipeline once with an empty
OMNIPACKAGE_IMAGE_CACHE. Release jobs start from plain distro images and runsetupthemselves. - Run prime. Start a pipeline manually and run the
primejob, or add a schedule. Once a month is enough. Also prime again whenbuild_dependenciesorbefore_build_scriptchange. Seeprime. - Set
OMNIPACKAGE_IMAGE_CACHE: gitlab. Release jobs now pull the cached images and skipsetup.
Secrets
Store secrets as masked CI/CD variables in Settings → CI/CD → Variables. You need the GPG key and the S3 credentials. Create the key with omnipackage gpg generate --format base64: the output is one line, so GitLab can mask it. ${...} in config.yml reads environment variables first, so you do not need a .env file. Child pipelines get project variables automatically. Mark the variables as protected only if you release from protected branches or tags.