Table of contents
@abgov/nx-oc
Nx plugin for generating and applying OpenShift manifests for Government of Alberta applications.
The plugin provides generators for CI/CD pipeline setup, per-application deployment configuration, and sandbox deployments for rapid local iteration. An executor handles running oc apply against an OpenShift cluster.
Installation
npm i -D @abgov/nx-oc
Prerequisites
- OpenShift CLI (
oc) installed and onPATH - An active OpenShift login:
oc login <url> --token=<token> - Separate OpenShift projects provisioned for build infrastructure and each runtime environment (dev, test, prod)
- GitHub CLI (
gh) installed and authenticated (gh auth login) — required when usingpipeline --apply
Generators
pipeline
Generates OpenShift manifests for a CI/CD pipeline, including shared build infrastructure resources used across all environments.
npx nx g @abgov/nx-oc:pipeline my-pipeline \
--infra my-infra-project \
--envs "my-dev my-test my-prod"
| Option | Alias | Required | Description |
|---|---|---|---|
pipeline | — | Yes | Name of the OpenShift pipeline |
infra | -i | Yes | OpenShift project name used for build infrastructure |
envs | -e | Yes | Space-separated names of the OpenShift environment projects (e.g. "my-dev my-test my-prod") |
registry | -r | No | Container registry to publish images to (e.g. ghcr.io/my-org). Derived automatically from the git remote when not provided. |
type | -t | No | Pipeline type: actions (default) or jenkins |
apply | -a | No | Apply the generated manifests to OpenShift and run automated secrets setup |
The generator creates the following files:
.github/
└─ pipeline.yml
.openshift/
├─ environment.infra.yml
└─ environments.yml
When --apply is set, the generator also:
- Applies the infrastructure manifests to OpenShift
- Sets
OPENSHIFT_SERVERandOPENSHIFT_TOKENas GitHub Actions secrets automatically - Prompts once for a GitHub classic PAT with
read:packagesscope, creates the GHCR pull secret in the infra project, and links it to thegithub-actionsservice account
apply-infra
Applies the OpenShift infrastructure manifests that were generated by pipeline. Takes no options — reads the generated pipeline configuration from the workspace.
npx nx g @abgov/nx-oc:apply-infra
Use this as a follow-up to pipeline when you want to defer cluster provisioning, or to re-apply manifests after editing them manually.
setup-secrets
Sets GitHub Actions secrets (OPENSHIFT_SERVER, OPENSHIFT_TOKEN) and creates the GHCR pull secret in OpenShift for an existing pipeline. Run this if the pipeline was generated without --apply, or to re-run secrets setup independently.
npx nx g @abgov/nx-oc:setup-secrets --infra my-infra-project
| Option | Required | Description |
|---|---|---|
infra | Yes | OpenShift project name used for build infrastructure |
Requires oc to be logged in and gh CLI to be authenticated.
deployment
Adds OpenShift deployment manifests (Deployment, Service, Route, ImageStream) to an existing Nx project for a specific environment. Generated manifests include liveness and readiness probes.
npx nx g @abgov/nx-oc:deployment my-app --appType node --env dev
| Option | Alias | Required | Description |
|---|---|---|---|
project | — | Yes | Name of the existing Nx project to add deployment manifests to |
appType | -t | Yes | Application type: frontend, dotnet, or node |
env | -e | Yes | ADSP environment: dev, test, or prod |
database | — | No | Database type used by the service: postgres, mongo, or none (default). When set, the manifest includes the appropriate secretKeyRef for the connection string and a migration init container (node migrate.js) for postgres. |
accessToken | -at | No | Access token for non-interactive retrieval of ADSP configuration |
Run the generator once per environment per application. For a typical three-environment setup, run it three times with --env dev, --env test, and --env prod.
deployment writes .openshift/<project>/<project>.yml; sandbox writes .openshift/<project>/<project>.sandbox.yml alongside it and shares the same .openshift/<project>/Dockerfile (identical either way). A project can have both — a real CI-driven pipeline deployment and a sandbox for local experimentation — at the same time; running one never touches the other’s manifest. Every object either renders also carries a deployment-mode: pipeline/sandbox label (alongside the existing app label), so the teardown-<env> and sandbox-teardown targets’ label-selector deletes can never remove the other mode’s resources even if they ever land in the same namespace.
The database connection secret must be created manually in each environment project before the first deploy:
# postgres
oc create secret generic my-app-database \
--from-literal=DATABASE_URL='postgresql://user:pass@host:5432/dbname' \
-n my-env-project
# mongo
oc create secret generic my-app-database \
--from-literal=MONGODB_URI='mongodb://user:pass@host:27017/dbname' \
-n my-env-project
Note: when @abgov/nx-adsp generators create a new application and @abgov/nx-oc is installed, the deployment generator is called automatically. Use deployment directly to add OpenShift manifests to an existing project.
sandbox
Generates a sandbox deployment for rapid local iteration — no git push or CI wait required. Builds the container image locally with podman, pushes it to a container registry (GHCR), and imports it into a sandbox namespace in a single command.
npx nx g @abgov/nx-oc:sandbox my-app --sandboxProject my-sandbox-ns
npx nx g @abgov/nx-oc:sandbox my-app-service --sandboxProject my-sandbox-ns --database postgres
| Option | Alias | Required | Description |
|---|---|---|---|
project | — | Yes | Name of the existing Nx project |
sandboxProject | -s | Yes | OpenShift namespace to deploy the sandbox into (expected to be per-user) |
appType | -t | No | Application type: frontend, dotnet, or node. Inferred from the project build executor when not provided. |
database | — | No | Database type: postgres, mongo, or none (default). postgres provisions via the CloudNativePG operator when the CRD is present and falls back to a plain Deployment otherwise; mongo always uses a plain Deployment. |
env | — | No | ADSP environment to target for configuration: dev (default), test, or prod |
registry | -r | No | Container registry for sandbox images (e.g. ghcr.io/my-org). Resolved once and persisted to nx.json; derived from the git remote when not provided. |
Prerequisites (local build, one-time):
podmaninstalled.gh auth loginas an account withwrite:packageson the registry org (the same login supplies both the push and the per-deploy pull secret — no PAT is stored).
The generator adds sandbox and sandbox-teardown targets to the project and creates:
.openshift/
├─ my-app/
│ ├─ Dockerfile ← built locally by the sandbox target (shared with `deployment`)
│ └─ my-app.sandbox.yml ← sandbox deployment manifest (coexists with `deployment`'s my-app.yml)
└─ sandbox/
├─ sandbox-postgres.yml ← plain Deployment fallback (used when CNPG operator absent)
├─ sandbox-postgres-cnpg.yml ← CNPG Cluster manifest (used when operator present; postgres only)
└─ my-app-db.yml ← CNPG Database CR creating the per-app database (postgres only)
Running nx run my-app:sandbox executes the full loop:
- Creates the ADSP client Secret (node); provisions the database (idempotent): for
postgres, probes for theclusters.postgresql.cnpg.ioCRD — if present, grants the CNPG SA therestricted-v2SCC, applies thesandbox-postgresCNPG Cluster and a per-appDatabaseCR; if absent but no CNPG Cluster has ever been created, falls back to a plain Deployment and createssandbox-postgres-app/sandbox-postgres-rwcompatibility shims so the app manifest works either way;mongoalways uses a plain Deployment. nx build→podman build --platform=linux/amd64→podman pushto<registry>/<sandboxProject>-<app>:sandbox.- Refreshes the
ghcr-pullSecret from the currentghsession token. oc tag+oc import-image --reference-policy=local— the internal registry serves the image, so pods pull in-cluster (no per-pod pull secret, no node egress).- Applies the manifest, restarts the Deployment, waits for rollout.
Local layer caching makes iteration fast — after the first push, only the changed app layer is re-uploaded.
Registry & naming: the image name is prefixed with the (per-user) sandboxProject — <registry>/<sandboxProject>-<app>:sandbox — so images from different experimenters never collide on GHCR’s org-global package namespace. Sandbox packages are not repo-linked (only Actions-published packages are), so they’re identifiable as the org’s unlinked container packages:
gh api "/orgs/<org>/packages?package_type=container" -q '.[] | select(.repository == null) | .name'
Shared database: All apps in the same sandbox namespace share one Postgres or MongoDB instance. Each app gets its own database (<appName>_sandbox); migrations run on deploy via the app’s init container. For Postgres on GoA ARO, the executor uses the CloudNativePG operator (a single sandbox-postgres Cluster CR, one PVC via the azure-disk storage class), with a per-app Database CR to declaratively create the database. When the operator is absent the executor falls back to a plain Deployment; both paths leave identical sandbox-postgres-app Secret and sandbox-postgres-rw Service in the namespace so the app manifest is format-stable regardless of which path ran. One-way door: if a CNPG Cluster already exists but the CRD is no longer responding, the executor fails fast rather than creating a conflicting plain Deployment alongside it.
Teardown: nx run my-app:sandbox-teardown deletes the app’s OpenShift resources and its GHCR package (best-effort; deleting the package needs delete:packages). The shared database and its PVC are left in place — other apps in the namespace may still be using them. To remove the shared Postgres manually (CNPG path):
# Remove per-app Database CR first
oc delete -f .openshift/sandbox/my-app-db.yml -n <sandbox-namespace>
# Then remove the shared Cluster (deletes PVC and all CNPG-managed secrets)
oc delete -f .openshift/sandbox/sandbox-postgres-cnpg.yml -n <sandbox-namespace>
For the plain Deployment fallback:
oc delete -f .openshift/sandbox/sandbox-postgres.yml -n <sandbox-namespace>
oc delete secret sandbox-postgres-creds sandbox-postgres-app -n <sandbox-namespace>
oc delete service sandbox-postgres-rw -n <sandbox-namespace>
teardown
Adds a teardown-<env> target to an existing project that removes the application’s runtime resources (Deployment, Service, Route, ConfigMap) from a specific OpenShift environment. Run the generator once per environment you want a teardown target for.
npx nx g @abgov/nx-oc:teardown my-app --env dev
npx nx g @abgov/nx-oc:teardown my-app --env prod
| Option | Alias | Required | Description |
|---|---|---|---|
project | — | Yes | Name of the existing Nx project |
env | -e | Yes | Environment to target: dev, test, or prod |
Running nx run my-app:teardown-dev runs oc delete all,configmap -l app=<name> against the environment’s OpenShift project. The label selector matches every resource the deployment template created — if new resource types are added to the template in future, they are cleaned up automatically. --ignore-not-found makes it safe to run even if resources are partially absent.
Note: The ImageStream in the infra project is not removed — it is shared across environments and managed separately. To remove it:
oc delete imagestream <app-name> -n <infra-project>
Note: Teardown targets delete resources immediately with no confirmation prompt. The target name (e.g. teardown-prod) is the safeguard — run only what you intend.
Executor: apply
Runs oc apply to deploy an application’s OpenShift manifests. Configure it as a target in the project’s project.json:
{
"targets": {
"deploy": {
"executor": "@abgov/nx-oc:apply",
"options": {
"ocProject": "my-dev-project"
}
}
}
}
Then run:
npx nx run my-app:deploy
Executor options
| Option | Required | Description |
|---|---|---|
ocProject | Yes | OpenShift project(s) to apply manifests to |
ocProject accepts three forms:
// Single project
{ "ocProject": "my-dev" }
// Multiple projects
{ "ocProject": ["my-dev", "my-test"] }
// Tagged deployments
{ "ocProject": [{ "project": "my-dev", "tag": "v1.2.3" }] }
Typical workflow
Production pipeline
- Run
pipelineonce per workspace to generate shared build infrastructure manifests. - Pass
--applyto provision the cluster, set GitHub secrets, and configure the GHCR pull secret in one step. Or runapply-infraandsetup-secretsseparately to defer or re-run either step. - Run
deploymentfor each application and environment combination, passing--databaseif the app uses Postgres or MongoDB. - In your GitHub Actions pipeline,
nx run my-app:apply-envsapplies manifests during CI/CD.
Sandbox iteration
- Run
sandboxfor each application, passing--sandboxProjectand--databaseas needed. - Run
nx run my-app:sandboxto build, push, and deploy. Repeat on every change.