<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ngapaillard</title>
    <description>The latest articles on DEV Community by ngapaillard (@ngapaillard).</description>
    <link>https://dev.to/ngapaillard</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3606481%2F102594e0-bb4e-43cd-9fd8-11b72fdc56b1.png</url>
      <title>DEV Community: ngapaillard</title>
      <link>https://dev.to/ngapaillard</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ngapaillard"/>
    <language>en</language>
    <item>
      <title>GitHub Actions Runner Controller (ARC v2): How to be Synced with argocd</title>
      <dc:creator>ngapaillard</dc:creator>
      <pubDate>Tue, 11 Nov 2025 20:07:46 +0000</pubDate>
      <link>https://dev.to/ngapaillard/github-actions-runner-controller-arc-v2-how-to-be-synced-with-argocd-1ppo</link>
      <guid>https://dev.to/ngapaillard/github-actions-runner-controller-arc-v2-how-to-be-synced-with-argocd-1ppo</guid>
      <description>&lt;h2&gt;
  
  
  The Problem: GitOps Auto-Sync Doesn't Work with Helm Values
&lt;/h2&gt;

&lt;p&gt;If you're using &lt;strong&gt;GitHub Actions Runner Controller (ARC) v2&lt;/strong&gt; with &lt;strong&gt;ArgoCD&lt;/strong&gt; for GitOps deployment, you've probably hit this frustrating wall:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ArgoCD doesn't auto-sync when you change Helm values.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You modify your runner configuration in Git, push, and... nothing happens. ArgoCD shows "Synced" but your changes aren't applied. You're forced to manually trigger sync every single time.&lt;/p&gt;

&lt;p&gt;Why? Because ArgoCD's Git polling doesn't detect changes in &lt;strong&gt;inline Helm values&lt;/strong&gt; or even &lt;strong&gt;external &lt;code&gt;valueFiles&lt;/code&gt;&lt;/strong&gt;. It's a known limitation when using Helm charts with ArgoCD.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Journey: From Helm to Pure YAML
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What We Tried (And Failed)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Webhooks&lt;/strong&gt; ❌ - Won't work if your cluster is in a private network&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;External valueFiles&lt;/strong&gt; ❌ - ArgoCD still doesn't detect changes reliably&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Checksum annotations&lt;/strong&gt; ❌ - Too complex, requires CI/CD pipeline&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual sync scripts&lt;/strong&gt; ❌ - Defeats the purpose of GitOps&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Breakthrough: Use AutoScalingRunnerSet Directly
&lt;/h3&gt;

&lt;p&gt;ARC v2 uses a &lt;strong&gt;Custom Resource&lt;/strong&gt; called &lt;code&gt;AutoScalingRunnerSet&lt;/code&gt;. While the official docs recommend deploying it via the &lt;code&gt;gha-runner-scale-set&lt;/code&gt; Helm chart, you can actually deploy it as a &lt;strong&gt;pure YAML manifest&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ ArgoCD detects changes immediately&lt;/li&gt;
&lt;li&gt;✅ Auto-sync works perfectly&lt;/li&gt;
&lt;li&gt;✅ No Helm templating complexity&lt;/li&gt;
&lt;li&gt;✅ Direct control over runner configuration&lt;/li&gt;
&lt;li&gt;✅ True GitOps experience&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;But there's a catch...&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mystery: Controller Keeps Deleting the Resource
&lt;/h2&gt;

&lt;p&gt;When we tried deploying &lt;code&gt;AutoScalingRunnerSet&lt;/code&gt; as a pure YAML manifest, something strange happened:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; autoscaling-runner-set.yaml
autoscalingrunnerset.actions.github.com/runners created

&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get autoscalingrunnersets
No resources found.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The resource disappeared immediately!&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Investigating the Controller Logs
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl logs deployment/gha-rs-controller &lt;span class="nt"&gt;-n&lt;/span&gt; arc-system
INFO  Autoscaling runner &lt;span class="nb"&gt;set &lt;/span&gt;version doesn&lt;span class="s1"&gt;'t match the build version. Deleting the resource.
{"targetVersion": "0.9.2", "actualVersion": ""}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Aha!&lt;/strong&gt; The controller was checking for a version and finding it empty, then immediately deleting the resource.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: A Hidden Label Requirement
&lt;/h2&gt;

&lt;p&gt;After diving into the &lt;a href="https://github.com/actions/actions-runner-controller/blob/master/controllers/actions.github.com/autoscalingrunnerset_controller.go" rel="noopener noreferrer"&gt;controller source code&lt;/a&gt;, we found the culprit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;v1alpha1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsVersionAllowed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;autoscalingRunnerSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Labels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;LabelKeyKubernetesVersion&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Delete the resource&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The controller checks for a specific label!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We used &lt;code&gt;helm template&lt;/code&gt; to see what labels the Helm chart adds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helm template &lt;span class="nb"&gt;test &lt;/span&gt;oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--version&lt;/span&gt; 0.9.2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="nv"&gt;githubConfigUrl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://github.com/myorg &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="nv"&gt;githubConfigSecret&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;github-token &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; controllerServiceAccount.name&lt;span class="o"&gt;=&lt;/span&gt;gha-rs-controller &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; controllerServiceAccount.namespace&lt;span class="o"&gt;=&lt;/span&gt;arc-system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key finding:&lt;/strong&gt; The Helm chart adds &lt;code&gt;app.kubernetes.io/version: "0.9.2"&lt;/code&gt; label!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Working Manifest
&lt;/h2&gt;

&lt;p&gt;Here's a complete, working &lt;code&gt;AutoScalingRunnerSet&lt;/code&gt; manifest that you can deploy with ArgoCD:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions.github.com/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AutoscalingRunnerSet&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github-runners&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;arc-runners&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# CRITICAL: Controller checks this label for version compatibility&lt;/span&gt;
    &lt;span class="na"&gt;app.kubernetes.io/version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.9.2"&lt;/span&gt;
    &lt;span class="na"&gt;app.kubernetes.io/name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github-runners&lt;/span&gt;
    &lt;span class="na"&gt;app.kubernetes.io/component&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;autoscaling-runner-set&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Optional: Bump this to force a rollout without changing spec&lt;/span&gt;
    &lt;span class="na"&gt;rollout-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2025-11-11"&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# GitHub configuration&lt;/span&gt;
  &lt;span class="na"&gt;githubConfigUrl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://github.com/your-org"&lt;/span&gt;
  &lt;span class="na"&gt;githubConfigSecret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github-token&lt;/span&gt;

  &lt;span class="c1"&gt;# Runner scale set name (appears in GitHub UI)&lt;/span&gt;
  &lt;span class="na"&gt;runnerScaleSetName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;k8s-runners"&lt;/span&gt;

  &lt;span class="c1"&gt;# Runner group&lt;/span&gt;
  &lt;span class="na"&gt;runnerGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;default"&lt;/span&gt;

  &lt;span class="c1"&gt;# Scaling configuration&lt;/span&gt;
  &lt;span class="na"&gt;minRunners&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;maxRunners&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;

  &lt;span class="c1"&gt;# Runner pod template&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;runner&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io/actions/actions-runner:latest&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/home/runner/run.sh"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

          &lt;span class="c1"&gt;# Docker-in-Docker configuration&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DOCKER_HOST&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tcp://localhost:2376&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DOCKER_TLS_VERIFY&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DOCKER_CERT_PATH&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/certs/client&lt;/span&gt;

          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker-certs&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/certs/client&lt;/span&gt;
              &lt;span class="na"&gt;readOnly&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;work&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/home/runner/_work&lt;/span&gt;

          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;250m&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1Gi&lt;/span&gt;
            &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3Gi&lt;/span&gt;

        &lt;span class="c1"&gt;# Docker-in-Docker sidecar&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dind&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker:24-dind&lt;/span&gt;
          &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;privileged&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DOCKER_TLS_CERTDIR&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/certs&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker-certs&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/certs/client&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker-storage&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/lib/docker&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;work&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/home/runner/_work&lt;/span&gt;
          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;250m&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2Gi&lt;/span&gt;
            &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;7Gi&lt;/span&gt;

      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker-certs&lt;/span&gt;
          &lt;span class="na"&gt;emptyDir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker-storage&lt;/span&gt;
          &lt;span class="na"&gt;emptyDir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;work&lt;/span&gt;
          &lt;span class="na"&gt;emptyDir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ArgoCD Application Configuration
&lt;/h2&gt;

&lt;p&gt;Deploy this with ArgoCD:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argoproj.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Application&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github-runners&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;

  &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;repoURL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/your-org/infra&lt;/span&gt;
    &lt;span class="na"&gt;targetRevision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;platform/github-runners&lt;/span&gt;
    &lt;span class="na"&gt;directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;autoscaling-runner-set.yaml"&lt;/span&gt;

  &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://kubernetes.default.svc&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;arc-runners&lt;/span&gt;

  &lt;span class="na"&gt;syncPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;automated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;prune&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;selfHeal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;syncOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CreateNamespace=true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;You modify&lt;/strong&gt; &lt;code&gt;autoscaling-runner-set.yaml&lt;/code&gt; in Git&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Git push&lt;/strong&gt; to your repository&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ArgoCD detects&lt;/strong&gt; the change (within 3 minutes with default polling)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-sync triggers&lt;/strong&gt; automatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runners update&lt;/strong&gt; without manual intervention&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;True GitOps!&lt;/strong&gt; ✅&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Notes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Version Label is Critical
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;app.kubernetes.io/version&lt;/code&gt; label &lt;strong&gt;must match&lt;/strong&gt; your ARC controller version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get deployment gha-rs-controller &lt;span class="nt"&gt;-n&lt;/span&gt; arc-system &lt;span class="nt"&gt;-o&lt;/span&gt; yaml | &lt;span class="nb"&gt;grep &lt;/span&gt;image:
image: ghcr.io/actions/actions-runner-controller:0.9.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your controller is version &lt;code&gt;0.9.2&lt;/code&gt;, use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app.kubernetes.io/version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.9.2"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Don't Specify listenerTemplate
&lt;/h3&gt;

&lt;p&gt;The listener pod is managed automatically by the controller. Don't add a &lt;code&gt;listenerTemplate&lt;/code&gt; section to your manifest - it will cause image pull errors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Controller Must Be Installed First
&lt;/h3&gt;

&lt;p&gt;Install the ARC controller before deploying runners:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm &lt;span class="nb"&gt;install &lt;/span&gt;arc &lt;span class="se"&gt;\&lt;/span&gt;
  oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; arc-system &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--create-namespace&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing Your Setup
&lt;/h2&gt;

&lt;p&gt;After deploying, verify everything works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check AutoScalingRunnerSet&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get autoscalingrunnersets &lt;span class="nt"&gt;-n&lt;/span&gt; arc-runners
NAME             MINIMUM   MAXIMUM   CURRENT   STATE   PENDING   RUNNING
github-runners   1         10        1                 1

&lt;span class="c"&gt;# Check pods&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; arc-runners
NAME                                    READY   STATUS
github-runners-55655b45-listener        1/1     Running
github-runners-fddsm-runner-pjjqx       2/2     Running

&lt;span class="c"&gt;# Check in GitHub&lt;/span&gt;
&lt;span class="c"&gt;# Go to: Settings → Actions → Runners&lt;/span&gt;
&lt;span class="c"&gt;# You should see your runner scale set online!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Benefits Over Helm Chart Approach
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Helm Chart&lt;/th&gt;
&lt;th&gt;Pure YAML&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ArgoCD Auto-Sync&lt;/td&gt;
&lt;td&gt;❌ Doesn't work&lt;/td&gt;
&lt;td&gt;✅ Works perfectly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration Changes&lt;/td&gt;
&lt;td&gt;Manual sync needed&lt;/td&gt;
&lt;td&gt;Automatic deployment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complexity&lt;/td&gt;
&lt;td&gt;Helm templating&lt;/td&gt;
&lt;td&gt;Simple YAML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Version Control&lt;/td&gt;
&lt;td&gt;Values in Git, hard to diff&lt;/td&gt;
&lt;td&gt;Direct manifest, easy to diff&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning Curve&lt;/td&gt;
&lt;td&gt;Need to know Helm&lt;/td&gt;
&lt;td&gt;Just Kubernetes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By deploying &lt;code&gt;AutoScalingRunnerSet&lt;/code&gt; as a pure YAML manifest with the correct &lt;code&gt;app.kubernetes.io/version&lt;/code&gt; label, you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;True GitOps&lt;/strong&gt; - Push to Git, auto-deploy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplified Configuration&lt;/strong&gt; - No Helm complexity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better Visibility&lt;/strong&gt; - Clear, readable manifests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster Iterations&lt;/strong&gt; - No manual sync needed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach is &lt;strong&gt;not documented anywhere&lt;/strong&gt; in the official ARC documentation, but it works perfectly and makes GitOps actually... GitOps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Resource Gets Deleted Immediately
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt; AutoScalingRunnerSet disappears right after creation&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Add the &lt;code&gt;app.kubernetes.io/version&lt;/code&gt; label matching your controller version&lt;/p&gt;

&lt;h3&gt;
  
  
  Listener Pod Has ImagePullBackOff
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt; Listener pod fails with "image not found"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Remove the &lt;code&gt;listenerTemplate&lt;/code&gt; section - let the controller manage it&lt;/p&gt;

&lt;h3&gt;
  
  
  ArgoCD Shows OutOfSync But Doesn't Sync
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt; Application stuck in OutOfSync state&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check if &lt;code&gt;automated: true&lt;/code&gt; is set in syncPolicy&lt;/li&gt;
&lt;li&gt;Manually trigger refresh: &lt;code&gt;kubectl annotate application github-runners -n argocd argocd.argoproj.io/refresh=hard --overwrite&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/actions/actions-runner-controller" rel="noopener noreferrer"&gt;ARC GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners-with-actions-runner-controller" rel="noopener noreferrer"&gt;ARC Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/actions/actions-runner-controller/blob/master/controllers/actions.github.com/autoscalingrunnerset_controller.go" rel="noopener noreferrer"&gt;Controller Source Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>github</category>
      <category>kubernetes</category>
      <category>argocd</category>
      <category>arc</category>
    </item>
  </channel>
</rss>
