Skip to content

Adding a New Application

This runbook walks through adding a new application to the cluster. All apps are deployed as ArgoCD Applications generated by an ApplicationSet. Each app has a config.yaml (metadata), values.yaml (Helm values), and optionally a kustomization.yaml (supporting resources). The ApplicationSet discovers new apps automatically.

Step 1: Create the Application Directory

Create a directory for the new app under the appropriate location:

  • Media/arr apps: k8s/clusters/homelabk8s01/apps/arr/<app-name>/
  • Other apps: k8s/clusters/homelabk8s01/apps/<app-name>/
mkdir -p k8s/clusters/homelabk8s01/apps/arr/<app-name>

Step 2: Create config.yaml

Create config.yaml with the app metadata. This is what the ApplicationSet discovers.

appName: arr-<app-name>
namespace: arr
sourceType: helm
chartRepo: https://bjw-s-labs.github.io/helm-charts
chartName: app-template
chartVersion: "4.6.2"
createNamespace: false
hasResources: false
syncOptions:
  - ServerSideApply=true
  - ServerSideDiff=true

Key Fields

Field Description
appName Unique name for the ArgoCD Application (prefix with arr- for media apps)
namespace Target namespace (arr for media apps, or set createNamespace: true for a new one)
chartVersion Helm chart version -- always quote it ("4.6.2")
hasResources Set to true if the app has supporting resources (PDBs, ExternalSecrets, HTTPRoutes)
createNamespace true for single-app namespaces, false for arr (managed by arr-prereqs)

Step 3: Create values.yaml

Create values.yaml with the Helm chart values.

Minimal Template

defaultPodOptions:
  securityContext:
    runAsUser: 1000
    runAsGroup: 1000
    fsGroup: 1000
    runAsNonRoot: true

controllers:
  main:
    containers:
      main:
        image:
          repository: <image-repository>
          tag: <image-tag>
        envFrom:
          - configMapRef:
              name: arr-env
        securityContext:
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          capabilities:
            drop:
              - ALL
        resources:
          requests:
            cpu: 100m
            memory: 256Mi
          limits:
            memory: 512Mi
        probes:
          liveness:
            enabled: true
          readiness:
            enabled: true
          startup:
            enabled: true

service:
  main:
    controller: main
    ports:
      http:
        port: <port>

route:
  main:
    enabled: true
    kind: HTTPRoute
    parentRefs:
      - group: gateway.networking.k8s.io
        kind: Gateway
        name: homelab-gateway
        namespace: default
        sectionName: https
    hostnames:
      - <app-name>.homelab.local
    rules:
      - matches:
          - path:
              type: PathPrefix
              value: /
        backendRefs:
          - name: arr-<app-name>
            port: <port>

persistence:
  tmp:
    type: emptyDir
    globalMounts:
      - path: /tmp
  config:
    type: persistentVolumeClaim
    storageClass: nfs-client
    accessMode: ReadWriteOnce
    size: 1Gi
    globalMounts:
      - path: /config
  data:
    type: persistentVolumeClaim
    existingClaim: arr-data
    globalMounts:
      - path: /data

Replace the <placeholder> values with your application's specifics.

Tip

Use an existing app's values.yaml as a starting point. The Sonarr values at k8s/clusters/homelabk8s01/apps/arr/sonarr/values.yaml is a good reference for a typical arr-stack application.

linuxserver.io images

If the image is from linuxserver.io, you will need to remove readOnlyRootFilesystem: true and add SETUID/SETGID capabilities for the s6-overlay init system. See the Sonarr or Radarr values for examples.

Step 4: Add Secrets (If Needed)

If the application requires secrets (API keys, credentials, etc.):

  1. Create an ExternalSecret manifest in the app directory (e.g., <app-name>-external-secret.yml):

    apiVersion: external-secrets.io/v1
    kind: ExternalSecret
    metadata:
      name: <app-name>-secrets
      namespace: arr
    spec:
      refreshInterval: 1h
      secretStoreRef:
        kind: ClusterSecretStore
        name: vault-backend
      target:
        name: <app-name>-secrets
      data:
        - secretKey: API_KEY
          remoteRef:
            key: apps/<app-name>
            property: API_KEY
            conversionStrategy: Default
            decodingStrategy: None
            metadataPolicy: None
    
  2. Create a kustomization.yaml listing the supporting resource:

    apiVersion: kustomize.config.k8s.io/v1beta1
    kind: Kustomization
    resources:
      - <app-name>-external-secret.yml
    
  3. Set hasResources: true in config.yaml.

  4. Write the actual values to Vault:

    vault kv put homelab/apps/<app-name> API_KEY=your_real_key
    
  5. Reference the secret in values.yaml via envFrom or env.valueFrom.

Step 5: Add a DNS Entry

Add a DNS record for the new hostname (<app-name>.homelab.local) pointing to the Cilium L2 VIP assigned to the homelab-gateway. The gateway IP can be found with:

kubectl get gateway homelab-gateway -n default -o jsonpath='{.status.addresses[0].value}'

Step 6: Commit and Push

git add k8s/clusters/homelabk8s01/apps/arr/<app-name>/
git commit -m "add <app-name>"
git push

The ApplicationSet's Git File Generator automatically discovers the new config.yaml and generates an Application. Monitor the deployment in the ArgoCD UI at https://argocd.homelab.local.

Verification

  1. Check that ArgoCD picked up the new application:

    kubectl get application -n argocd arr-<app-name>
    
  2. Verify the pod is running:

    kubectl get pods -n arr -l app.kubernetes.io/instance=arr-<app-name>
    
  3. Open the web UI at https://<app-name>.homelab.local and confirm it loads.