Using Reis in CI/CD Pipelines
Reis is designed to work in automated environments. Use environment variables for authentication, JSON output for machine-readable results, and YAML files for declarative deployments.
Authentication in CI/CD
Set the REIS_TOKEN environment variable with your personal access token:
export REIS_TOKEN=pat_abc123...
When REIS_TOKEN is set, Reis uses it automatically without requiring reis auth:login. The token never appears in shell history or config files.
You can also set the API URL if needed:
export REIS_API_URL=https://api.bahriya.cloud/console/v1
Storing the token
Store your PAT as a secret in your CI/CD platform:
- GitHub Actions: Repository or environment secret
- GitLab CI: CI/CD variable (masked)
- Concourse: Credential manager (Vault, CredHub)
- Jenkins: Credentials store
Exit codes
Reis uses distinct exit codes to help pipelines differentiate between errors:
| Code | Meaning |
0 | Success |
1 | General error |
2 | Authentication failure |
Use exit code 2 to detect credential problems:
reis container:list --project my-project --output json
EXIT_CODE=$?
if [ $EXIT_CODE -eq 2 ]; then
echo "Auth failed — check REIS_TOKEN"
exit 1
elif [ $EXIT_CODE -ne 0 ]; then
echo "Command failed"
exit 1
fi
Output formats
Use --output json for machine-readable output:
# Get container details as JSON
reis container:show web-api --project my-project --output json
# Pipe to jq
reis container:list --project my-project --output json | jq '.[].handle'
YAML output is also available:
reis container:show web-api --project my-project --output yaml
Using the Docker image
For container-first pipelines, the easiest option is the public Reis image at 1x.ax/bahriya/library/reis. It's multi-arch (linux/amd64, linux/arm64), has reis as its entrypoint, and ships with git and ca-certificates already installed — so you can clone, build, and apply in a single image.
Pin a specific tag in CI so an upstream release cannot change your build:
docker pull 1x.ax/bahriya/library/reis:0.1.10
Use :latest only for ad-hoc local invocations.
Example: GitHub Actions
Using the shell installer
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Reis
run: curl -sSL https://get.bahriya.cloud/reis | bash
- name: Deploy infrastructure
env:
REIS_TOKEN: ${{ secrets.BAHRIYA_PAT }}
run: |
reis apply -f infrastructure.yml
Using the Docker image
Run the job inside the Reis container — no install step needed:
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
container:
image: 1x.ax/bahriya/library/reis:0.1.10
steps:
- uses: actions/checkout@v4
- name: Deploy infrastructure
env:
REIS_TOKEN: ${{ secrets.BAHRIYA_PAT }}
run: reis apply -f infrastructure.yml
Example: GitLab CI
Using the shell installer
deploy:
stage: deploy
image: ubuntu:latest
before_script:
- curl -sSL https://get.bahriya.cloud/reis | bash
script:
- reis apply -f infrastructure.yml
variables:
REIS_TOKEN: $BAHRIYA_PAT
only:
- main
Using the Docker image
deploy:
stage: deploy
image: 1x.ax/bahriya/library/reis:0.1.10
script:
- reis apply -f infrastructure.yml
variables:
REIS_TOKEN: $BAHRIYA_PAT
only:
- main
Example: Deploying a new image version
A common pattern is updating a container image after building and pushing:
#!/usr/bin/env bash
set -eo pipefail
IMAGE_TAG="${CI_COMMIT_SHA:0:8}"
IMAGE="ghcr.io/myorg/api:${IMAGE_TAG}"
# Build and push the image (your existing CI step)
docker build -t "${IMAGE}" .
docker push "${IMAGE}"
# Update the container on Bahriya
reis container:update web-api \
--project my-project \
--image "${IMAGE}" \
--output json
Example: Declarative deployment with YAML
Maintain your infrastructure as YAML files in your repository:
infra/
secrets.yml
registries.yml
containers.yml
Or combine everything in one file:
# infra/production.yml
kind: secret
project: my-project
handle: db-url
name: Database URL
value: "${DB_URL}" # Note: env var substitution is NOT supported in YAML
# Use the API or interactive mode for dynamic secrets
---
kind: container
project: my-project
handle: web-api
name: Web API
image: ghcr.io/myorg/api:v2.0.0
regions:
- falkenstein-1
- virginia-1
workload:
cpu: "500"
memory: "512"
port: "8080"
healthcheck: /healthz
scaling:
replicas: "2"
max_replicas: "8"
autoscalingtargetcpu: "70"
Then apply in your pipeline:
reis apply -f infra/production.yml
Dry run in CI
Use --dry-run as a validation step before actual deployment:
# Validate step (no auth needed)
reis apply -f infrastructure.yml --dry-run
# Deploy step
reis apply -f infrastructure.yml
Tips