arc-terraform-deployment

Deploy ARC (Actions Runner Controller) infrastructure using Terraform on Rackspace Spot. Handles CRD registration, ArgoCD installation, and namespace management. Use when deploying or troubleshooting ARC infrastructure.

16 stars

Best use case

arc-terraform-deployment is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Deploy ARC (Actions Runner Controller) infrastructure using Terraform on Rackspace Spot. Handles CRD registration, ArgoCD installation, and namespace management. Use when deploying or troubleshooting ARC infrastructure.

Teams using arc-terraform-deployment should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/arc-terraform-deployment/SKILL.md --create-dirs "https://raw.githubusercontent.com/diegosouzapw/awesome-omni-skill/main/skills/devops/arc-terraform-deployment/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/arc-terraform-deployment/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How arc-terraform-deployment Compares

Feature / Agentarc-terraform-deploymentStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Deploy ARC (Actions Runner Controller) infrastructure using Terraform on Rackspace Spot. Handles CRD registration, ArgoCD installation, and namespace management. Use when deploying or troubleshooting ARC infrastructure.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# ARC Runner Terraform Deployment Skill

## Overview

This skill covers Terraform patterns for deploying GitHub Actions Runner Controller (ARC) on Rackspace Spot Kubernetes. Key challenge: managing resources that depend on CRDs installed during the same apply.

## Critical Learning: CRD Installation Timing

### The Problem

When deploying ARC, ArgoCD Applications are CRDs that don't exist until ArgoCD Helm chart is installed. Using `kubernetes_manifest` fails:

```
Error: Provider produced inconsistent result after apply
The CRD "applications.argoproj.io" does not exist
```

### The Solution: Use kubectl_manifest Instead

**WRONG** - kubernetes_manifest validates at plan time:
```hcl
resource "kubernetes_manifest" "argocd_app" {
  manifest = {
    apiVersion = "argoproj.io/v1alpha1"
    kind       = "Application"
    # ...
  }
}
# ERROR: CRD doesn't exist during terraform plan
```

**CORRECT** - kubectl_manifest applies at runtime:
```hcl
resource "kubectl_manifest" "argocd_app" {
  yaml_body = yamlencode({
    apiVersion = "argoproj.io/v1alpha1"
    kind       = "Application"
    # ...
  })

  depends_on = [
    helm_release.argocd,
    time_sleep.wait_for_crds
  ]
}
```

### Why This Works

| Provider | Plan Behavior | Apply Behavior | Use Case |
|----------|---------------|----------------|----------|
| `kubernetes_manifest` | Validates CRD exists | Applies manifest | Resources where CRD pre-exists |
| `kubectl_manifest` | No validation | Runs kubectl apply | Resources where CRD installed in same run |

## Pattern: CRD Registration Wait

After installing Helm charts that provide CRDs, add explicit wait:

```hcl
resource "helm_release" "argocd" {
  name       = "argocd"
  chart      = "argo-cd"
  repository = "https://argoproj.github.io/argo-helm"
  namespace  = "argocd"

  # ... chart configuration
}

resource "time_sleep" "wait_for_crds" {
  depends_on = [helm_release.argocd]

  create_duration = "30s"  # Wait for CRDs to register with K8s API
}

resource "kubectl_manifest" "bootstrap_app" {
  yaml_body = yamlencode({
    apiVersion = "argoproj.io/v1alpha1"
    kind       = "Application"
    # ...
  })

  depends_on = [time_sleep.wait_for_crds]
}
```

**Why 30 seconds?**
- CRDs must register with Kubernetes API server
- API server must propagate to all control plane nodes
- 30s provides safe buffer for registration

## Pattern: Namespace Management

### The Conflict

When both Terraform and ArgoCD try to create namespaces:
1. Terraform creates namespace
2. ArgoCD tries to create namespace with `CreateNamespace=true`
3. Namespace already exists → sync drift

### The Solution: Let ArgoCD Own Namespaces

**WRONG** - Terraform creates namespace:
```hcl
resource "kubernetes_namespace" "arc_runners" {
  metadata {
    name = "arc-runners"
  }
}

resource "kubectl_manifest" "argocd_app" {
  yaml_body = yamlencode({
    # ...
    spec = {
      destination = {
        namespace = "arc-runners"  # Already exists
      }
      syncPolicy = {
        syncOptions = ["CreateNamespace=true"]  # Conflict!
      }
    }
  })
}
```

**CORRECT** - ArgoCD creates namespace:
```hcl
resource "kubectl_manifest" "argocd_app" {
  yaml_body = yamlencode({
    apiVersion = "argoproj.io/v1alpha1"
    kind       = "Application"
    metadata = {
      name      = "arc-runners"
      namespace = "argocd"
    }
    spec = {
      destination = {
        namespace = "arc-runners"  # ArgoCD will create this
      }
      syncPolicy = {
        automated = {
          prune    = true
          selfHeal = true
        }
        syncOptions = ["CreateNamespace=true"]  # ArgoCD manages it
      }
    }
  })
}
```

**Exception: Namespace needs pre-created secrets**

If you need to create secrets BEFORE the application deploys:

```hcl
resource "kubernetes_namespace" "arc_runners" {
  metadata {
    name = "arc-runners"
  }
}

resource "kubernetes_secret" "github_token" {
  metadata {
    name      = "arc-org-github-secret"
    namespace = kubernetes_namespace.arc_runners.metadata[0].name
  }

  data = {
    github_token = var.github_token
  }

  type = "Opaque"
}

resource "kubectl_manifest" "argocd_app" {
  yaml_body = yamlencode({
    # ...
    spec = {
      destination = {
        namespace = "arc-runners"
      }
      syncPolicy = {
        syncOptions = []  # Do NOT include CreateNamespace - we created it
      }
    }
  })

  depends_on = [
    kubernetes_namespace.arc_runners,
    kubernetes_secret.github_token
  ]
}
```

## Common Deployment Patterns

### Pattern 1: ArgoCD Installation

```hcl
module "argocd" {
  source = "./modules/argocd"

  kubeconfig_path     = module.cloudspace.kubeconfig_path
  github_token_secret = var.github_token
  bootstrap_repo_url  = "https://github.com/Matchpoint-AI/matchpoint-github-runners-helm"
}
```

**Module responsibilities:**
1. Install ArgoCD Helm chart
2. Wait for CRDs to register
3. Create bootstrap Application (App-of-Apps)

### Pattern 2: Runner Scale Set Deployment

ArgoCD manages runner deployments via ApplicationSet:

```yaml
# argocd/applicationset.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: github-runners
spec:
  generators:
  - list:
      elements:
      - name: arc-beta-runners
        valuesFile: examples/beta-runners-values.yaml
  template:
    metadata:
      name: '{{name}}'
    spec:
      source:
        repoURL: https://github.com/Matchpoint-AI/matchpoint-github-runners-helm
        targetRevision: main
        path: charts/github-actions-runners
        helm:
          releaseName: '{{name}}'  # CRITICAL: Must match runnerScaleSetName
          valueFiles:
          - '../../{{valuesFile}}'
```

## Troubleshooting

### Error: "Provider produced inconsistent result"

**Symptom:**
```
Error: Provider produced inconsistent result after apply
The CRD "applications.argoproj.io" does not exist
```

**Fix:** Change from `kubernetes_manifest` to `kubectl_manifest`

### Error: "Namespace already exists"

**Symptom:**
```
ArgoCD sync failed: namespace "arc-runners" already exists
```

**Fix:** Remove `CreateNamespace=true` from ArgoCD Application if Terraform created the namespace

### Error: "Application CRD not found"

**Symptom:**
```
kubectl_manifest failed: no matches for kind "Application"
```

**Fix:** Add `time_sleep` resource after ArgoCD Helm release:
```hcl
resource "time_sleep" "wait_for_crds" {
  depends_on      = [helm_release.argocd]
  create_duration = "30s"
}
```

## Diagnostic Commands

```bash
# Check if ArgoCD CRDs are registered
kubectl api-resources | grep argoproj

# Verify ArgoCD installation
kubectl get pods -n argocd

# Check Application CRD definition
kubectl get crd applications.argoproj.io

# View terraform state for ArgoCD resources
cd terraform
terraform state list | grep argocd

# Check for orphaned kubernetes resources
terraform state list | grep kubernetes_
```

## Best Practices

1. **Always use kubectl_manifest for ArgoCD Applications** - They depend on CRDs from the same apply
2. **Add time_sleep after Helm releases that install CRDs** - 30s is safe default
3. **Let ArgoCD manage namespaces when possible** - Reduces terraform/ArgoCD conflicts
4. **Use depends_on explicitly** - Makes dependencies clear and prevents race conditions
5. **Separate infrastructure from application config** - Terraform for infra, ArgoCD for apps

## Related Skills

- [infrastructure-cd](../infrastructure-cd/SKILL.md) - CD workflows for terraform
- [argocd-bootstrap](../argocd-bootstrap/SKILL.md) - App-of-Apps pattern
- [terraform-state-recovery](../terraform-state-recovery/SKILL.md) - Cleaning orphaned state

## Related Issues

- #121 - releaseName/runnerScaleSetName mismatch
- #122 - ApplicationSet fix
- #112 - CI jobs stuck investigation

## References

- [kubectl provider docs](https://registry.terraform.io/providers/gavinbunney/kubectl/latest/docs)
- [Terraform time_sleep](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep)
- [ArgoCD Application CRD](https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/)

Related Skills

azure-deployment

16
from diegosouzapw/awesome-omni-skill

Deploys applications to Azure using Azure Dev CLI, Bicep infrastructure as code, and GitHub Actions CI/CD. Use this skill when asked to deploy to Azure, create infrastructure, set up CI/CD, configure Azure resources, or create deployment pipelines.

azd-deployment

16
from diegosouzapw/awesome-omni-skill

Deploy containerized applications to Azure Container Apps using Azure Developer CLI (azd). Use when setting up azd projects, writing azure.yaml configuration, creating Bicep infrastructure for Cont...

app-store-deployment

16
from diegosouzapw/awesome-omni-skill

Publishes mobile applications to iOS App Store and Google Play with code signing, versioning, and CI/CD automation. Use when preparing app releases, configuring signing certificates, or setting up automated deployment pipelines.

ansible-deployment

16
from diegosouzapw/awesome-omni-skill

Automates server configuration and multi-server deployments. Use when writing Ansible playbooks, setting up SSH auth, or checking deployment diffs.

aks-deployment

16
from diegosouzapw/awesome-omni-skill

Deploying and debugging Toygres on AKS (Azure Kubernetes Service). Use when deploying, debugging pods, viewing logs, troubleshooting SSL, or managing Kubernetes resources.

aks-deployment-troubleshooter

16
from diegosouzapw/awesome-omni-skill

Diagnose and fix Kubernetes deployment failures, especially ImagePullBackOff, CrashLoopBackOff, and architecture mismatches. Battle-tested from 4-hour AKS debugging session with 10+ failure modes resolved.

agentuity-cli-cloud-machine-deployments

16
from diegosouzapw/awesome-omni-skill

List deployments running on a specific organization managed machine. Requires authentication. Use for Agentuity cloud platform operations

agentuity-cli-cloud-deployment-undeploy

16
from diegosouzapw/awesome-omni-skill

Undeploy the latest deployment. Requires authentication. Use for Agentuity cloud platform operations

agentuity-cli-cloud-deployment-show

16
from diegosouzapw/awesome-omni-skill

Show details about a specific deployment. Requires authentication. Use for Agentuity cloud platform operations

agentuity-cli-cloud-deployment-rollback

16
from diegosouzapw/awesome-omni-skill

Rollback the latest to the previous deployment. Requires authentication. Use for Agentuity cloud platform operations

agentuity-cli-cloud-deployment-remove

16
from diegosouzapw/awesome-omni-skill

Remove a specific deployment. Requires authentication. Use for Agentuity cloud platform operations

agentuity-cli-cloud-deployment-logs

16
from diegosouzapw/awesome-omni-skill

View logs for a specific deployment. Requires authentication. Use for Agentuity cloud platform operations