GitLab Runner Custom Executor that provisions a Proxmox VM and runs the job script inside it
Project description
gitlab-proxmox-runner
A GitLab Runner Custom Executor
driver that provisions a fresh Proxmox VM for each CI job and runs the job's
script inside that VM. CI variables (CI_JOB_ID, CI_COMMIT_SHA, …) are
visible to user scripts the same way the docker executor exposes them.
The package ships four console scripts: vm_config_exec, vm_prepare_exec,
vm_run_exec, vm_cleanup_exec. They map 1:1 to the four hooks of the
gitlab-runner custom executor protocol.
How it works
Per CI job, gitlab-runner invokes the four entry points this package installs:
| Entry point | Stage | Responsibility |
|---|---|---|
vm_config_exec |
once, first | Emit driver/build dirs/job_env JSON; resolves the requested template ID. |
vm_prepare_exec |
once | Clone the Proxmox template, boot the VM, wait for the QEMU guest agent, save {vmid, ip} state. |
vm_run_exec |
per stage | scp the runner-generated stage script to the VM, then ssh <user>@vm sudo /bin/bash …. Runs prepare_script, get_sources, build_script, upload_artifacts_*, etc., all in the VM. |
vm_cleanup_exec |
once, last | Best-effort stop + destroy of the VM, remove state file. |
Per-job state is persisted to /tmp/gitlab-proxmox-runner-${CI_JOB_ID}.json
so each stage can find the VM that was provisioned in vm_prepare_exec.
Templates
Pick one via PROXMOX_TEMPLATE (job-level variable):
| Template name | Proxmox VMID |
|---|---|
ubuntu-focal |
60900 |
ubuntu-bionic |
60910 |
debian-11 |
60920 |
debian-12 |
60930 |
Prerequisite: these template VMs must already exist on the Proxmox server at the matching VMIDs before any CI job runs. The driver only clones an existing template — it does not create one. The VMID column above is the ID the driver looks up in
pve.<node>.qemu/<vmid>. If you use different VMIDs in your environment, fork this repo and editVM_Templatesingitlab_proxmox_runner/__init__.py.
Each template VM must:
- have the QEMU guest agent installed and enabled,
- contain the SSH user named in
VM_SSH_USER(defaultci) with passwordlesssudoand the runner's SSH public key in~/.ssh/authorized_keys, - be marked as a template in Proxmox (
qm template <vmid>).
Required environment on the runner host
Set in [[runners]].environment (config.toml). gitlab-runner automatically
prefixes build variables with CUSTOM_ENV_ when handing them to custom
executor scripts, so write the names below without the prefix in
config.toml — the executor reads them as CUSTOM_ENV_<NAME>.
| Variable in config.toml | Read by executor as | Purpose |
|---|---|---|
PROXMOX_HOST |
CUSTOM_ENV_PROXMOX_HOST |
Proxmox API host |
PROXMOX_USER |
CUSTOM_ENV_PROXMOX_USER |
Proxmox user (e.g. root@pam) |
PROXMOX_TOKEN_NAME |
CUSTOM_ENV_PROXMOX_TOKEN_NAME |
Proxmox API token name |
PROXMOX_TOKEN_VALUE |
CUSTOM_ENV_PROXMOX_TOKEN_VALUE |
Proxmox API token value |
PROXMOX_NODE |
CUSTOM_ENV_PROXMOX_NODE |
Proxmox node name to clone on |
VM_SSH_USER |
CUSTOM_ENV_VM_SSH_USER |
SSH user inside the VM (default: ci) |
VM_SSH_PRIVATE_KEY carries the private key for ssh/scp into the VM. It
is typically a GitLab CI variable (instance- or project-level, File or
Variable type). gitlab-runner exposes it to the executor as
CUSTOM_ENV_VM_SSH_PRIVATE_KEY. The driver also accepts VM_SSH_PRIVATE_KEY
(no prefix) for setups where the value is exported via the runner's systemd
unit. The variable may contain either:
- the actual private-key text (the driver materialises it to a
0600temp file on the runner host), or - a filesystem path to an existing key file.
Installation on the runner host
sudo /usr/bin/pip install -U --break-system-packages gitlab-proxmox-runner
--break-system-packages is required on Debian 12 / Python 3.12+ where the
system pip enforces PEP 668.
The four entry points install to
/usr/local/bin/{vm_config_exec,vm_prepare_exec,vm_run_exec,vm_cleanup_exec}.
Runner config
A worked config.toml example lives at examples/config.toml.
Copy the relevant [[runners]] block onto your runner host and
systemctl restart gitlab-runner.
Using it from a job
The job script is plain shell — no manual SSH/SCP plumbing:
my-job:
tags: [proxmox]
variables:
PROXMOX_TEMPLATE: ubuntu-focal
script:
- apt-get update && apt-get install -y build-essential
- make
artifacts:
paths: [out/]
get_sources, the user script:, and upload_artifacts_* all execute inside
the VM. CI variables are exported automatically. Artifacts are uploaded by
gitlab-runner's normal flow.
Development
python -m venv .venv
. .venv/bin/activate
pip install -e ".[dev]"
ruff check .
pytest -q --cov=gitlab_proxmox_runner --cov-report=term-missing
python -m build # produces sdist + wheel under dist/
The unit-test suite does not require a live Proxmox instance — Proxmox API calls and SSH/SCP subprocess calls are mocked out. End-to-end testing must be done on a host with network access to a Proxmox cluster.
Releasing to PyPI
CI publishes on tag pushes matching vX.Y.Z via
PyPI Trusted Publishing (OIDC).
One-time PyPI setup: at https://pypi.org/manage/account/publishing/ add a
publisher with:
- Project name:
gitlab-proxmox-runner - Owner: your gitlab.com namespace
- Repository name: this repo's slug
- Workflow filename:
.gitlab-ci.yml
Then git tag v0.1.0 && git push --tags triggers the publish job.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gitlab_proxmox_runner-0.0.1.tar.gz.
File metadata
- Download URL: gitlab_proxmox_runner-0.0.1.tar.gz
- Upload date:
- Size: 18.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e6d2b40466a44a2bb716a81d8aeb287d9ff3024b9471bac5d34d1b55c5b4ca54
|
|
| MD5 |
2b882b4cf1392a438924526d1c6cc317
|
|
| BLAKE2b-256 |
ebfaeffef5a126b1adfeb30b831aa16fca5727f33978b28c0a46411ca55725f1
|
File details
Details for the file gitlab_proxmox_runner-0.0.1-py3-none-any.whl.
File metadata
- Download URL: gitlab_proxmox_runner-0.0.1-py3-none-any.whl
- Upload date:
- Size: 12.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4baf39905f40f996cbddc17719542334b66642bec59be85529ac2665f0b41117
|
|
| MD5 |
3a581d7054dc9b919c37a4faaf04ae64
|
|
| BLAKE2b-256 |
9a5bc55a55c0f8fc47becb20ec375e9849d6f0ece6f4161c532b1d40ebbd6a61
|