Integrate Zyra with your CI/CD
Chapter 5 · about 20 minutes to read
Manual deploys are fine for the first month. After that, every change to your application should flow through CI. This chapter shows the patterns we see most often: spin a VS for an integration test, deploy from a release tag, and tear down everything when CI exits.
Time: about 20 minutes. Prerequisites: an API key from Chapter 1. At least one CI provider account.
The pattern
Three jobs in your pipeline:
- Build. Build and push your Docker image to a registry Zyra can pull from. Zyra's container registry (
/api/v1/registry) is one option; Docker Hub, GHCR, ECR all work. - Deploy.
POST /api/v1/virtual-serverswith the image. Poll status untilrunning. - Tear down (on failure or after tests).
DELETE /api/v1/virtual-servers/{id}orPOST .../stopfor ephemeral runs.
GitHub Actions example
Save this as .github/workflows/deploy-zyra-vs.yml:
name: deploy-to-zyra
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
env:
ZYRA_API_KEY: ${{ secrets.ZYRA_API_KEY }}
ZYRA_BASE: https://app.getzyra.io/api/v1
IMAGE: ghcr.io/${{ github.repository }}:${{ github.sha }}
steps:
- uses: actions/checkout@v4
- name: Build and push image
run: |
echo "${{ secrets.GHCR_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
docker build -t "$IMAGE" .
docker push "$IMAGE"
- name: Deploy Virtual Server
id: deploy
run: |
VS_ID=$(curl -fsS -X POST "$ZYRA_BASE/virtual-servers" \
-H "Authorization: Bearer $ZYRA_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"name\":\"prod-${{ github.sha }}\",\"docker_image\":\"$IMAGE\",\"vcpus\":2,\"memory_mb\":4096,\"disk_gb\":50}" \
| jq -r '.data.id')
echo "vs_id=$VS_ID" >> $GITHUB_OUTPUT
- name: Wait for running
run: |
for i in {1..30}; do
STATUS=$(curl -fsS "$ZYRA_BASE/virtual-servers/${{ steps.deploy.outputs.vs_id }}" \
-H "Authorization: Bearer $ZYRA_API_KEY" | jq -r '.data.status')
[ "$STATUS" = "running" ] && exit 0
[ "$STATUS" = "error" ] && exit 1
sleep 10
done
exit 1
- name: Teardown on failure
if: failure()
run: |
curl -fsS -X DELETE \
"$ZYRA_BASE/virtual-servers/${{ steps.deploy.outputs.vs_id }}" \
-H "Authorization: Bearer $ZYRA_API_KEY" || true
That's the minimal, honest version: build → deploy → poll for running → clean up on failure.
GitLab CI
Same shape, different syntax. Store ZYRA_API_KEY and IMAGE as protected CI variables and POST to $ZYRA_BASE/virtual-servers from a script: block, capturing the VS ID into a dotenv artifact for later jobs.
Jenkins (declarative pipeline)
pipeline {
agent any
environment {
ZYRA_API_KEY = credentials('zyra-api-key')
ZYRA_BASE = 'https://app.getzyra.io/api/v1'
}
stages {
stage('Deploy') {
steps {
sh 'curl -fsS -X POST "$ZYRA_BASE/virtual-servers" -H "Authorization: Bearer $ZYRA_API_KEY" -d "..."'
}
}
}
}
Secrets — the only rule
Never hardcode ZYRA_API_KEY in a file that lives in your repo. Use the CI provider's secret store: GitHub Actions Secrets, GitLab CI variables, Jenkins Credentials Plugin, AWS Secrets Manager. Treat the key like a database password — it has full write access to your org. Rotate every 90 days.
Declarative deploys
For full Infrastructure-as-Code, two routes are wired today:
- Terraform.
POST /api/v1/terraform/...endpoints expose a state-aware deploy surface. A first-party provider is on the roadmap.[VERIFY: provider publication target] - GitOps.
/api/v1/gitopsrouters connect a Git repository to your Zyra org, so a push tomaintriggers a deploy. Useful if you already run Argo CD or Flux.
For now, the curl recipes above are the recommended pattern.
What just happened
You wired a build → deploy → teardown loop with API-key auth, and you know where to keep secrets. Next chapter covers running dev / staging / prod side-by-side.
Troubleshooting
- Polling hits a
404. The VS was likely auto-terminated by an SLA breach. Check audit log (Chapter 4). docker_imagepulls fail. Zyra's runtime needs registry credentials. Configure viaPOST /api/v1/registry/credentials.- Teardown leaks resources. Always wrap the deploy in
if: failure()or atrap— orphaned VSs continue billing.
Last reviewed: 2026-05-21