Pular para o conteúdo

Spacelift Cheat Sheet

Overview

Spacelift is a sophisticated infrastructure-as-code (IaC) management platform that provides CI/CD workflows specifically designed for infrastructure tools including Terraform, OpenTofu, Pulumi, CloudFormation, Kubernetes, and Ansible. It goes beyond simple automation by offering policy-as-code governance using Open Policy Agent (OPA), drift detection, resource visualization, cost estimation, and fine-grained access controls that make it suitable for enterprise infrastructure management at scale.

The platform organizes infrastructure into “stacks” that represent independent deployment units, with support for stack dependencies, shared contexts for common configurations, and worker pools for executing runs in private networks. Spacelift’s approval workflows, plan policies, and push policies enable organizations to enforce guardrails on infrastructure changes while still empowering developers to self-serve their infrastructure needs.

Installation

Spacelift CLI (spacectl)

# macOS
brew install spacelift-io/spacelift/spacectl

# Linux
curl -fsSL https://github.com/spacelift-io/spacectl/releases/latest/download/spacectl-linux-amd64 -o /usr/local/bin/spacectl
chmod +x /usr/local/bin/spacectl

# Verify
spacectl version

# Login to Spacelift
spacectl profile login https://your-account.app.spacelift.io

# Configure API token
export SPACELIFT_API_KEY_ENDPOINT="https://your-account.app.spacelift.io"
export SPACELIFT_API_KEY_ID="your-key-id"
export SPACELIFT_API_KEY_SECRET="your-key-secret"

Worker Pool (Self-Hosted Runners)

# Deploy a private worker pool (Docker)
docker run -d \
  --name spacelift-worker \
  -e SPACELIFT_TOKEN="worker-pool-token" \
  -e SPACELIFT_POOL_PRIVATE_KEY="base64-encoded-private-key" \
  -v /var/run/docker.sock:/var/run/docker.sock \
  public.ecr.aws/spacelift/launcher:latest

# Deploy worker pool on Kubernetes
helm repo add spacelift https://downloads.spacelift.io/helm
helm repo update

helm install spacelift-worker spacelift/spacelift-worker-pool \
  --namespace spacelift \
  --create-namespace \
  --set credentials.token="worker-pool-token" \
  --set credentials.privateKey="base64-private-key" \
  --set replicas=3

Core Commands — Stack Management

Managing Stacks via CLI

# List all stacks
spacectl stack list

# Get stack details
spacectl stack show --id "my-stack"

# Create a stack
spacectl stack create \
  --name "production-vpc" \
  --repository "org/infrastructure" \
  --branch "main" \
  --project-root "terraform/vpc" \
  --terraform-version "1.7.0" \
  --administrative

# Trigger a run
spacectl stack run trigger --id "production-vpc"

# Confirm a run (approve pending apply)
spacectl stack run confirm --id "production-vpc" --run "run-id"

# Discard a pending run
spacectl stack run discard --id "production-vpc" --run "run-id"

# Set stack environment variable
spacectl stack environment set --id "production-vpc" \
  --name "AWS_REGION" --value "us-east-1"

# Set sensitive variable
spacectl stack environment set --id "production-vpc" \
  --name "DB_PASSWORD" --value "secret" --secret

# Deploy a stack
spacectl stack deploy --id "production-vpc"

# Lock a stack (prevent changes)
spacectl stack lock --id "production-vpc" --note "Maintenance window"

# Unlock a stack
spacectl stack unlock --id "production-vpc"

Managing Runs

# List runs for a stack
spacectl stack run list --id "production-vpc"

# Get run details
spacectl stack run show --id "production-vpc" --run "run-id"

# View run logs
spacectl stack run logs --id "production-vpc" --run "run-id"

# List all currently running/pending runs
spacectl stack run list --id "production-vpc" --state "QUEUED,PLANNING,APPLYING"

# Get run resources (what will change)
spacectl stack run resources --id "production-vpc" --run "run-id"

Core Commands — GraphQL API

Stack Operations

# Spacelift uses a GraphQL API
SPACELIFT_API="https://your-account.app.spacelift.io/graphql"

# List stacks
curl -s "$SPACELIFT_API" \
  -H "Authorization: Bearer $SPACELIFT_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "{ stacks { id name state branch repository projectRoot } }"
  }' | jq '.data.stacks[]'

# Trigger a run
curl -s "$SPACELIFT_API" \
  -H "Authorization: Bearer $SPACELIFT_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation { stackRunTrigger(stack: \"production-vpc\") { id state } }"
  }'

# Get stack resources
curl -s "$SPACELIFT_API" \
  -H "Authorization: Bearer $SPACELIFT_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "{ stack(id: \"production-vpc\") { trackedResources { count } currentRun { id state } } }"
  }'

Configuration

Stack Configuration (Terraform)

# .spacelift/config.yml — Stack configuration in repo
version: "1"

stacks:
  production-vpc:
    name: "Production VPC"
    project_root: "terraform/vpc"
    terraform_version: "1.7.0"
    labels:
      - "environment:production"
      - "team:platform"
    environment:
      variables:
        - name: AWS_REGION
          value: us-east-1
        - name: TF_VAR_environment
          value: production
    before_init:
      - "echo 'Initializing VPC stack'"
    after_apply:
      - "curl -X POST https://hooks.slack.com/services/T00/B00/xxx -d '{\"text\": \"VPC deployed\"}'"
    auto_deploy: true
    auto_retry: true

  production-eks:
    name: "Production EKS"
    project_root: "terraform/eks"
    terraform_version: "1.7.0"
    dependencies:
      - production-vpc
    labels:
      - "environment:production"
      - "team:platform"
    worker_pool: "private-workers"

Contexts (Shared Configuration)

# Create a shared context
spacectl context create \
  --name "aws-production" \
  --description "AWS production account credentials"

# Add variables to context
spacectl context environment set --id "aws-production" \
  --name "AWS_ACCESS_KEY_ID" --value "AKIA..." --secret
spacectl context environment set --id "aws-production" \
  --name "AWS_SECRET_ACCESS_KEY" --value "secret" --secret
spacectl context environment set --id "aws-production" \
  --name "AWS_REGION" --value "us-east-1"

# Attach context to a stack
spacectl stack context attach --id "production-vpc" --context "aws-production"

# Auto-attach context to stacks by label
spacectl context create \
  --name "datadog-monitoring" \
  --auto-attach "environment:production"

Policy-as-Code (OPA)

# plan-policy.rego — Enforce infrastructure guardrails
package spacelift

# Deny destroying production databases
deny["Cannot destroy production databases"] {
  resource := input.terraform.resource_changes[_]
  resource.type == "aws_db_instance"
  resource.change.actions[_] == "delete"
  contains(resource.address, "production")
}

# Require tags on all resources
warn["Resource missing required tags"] {
  resource := input.terraform.resource_changes[_]
  resource.change.actions[_] == "create"
  not resource.change.after.tags["Environment"]
}

# Limit instance sizes
deny[msg] {
  resource := input.terraform.resource_changes[_]
  resource.type == "aws_instance"
  resource.change.actions[_] == "create"
  instance_type := resource.change.after.instance_type
  contains(instance_type, "metal")
  msg := sprintf("Bare metal instances not allowed: %s", [instance_type])
}

# Cost threshold
deny[msg] {
  cost := input.spacelift.cost_estimate.monthly_cost
  cost > 10000
  msg := sprintf("Monthly cost $%.2f exceeds $10,000 limit", [cost])
}
# Create a plan policy
spacectl policy create \
  --name "infrastructure-guardrails" \
  --type "PLAN" \
  --body-file plan-policy.rego

# Attach policy to stacks by label
spacectl policy create \
  --name "tag-enforcement" \
  --type "PLAN" \
  --body-file tag-policy.rego \
  --auto-attach "environment:production"

Push Policy (Control Which Pushes Trigger Runs)

# push-policy.rego
package spacelift

# Only trigger on changes to the stack's project root
track {
  affected := input.push.affected_files[_]
  startswith(affected, input.stack.project_root)
}

# Ignore documentation changes
ignore {
  input.push.affected_files[_] == "README.md"
}

# Auto-deploy on main branch
propose { input.push.branch != input.stack.branch }
track { input.push.branch == input.stack.branch }

Advanced Usage

Stack Dependencies

# Create dependent stacks (VPC -> EKS -> App)
# Spacelift automatically triggers dependent stacks after parent applies

# Define dependency via CLI
spacectl stack dependency add \
  --id "production-eks" \
  --depends-on "production-vpc"

spacectl stack dependency add \
  --id "production-app" \
  --depends-on "production-eks"

# Pass outputs between stacks using Terraform remote state
# or Spacelift output references

Drift Detection

# Enable drift detection on a stack
spacectl stack update --id "production-vpc" \
  --drift-detection true \
  --drift-detection-schedule "0 */4 * * *"

# Reconcile drift (auto-apply to match desired state)
spacectl stack update --id "production-vpc" \
  --drift-detection-reconcile true

# Check drift status
spacectl stack show --id "production-vpc" | grep drift

Terraform Provider

# Manage Spacelift with Terraform
terraform {
  required_providers {
    spacelift = {
      source  = "spacelift-io/spacelift"
      version = "~> 1.0"
    }
  }
}

resource "spacelift_stack" "vpc" {
  name            = "production-vpc"
  repository      = "org/infrastructure"
  branch          = "main"
  project_root    = "terraform/vpc"
  terraform_version = "1.7.0"
  
  autodeploy      = true
  autoretry       = true
  
  labels = ["environment:production", "team:platform"]
}

resource "spacelift_context" "aws_prod" {
  name        = "aws-production"
  description = "AWS production credentials"
}

resource "spacelift_context_attachment" "vpc_aws" {
  context_id = spacelift_context.aws_prod.id
  stack_id   = spacelift_stack.vpc.id
}

resource "spacelift_policy" "guardrails" {
  name = "infrastructure-guardrails"
  type = "PLAN"
  body = file("policies/guardrails.rego")
}

resource "spacelift_policy_attachment" "guardrails_vpc" {
  policy_id = spacelift_policy.guardrails.id
  stack_id  = spacelift_stack.vpc.id
}

Troubleshooting

IssueCauseSolution
Run stuck in QUEUEDNo available workersCheck worker pool status or add workers
Plan policy blockingOPA policy denying changesReview policy evaluations in run details
Drift detection false positivesState refresh capturing transient changesAdd ignore_changes in Terraform or adjust schedule
Context variables not availableContext not attached to stackVerify context attachment: spacectl stack context list
Dependency run not triggeringDependency not configuredVerify dependency: spacectl stack dependency list
Worker pool disconnectedToken expired or network issueRegenerate worker pool token and restart workers
Terraform init failingMissing provider credentialsCheck context variables and mount files
Stack resources out of syncManual changes outside SpaceliftRun drift detection and reconcile
# Check worker pool status
spacectl worker-pool list

# View run logs for debugging
spacectl stack run logs --id "my-stack" --run "latest"

# List policies attached to a stack
spacectl stack policy list --id "my-stack"

# Evaluate a policy locally
spacectl policy eval --policy-file guardrails.rego --input plan.json

# Check stack health
spacectl stack show --id "my-stack" --json | jq '{state, trackedResources, currentRun}'

# List all active runs
spacectl stack run list --state "PLANNING,APPLYING,QUEUED"