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.

Updated 8 Jun 20264 min read

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:

CodeMeaning
0Success
1General error
2Authentication 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

  • Always use --output json when parsing command output in scripts
  • Use --dry-run as a validation gate before deploying
  • Store PATs as CI secrets, never in code or config files
  • Check exit code 2 to detect and handle auth failures separately
  • Pin the Reis version in CI. With the shell installer:
    curl -sSL https://get.bahriya.cloud/reis | bash -s -- --version 0.1.10
    With the Docker image, pin a specific tag rather than :latest:
    docker pull 1x.ax/bahriya/library/reis:0.1.10