
This guide deploys Pulp on Kubernetes with the official operator: you install the controller with Helm, then describe the instance in a Pulp custom resource, and the operator provisions the whole stack (API, content, workers, PostgreSQL, Redis, reverse proxy). Intended audience: platform teams that want a declarative, scalable artifact manager. Prerequisites: a Kubernetes cluster, kubectl and helm. You will see the installation with the right versions pinned, the Pulp resource, access to the instance, and the PostgreSQL version setting that conditions both startup and backup.
On Kubernetes, you do not install Pulp by hand: you install the Pulp Operator, a controller that watches Pulp resources and reconciles the cluster to match them. This is the operator model, declarative and self-healing.
What you will learn
- Install the Pulp Operator with Helm, pinning the right versions.
- Describe an instance with a
Pulpcustom resource. - Access the API and retrieve the admin password.
- Choose the PostgreSQL version that is compatible with backup.
Prerequisites
- A working Kubernetes cluster and
kubectlconfigured. - Helm 3+ installed.
- An available StorageClass. On a single-node cluster (k3d, Minikube), the
local-pathclass inReadWriteOnceis enough.
Installing the operator
The operator is deployed through its Helm chart. It installs the controller and the custom resource definitions (pulps, pulpbackups, pulprestores).
One point deserves to be made upfront: the published Helm chart pins old default versions (operator 1.3 and PostgreSQL 13). But pulpcore requires PostgreSQL 14 or later. So you install by overriding the operator image (latest version, here 2.0) and the PostgreSQL image (version 15).
-
Add the Helm repository and create a namespace:
Terminal window helm repo add pulp-operator https://github.com/pulp/pulp-k8s-resources/raw/main/helm-charts/ --force-updatekubectl create namespace pulp -
Install the operator with the versions pinned:
Terminal window helm -n pulp install pulp pulp-operator/pulp-operator \--set image=quay.io/pulp/pulp-operator:v2.0.0 \--set operator.relatedImages.postgres=docker.io/library/postgres:15 -
Check that the controller is running:
Terminal window kubectl -n pulp rollout status deploy/pulp-operator-controller-managerkubectl get crd | grep pulpprojectThe three CRDs
pulps,pulpbackupsandpulprestoresmust appear: the operator is ready to receive aPulpresource.
Deploying Pulp with a custom resource
The instance is described in a Pulp object. The operator reads this resource and creates the matching deployments, services, secrets and volumes.
apiVersion: repo-manager.pulpproject.org/v1kind: Pulpmetadata: name: pulp namespace: pulpspec: image_version: stable ingress_type: nodeport api: replicas: 1 content: replicas: 1 worker: replicas: 1 file_storage_access_mode: "ReadWriteOnce" file_storage_size: "10Gi" file_storage_storage_class: local-path database: postgres_storage_class: local-path postgres_image: docker.io/library/postgres:15kubectl apply -f pulp.yamlTwo settings in the database section are decisive:
postgres_storage_classis mandatory. Without it, the operator stops with the errorcould not find any storage definition for Database.postgres_image: postgres:15aligns the database with the same version as the backup tooling (see the box above). Keep this value consistent with the--set operator.relatedImages.postgresof the installation.
Following the deployment and connecting
The operator provisions the components in order: database, migrations, content, API, workers, reverse proxy. The first deployment downloads large images, so allow a few minutes.
-
Wait for the pods to be ready:
Terminal window kubectl -n pulp get pods -wYou should see
pulp-database-0,pulp-api,pulp-contentandpulp-workerasRunning, and themigrationandreset-admin-passwordjobs asCompleted. -
Retrieve the admin password, automatically generated in a secret:
Terminal window kubectl -n pulp get secret pulp-admin-password \-o jsonpath='{.data.password}' | base64 -d -
Test the API. The
pulp-web-svcservice (here in NodePort) exposes the instance; for a quick test, a port-forward is enough:Terminal window kubectl -n pulp port-forward svc/pulp-api-svc 24817:24817 &curl -s http://localhost:24817/pulp/api/v3/status/ | headA 200 response listing the components (
core,file,container...) confirms that the instance is operational.
Troubleshooting
| Symptom | Cause | Solution |
|---|---|---|
Operator stuck, could not find any storage definition for Database | postgres_storage_class missing | Add it under database: in the Pulp resource |
pulp-api in CrashLoopBackOff, log PostgreSQL 14 or later is required | PostgreSQL 13 image, the chart default | Pin postgres:15 at installation and in the CR |
pulp-database in CrashLoop, data directory ... version X ... not compatible | Leftover PVC from another major version | Delete the Pulp resource and the PVC, redeploy |
PulpBackup fails, Failed to run pg_dump | Database on 16 against a pg_dump 15 | Use PostgreSQL 15 for the database |
api/worker pods Pending on volume | ReadWriteOnce on a multi-node cluster | Switch to ReadWriteMany or to S3 object storage |
Key takeaways
- On Kubernetes, Pulp is deployed through the Pulp Operator and a declarative
Pulpcustom resource. - The Helm chart pins old versions: override the operator image (2.0) and PostgreSQL (15) at installation.
- The operator provisions the whole stack: API, content, workers, PostgreSQL, Redis, reverse proxy.
postgres_storage_classis mandatory; PostgreSQL 15 satisfies pulpcore and the backup tool.- In multi-node production, artifact storage must be
ReadWriteManyor S3, never localReadWriteOnce.
Knowledge check
Six questions on what the operator provisions, what it does not take off your hands, and the storage access mode that decides whether the instance holds on several nodes.
Knowledge check
Check what you have learned with this interactive quiz
How it works
- The timer starts when you click Start
- Multiple choice, true/false and short answer questions
- You can move between questions
- Detailed results are shown at the end
Starts the quiz and the timer
Review
(0/0)Score by domain
A domain groups several guides and gets several questions, so its score is more reliable than a per-topic score, which often rests on a single question.
Summary
Strengths
No topic passed at 80% on at least two questions yet.
Weak areas
No topic below the pass mark.
Recommended next
Hints before you try again?
Continue the course: Nexus Repository: the DevOps artifact manager
A new full quiz with random questions
Work again only on the questions you missed