.ankra/pipeline.yaml, or a stage you add to one. The test pipelines, the cache, the Postgres service, the matrix and the secret were each run on a real Ankra pipeline cluster before they were published, against a small project of each kind.
New to Ankra CI? Start with Get started with Ankra CI, which connects the repository and gets the first run green.
Three rules every step follows
A pipeline step is a container on your cluster, and three things about it differ from a CI runner or your laptop. Every recipe below already handles them, and anything you write yourself needs to as well:- No network unless you ask. A
runstage has no network access by default.defaults.network: "egress-https"gives every stage HTTPS to the public internet, which is what installing packages needs. Private addresses stay out of reach unless an administrator allows them. - A read-only root filesystem, and a non-root user. A step cannot install system packages or write into the image, so
apt-get installandcorepack enablefail. Use an image that already has your tools in it.HOMEis/tmp: writable, but 256 MiB and held in memory, so send package caches and build output to/workspaceinstead. - One shared workspace.
/workspaceholds the checkout and is shared by every stage of the run, so what one stage installs there, the next can use./tmpis private to each step and starts empty.
Test pipelines by toolchain
All of these run on pushes tomain, pull requests into main and manual runs. Change branches to match your default branch.
- npm
- pnpm
- Yarn
- Python (pip)
- Python (uv)
- Go
- Rust
package-lock.json.Make it faster with caches
Without a cache, every run downloads its dependencies again. Acache block keeps directories of the workspace between runs, keyed on your lock file, so a run whose lock file did not change starts warm.
Add it to the stage that installs, pointing at the same directories its env sends the package manager’s cache to. For the npm pipeline above:
Use the key’s prefix as its
restore_keys entry (npm-, go-), so a changed lock file still starts from the newest older cache.
Caches need approval. A cache decides whose earlier output is copied into a run, so the
cache block is a protected setting: it takes effect once an administrator approves the pipeline on the default branch. Until then the stage runs cold and the run says so. The step’s CACHE column in ankra pipeline get shows miss on the first run and hit from then on. Caches covers keys, scopes and retention.Give a step more memory or time
Every step gets 500m of CPU, 1Gi of memory and 30 minutes unless the stage asks for more. A large JavaScript install, a TypeScript build or a big test suite often needs more memory - a step killed at its limit fails with the diagnosisout_of_memory.
resources and timeout are protected settings, so they apply once an administrator approves them. One step can ask for up to 8 CPU cores, 32Gi of memory and 6 hours.
Test against a Postgres database
A service is a sidecar container next to your test step, reachable by its name. This pipeline installs dependencies in one stage with internet access, then runs the tests in a second stage on theservices network tier, which reaches the database and nothing else:
- Use a Debian-based Postgres image such as
postgres:17, not an Alpine one. The sidecar also runs as a non-root user, and the Debian image’s entrypoint is the one that can initialise a database that way. - Set
PGDATAto a subdirectory. The image’s own data directory belongs to another user, and Postgres cannot take it over, so the sidecar would restart in a loop and the step would never start. - Install before you switch to
services. Theservicestier has no internet access, so a package install in the test stage fails. Install in an earlier stage onegress-httpsand reuse what it left in/workspace.
ready probe holds the test step until Postgres accepts connections. The password here is for this throwaway database only - use a pipeline secret (below) for anything real. services, the services network tier, cache and resources are protected, so approve the pipeline before you rely on them.
Test against several versions
Amatrix runs one stage once per value, in parallel:
test:node=20, test:node=22, test:node=24. Give each leg its own cache directory, as above, because the legs share the workspace and run at the same time. A matrix takes include and exclude lists as GitHub Actions does, up to 64 legs per stage.
Use a secret in a step
Store the value in Ankra once, as an organisation variable - Variables and secrets in the portal, or from the CLI, which reads the value from standard input so it stays out of your shell history:/run/agent-secrets/<name>, not as an environment variable, and never appears in the pipeline or a log. from is org_variable for an organisation or cluster variable, app_env_secret for the linked application’s environment secret, or registry for a registry login. Only the stages that list a secret can read it, and pull requests from forks get none.
secrets is a protected setting. Merge the declaration to the default branch and approve it before the first run that needs it - a pull request that adds a secret runs without it until then.
Run every night
Declare the schedule in the pipeline, then create it once:--ref. To run only your slow suites at night, give the schedule entry a stages list, and include checkout and every stage those suites need. An application’s Pipelines page in the portal has Scheduled runs as well, to create, pause or delete one.
Build, scan and publish an image
For a repository linked to an Ankra application, the pipeline can build the container image, scan it and publish it to your organisation’s registry. Nothing reaches the registry until the gate has passed the exact image that was scanned. Add these stages after your tests:buildbuilds the image rootless, inside your cluster, and stores it by digest in a staging area of your registry. A pull request’s build is built and scanned but not published.scanruns Semgrep and Checkov over your source and Trivy over the image. The reports go to the run and to the application’s Security tab.gatejudges what the scanners found against your organisation’s image policy - by default, fixable critical and high vulnerabilities in your own dependencies block.fail_oncan make one pipeline stricter, never looser.publishtags the exact digest the gate passed assha-<first 7 characters of the commit>in your application’s repository, only on pushes to the default branch. Your application deploys that tag.
build and scan reach the internet by default, so they need no network line, and gate and publish run on the Ankra platform rather than in a pod. If your nodes stop the rootless builder from starting, Ankra builds the image on its own platform builders instead, and the scan and gate still run on your cluster. A new application’s setup pull request commits these stages for you.
A monorepo
For a repository with several components, give each component its own test stage with a path filter for pull requests, so a pull request only tests what it touches and a push tomain tests everything. Monorepo: PR-only checks, full builds on push has the full pattern.
Related
- Get started with Ankra CI - connect a repository and get the first run green
- Troubleshooting - what a failing first pipeline usually means
- Pipeline reference - every key, trigger, stage kind and expression