|docs
Start Trial

For AI agents and assistants: visit https://docs.pagerduty.com/llms.txt for the index.

AI & Automation

PD Automation Runner: Installation

Deploy the PD Automation Runner into your infrastructure using Helm, Kubernetes YAML, Docker Run, or Docker Compose.

View as Markdown

This page covers how to deploy the PD Automation Runner into your infrastructure. For what the runner is, how it works, and how to register it and use it in a Workflow, see PD Automation Runner.

Before You Start

Register the runner in PagerDuty and have your three credential values ready — RUNNER_ID, RUNNER_SECRET, and RUNNER_PDTOKEN. In all commands on this page, replace <version> with the runner image version specified in your PagerDuty onboarding documentation.

Choose a Deployment Method

MethodRuns AsKubernetes Actions?Prometheus and Grafana Actions?
HelmPod inside your clusterYes (recommended)Yes
Kubernetes YAMLPod inside your clusterYesYes
Docker RunStandalone containerNoYes
Docker ComposeStandalone containerNoYes

A single runner can serve Kubernetes, Prometheus, and Grafana connections. Prometheus and Grafana actions only require network access from the runner to those instances. Once the runner is deployed, see Prometheus Self-Hosted or Grafana Self-Hosted to connect those instances.

Kubernetes Actions Require In-Cluster Deployment

Kubernetes Workflow Actions authenticate to the Kubernetes API using the runner pod's service account token, so the runner must run as a pod inside the cluster it manages. Use Helm or Kubernetes YAML for Kubernetes actions.

Configure RBAC (Kubernetes)

The runner pod must have a Kubernetes service account with permission to perform the operations your Kubernetes Workflow Actions require. Using a service account (rather than a kubeconfig with personal credentials) is the correct pattern: tokens are automatically rotated, permissions are scoped and auditable, and no credential file needs to be managed.

The following ClusterRole grants the minimum permissions required for all six Kubernetes Workflow Actions. Apply it in place of any wildcard grant you may have used during initial setup. The Kubernetes YAML method in the following section includes these rules inline. The Helm chart does not create RBAC, so Helm installations must apply these rules separately (see Grant Kubernetes Access (Helm)).

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pagerduty-automation-runner
  labels:
    app.kubernetes.io/name: pagerduty-automation-runner
    app.kubernetes.io/part-of: pagerduty-automation
rules:
  # Core resources — list and describe support
  - apiGroups: [""]
    resources:
      - configmaps
      - namespaces
      - nodes
      - persistentvolumes
      - persistentvolumeclaims
      - secrets
      - services
    verbs: [get, list]

  # Pods — all pod actions (list, describe, create, delete, logs, exec)
  - apiGroups: [""]
    resources: [pods]
    verbs: [get, list, create, delete]
  - apiGroups: [""]
    resources: [pods/log]
    verbs: [get]
  - apiGroups: [""]
    resources: [pods/exec]
    verbs: [create]

  # Apps resources
  - apiGroups: [apps]
    resources: [daemonsets, deployments, replicasets, statefulsets]
    verbs: [get, list]

  # Batch resources
  - apiGroups: [batch]
    resources: [cronjobs, jobs]
    verbs: [get, list]

  # Networking
  - apiGroups: [networking.k8s.io]
    resources: [ingresses]
    verbs: [get, list]

  # Policy — list-objects only (describe-object does not support PDBs)
  - apiGroups: [policy]
    resources: [poddisruptionbudgets]
    verbs: [list]

  # Storage
  - apiGroups: [storage.k8s.io]
    resources: [storageclasses]
    verbs: [get, list]

  # CRDs — list-objects only (describe-object does not support CRDs)
  - apiGroups: [apiextensions.k8s.io]
    resources: [customresourcedefinitions]
    verbs: [list]

Secrets Access

The List Objects and Describe Object actions can target Kubernetes Secrets. The secrets: [get, list] entry gives the runner read access to all Secrets across the cluster when combined with a ClusterRoleBinding. If this is too broad for your security posture, restrict access to specific namespaces by using a RoleBinding (instead of a ClusterRoleBinding) in each namespace where the runner operates. A ClusterRoleBinding is only strictly required for cluster-scoped resources (Namespaces, Nodes, PersistentVolumes, Storage Classes, Custom Resource Definitions).

Deploy the runner with the PagerDuty Helm chart. This is the recommended method for Kubernetes Workflow Actions.

Requirements: Helm 3.8 or later and a Kubernetes cluster.

Step 1: Create the credentials secret. The chart does not create the credentials secret. Create it before you install the chart, using the method that fits your organization's secrets-management policy (for example, External Secrets Operator, Sealed Secrets, Vault, or kubectl). Creating the secret separately, rather than passing credentials as --set values, keeps them out of Helm's release history.

kubectl create namespace pagerduty-automation-runner

kubectl create secret generic pagerduty-automation-runner-credentials \
  --namespace pagerduty-automation-runner \
  --from-literal=RUNNER_ID='<runner-id>' \
  --from-literal=RUNNER_SECRET='<runner-secret>' \
  --from-literal=RUNNER_PDTOKEN='<pagerduty-api-token>'

To use a different secret name, set credentials.secretName to that name when you install the chart.

Step 2: Install the chart. The chart is distributed as an OCI artifact through GitHub Container Registry, so there is no helm repo add step. Install it directly by its OCI reference:

helm install pd-runner \
  oci://ghcr.io/pagerduty/pagerduty-automation-runner-helm-charts/pd-runner \
  --version <chart-version> \
  --namespace pagerduty-automation-runner \
  --create-namespace

For accounts in the EU service region, add --set runner.region=eu:

helm install pd-runner \
  oci://ghcr.io/pagerduty/pagerduty-automation-runner-helm-charts/pd-runner \
  --version <chart-version> \
  --namespace pagerduty-automation-runner \
  --create-namespace \
  --set runner.region=eu

Replace <chart-version> with the chart version you want to install. Check the package's tags on GHCR for the current version. The chart version is tracked separately from the runner image version.

To inspect the chart before installing it, download the archive with helm pull:

helm pull oci://ghcr.io/pagerduty/pagerduty-automation-runner-helm-charts/pd-runner \
  --version <chart-version>

Pod Status Before the Secret Exists

If you install the chart before creating the credentials secret, the pod shows CreateContainerConfigError. The pod recovers automatically once the secret exists — you do not need to reinstall or upgrade the chart.

Step 3: Verify. Within a few minutes, the runner's status in Incident Workflows Automation Connectors Self-hosted Runners changes from Unhealthy to Healthy. The pod logs show the connection attempts:

kubectl --namespace pagerduty-automation-runner logs deployment/pd-runner --follow

To run a separate connectivity check, use helm test. It confirms that the credentials secret has non-empty values and that the cluster can reach the PagerDuty API over the network. It does not confirm that this runner's region and credentials are correct — use the pod logs and the Self-hosted Runners page for that.

helm test pd-runner --namespace pagerduty-automation-runner --logs

If the credentials secret does not exist yet, helm test fails with CreateContainerConfigError, the same as the runner pod.

Grant Kubernetes Access (Helm)

The chart does not create any Kubernetes RBAC — no ClusterRole, Role, ClusterRoleBinding, or RoleBinding. It creates a service account named pagerduty-automation-runner and mounts its token, but the token grants no access until you bind RBAC to it. If the runner only reaches non-Kubernetes targets, such as Prometheus or Grafana, no further configuration is needed.

To use Kubernetes Workflow Actions, apply the ClusterRole and ClusterRoleBinding from Configure RBAC — the same reference used for every deployment method — and bind it to the pagerduty-automation-runner service account in the release namespace. A namespaced Role and RoleBinding only work if the runner needs pod and workload actions in a single namespace: several of the ClusterRole's rules cover cluster-scoped resources (Nodes, Namespaces, PersistentVolumes, Storage Classes, Custom Resource Definitions) that a namespaced Role cannot grant, and Kubernetes actions on those resources fail without them.

Secret Read Access

Granting the runner read access to Secrets lets anyone who can trigger a workflow action against this runner read every Secret it can see, including the runner's own credentials. Grant Secret access only where it is required.

Key Chart Values

The chart validates values against its schema. An invalid value, such as an unrecognized runner.region or a blank credentials.secretName, fails at helm install with a schema error.

KeyDefaultDescription
credentials.secretNamepagerduty-automation-runner-credentialsName of the secret holding RUNNER_ID, RUNNER_SECRET, and RUNNER_PDTOKEN. The chart does not create this secret.
runner.regionnaPagerDuty API region: na, eu, or other. Must match the region where the runner was registered.
runner.cloudUrl—API endpoint to use when runner.region is other.
runner.logOutputconsoleDestination for the runner's own logs. Does not affect the Object Logs action.
image.repositoryrundeckpro/ua-runnerRunner image repository.
image.tagChart appVersionRunner image tag. Ignored when image.digest is set.
image.digest—Pins the image by digest instead of tag.
serviceAccount.createtrueCreates the runner's service account.
serviceAccount.namepagerduty-automation-runnerFixed name, not derived from the release name, so RBAC bound outside the chart survives renames and reinstalls.
kubernetesAccess.enabledtrueMounts the service account token. Set to false to withhold the token even from RBAC bound outside the chart.
replicaCount1Number of runner replicas.
podDisruptionBudget.createfalseCreates a PodDisruptionBudget. Enable only when running more than one replica.
resourcesRequests: 100m CPU, 256Mi memory. Limits: 500m CPU, 512Mi memory.Pod resource requests and limits.

The chart also supports standard scheduling and metadata values: affinity, nodeSelector, tolerations, podAnnotations, podLabels, podSecurityContext, containerSecurityContext, imagePullSecrets, extraEnv, nameOverride, and fullnameOverride.

Option B: Kubernetes YAML

Deploy the runner using kubectl apply.

Step 1: Apply namespace and RBAC. Save the following as pd-runner-rbac.yaml and apply it:

apiVersion: v1
kind: Namespace
metadata:
  name: pagerduty-automation-runner
  labels:
    app.kubernetes.io/name: pagerduty-automation-runner
    app.kubernetes.io/part-of: pagerduty-automation

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: pagerduty-automation-runner
  namespace: pagerduty-automation-runner
  labels:
    app.kubernetes.io/name: pagerduty-automation-runner
    app.kubernetes.io/part-of: pagerduty-automation

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pagerduty-automation-runner
  labels:
    app.kubernetes.io/name: pagerduty-automation-runner
    app.kubernetes.io/part-of: pagerduty-automation
rules:
  - apiGroups: [""]
    resources:
      - configmaps
      - namespaces
      - nodes
      - persistentvolumes
      - persistentvolumeclaims
      - secrets
      - services
    verbs: [get, list]
  - apiGroups: [""]
    resources: [pods]
    verbs: [get, list, create, delete]
  - apiGroups: [""]
    resources: [pods/log]
    verbs: [get]
  - apiGroups: [""]
    resources: [pods/exec]
    verbs: [create]
  - apiGroups: [apps]
    resources: [daemonsets, deployments, replicasets, statefulsets]
    verbs: [get, list]
  - apiGroups: [batch]
    resources: [cronjobs, jobs]
    verbs: [get, list]
  - apiGroups: [networking.k8s.io]
    resources: [ingresses]
    verbs: [get, list]
  - apiGroups: [policy]
    resources: [poddisruptionbudgets]
    verbs: [list]
  - apiGroups: [storage.k8s.io]
    resources: [storageclasses]
    verbs: [get, list]
  - apiGroups: [apiextensions.k8s.io]
    resources: [customresourcedefinitions]
    verbs: [list]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: pagerduty-automation-runner
  labels:
    app.kubernetes.io/name: pagerduty-automation-runner
    app.kubernetes.io/part-of: pagerduty-automation
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: pagerduty-automation-runner
subjects:
  - kind: ServiceAccount
    name: pagerduty-automation-runner
    namespace: pagerduty-automation-runner
kubectl apply -f pd-runner-rbac.yaml

Step 2: Create the credentials secret. Do not put credentials in a YAML file that could be committed to source control. Create the secret directly from your credential values:

kubectl create secret generic pagerduty-automation-runner-credentials \
  --namespace pagerduty-automation-runner \
  --from-literal=RUNNER_ID="<your-runner-id>" \
  --from-literal=RUNNER_SECRET="<your-runner-secret>" \
  --from-literal=RUNNER_PDTOKEN="<your-pd-api-token>"

Step 3: Deploy the runner. Save the following as pd-runner-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pagerduty-automation-runner
  namespace: pagerduty-automation-runner
  labels:
    app.kubernetes.io/name: pagerduty-automation-runner
    app.kubernetes.io/part-of: pagerduty-automation
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: pagerduty-automation-runner
  template:
    metadata:
      labels:
        app.kubernetes.io/name: pagerduty-automation-runner
        app.kubernetes.io/part-of: pagerduty-automation
    spec:
      serviceAccountName: pagerduty-automation-runner
      automountServiceAccountToken: true
      containers:
        - name: runner
          image: rundeckpro/ua-runner:<version>
          imagePullPolicy: IfNotPresent
          env:
            - name: RUNNER_ID
              valueFrom:
                secretKeyRef:
                  name: pagerduty-automation-runner-credentials
                  key: RUNNER_ID
            - name: RUNNER_SECRET
              valueFrom:
                secretKeyRef:
                  name: pagerduty-automation-runner-credentials
                  key: RUNNER_SECRET
            - name: RUNNER_PDTOKEN
              valueFrom:
                secretKeyRef:
                  name: pagerduty-automation-runner-credentials
                  key: RUNNER_PDTOKEN
            - name: RUNNER_CLOUD_URL
              value: "https://api.pagerduty.com"  # EU: https://api.eu.pagerduty.com
            - name: RUNNER_LOG_OUTPUT
              value: "console"
          resources:
            requests:
              cpu: "100m"
              memory: "256Mi"
            limits:
              cpu: "500m"
              memory: "512Mi"
      restartPolicy: Always
kubectl apply -f pd-runner-deployment.yaml

API Endpoint

RUNNER_CLOUD_URL defaults to the NA production endpoint (https://api.pagerduty.com). EU accounts should set it to https://api.eu.pagerduty.com. The value must match the region where the runner was registered — a runner registered in one region will not authenticate against another.

Step 4: Verify. Confirm the pod is running and follow its logs to confirm it connected to PagerDuty:

kubectl -n pagerduty-automation-runner get pods
kubectl -n pagerduty-automation-runner logs deploy/pagerduty-automation-runner --follow

A successful connection produces log lines indicating the runner registered and is polling for jobs. Once connected, the runner appears as Healthy in Incident Workflows Automation Connectors Self-hosted Runners.

Updating. To update the runner image version, change the image: field in pd-runner-deployment.yaml and re-apply with kubectl apply -f pd-runner-deployment.yaml. Kubernetes performs a rolling update with zero downtime.

Removing. Delete the deployment, RBAC, secret, and namespace, then deregister the runner in Incident Workflows Automation Connectors Self-hosted Runners:

kubectl delete -f pd-runner-deployment.yaml
kubectl delete -f pd-runner-rbac.yaml
kubectl delete secret pagerduty-automation-runner-credentials -n pagerduty-automation-runner
kubectl delete namespace pagerduty-automation-runner

Option C: Docker Run

Kubernetes Actions Are Not Supported with Docker Deployment

Kubernetes Workflow Actions require the runner to run as a pod inside the target cluster. Use Helm or Kubernetes YAML for Kubernetes actions.

docker run -d \
  --name pagerduty-automation-runner \
  --restart unless-stopped \
  -e RUNNER_ID="<your-runner-id>" \
  -e RUNNER_SECRET="<your-runner-secret>" \
  -e RUNNER_PDTOKEN="<your-pd-api-token>" \
  -e RUNNER_CLOUD_URL="https://api.pagerduty.com" \
  -e RUNNER_LOG_OUTPUT="console" \
  rundeckpro/ua-runner:<version>

EU Accounts

Set RUNNER_CLOUD_URL to https://api.eu.pagerduty.com.

Verify the runner connected:

docker logs -f pagerduty-automation-runner

Option D: Docker Compose

Kubernetes Actions Are Not Supported with Docker Deployment

Use Helm or Kubernetes YAML for Kubernetes actions.

Create a .env file with your credentials (do not commit it to source control):

RUNNER_ID=<your-runner-id>
RUNNER_SECRET=<your-runner-secret>
RUNNER_PDTOKEN=<your-pd-api-token>

Create docker-compose.yml (EU accounts set RUNNER_CLOUD_URL to https://api.eu.pagerduty.com):

services:
  pagerduty-automation-runner:
    image: rundeckpro/ua-runner:<version>
    container_name: pagerduty-automation-runner
    restart: unless-stopped
    environment:
      RUNNER_ID: "${RUNNER_ID}"
      RUNNER_SECRET: "${RUNNER_SECRET}"
      RUNNER_PDTOKEN: "${RUNNER_PDTOKEN}"
      RUNNER_CLOUD_URL: "https://api.pagerduty.com"
      RUNNER_LOG_OUTPUT: "console"

Start the runner and verify it connected:

docker compose up -d
docker compose logs -f pagerduty-automation-runner

In all cases, the runner appears as Healthy in Incident Workflows Automation Connectors Self-hosted Runners once connected.

Troubleshooting

Helm Installations

The commands in this section use the deployment name from the Kubernetes YAML method (deploy/pagerduty-automation-runner). If you installed with Helm, use deploy/pd-runner instead — the namespace, service account, and secret names are the same regardless of deployment method.

Runner Shows Unhealthy in PagerDuty

The runner appears in Incident Workflows Automation Connectors Self-hosted Runners but its status is Unhealthy, or it does not connect at all. Check the runner logs first:

kubectl -n pagerduty-automation-runner logs deploy/pagerduty-automation-runner --follow
Symptom in LogsCauseFix
401 Unauthorized or authentication failedInvalid RUNNER_ID, RUNNER_SECRET, or RUNNER_PDTOKENVerify credentials match what PagerDuty generated at registration. Re-create the secret if needed.
connection refused or unable to connectNetwork egress blockedThe runner requires outbound HTTPS (port 443) to the PagerDuty API endpoint configured in RUNNER_CLOUD_URL. Check firewall and proxy rules.
Pod is in CrashLoopBackOffContainer exiting on startupRun kubectl -n pagerduty-automation-runner describe pod <pod-name> for the exit reason. Usually a missing or malformed secret.
No log output at allPod not startingRun kubectl -n pagerduty-automation-runner get pods to check pod status, then describe for events.

Action Fails with "Runner Offline" or Times Out

A Workflow action returns Failed with a message indicating the runner did not respond.

  1. Confirm the runner pod is running: kubectl -n pagerduty-automation-runner get pods
  2. Confirm the runner shows Healthy in Incident Workflows Automation Connectors Self-hosted Runners.
  3. Confirm the Connection Input in the Workflow action references the correct runner.
  4. Check runner logs for a received job — a healthy runner logs each job it receives.

Action Fails with a Permissions Error

The action executes but returns an error like forbidden: User "system:serviceaccount:pagerduty-automation-runner:pagerduty-automation-runner" cannot list resource "pods". The runner's service account does not have the required RBAC permissions.

  1. Verify the ClusterRole and ClusterRoleBinding exist:
kubectl get clusterrole pagerduty-automation-runner
kubectl get clusterrolebinding pagerduty-automation-runner
  1. Check the ClusterRole rules match the scoped manifest in the Configure RBAC section. If you started with a wildcard grant and removed it, ensure the replacement rules cover the resource type the action is trying to access.
  2. If you switched from a ClusterRoleBinding to per-namespace RoleBindings, verify a RoleBinding exists in the namespace the action is targeting:
kubectl get rolebinding -n <target-namespace> | grep pagerduty-automation-runner
  1. Apply the corrected RBAC and restart the runner:
kubectl apply -f pd-runner-rbac.yaml
kubectl -n pagerduty-automation-runner rollout restart deploy/pagerduty-automation-runner

Action Fails with "Unknown Object Type" or Similar Plugin Error

The runner received the job but the Kubernetes plugin could not process it.

  1. Check runner logs for the specific error message around the time of the action invocation.
  2. Verify the Object Type input matches a supported type for that action (refer to the input tables in Kubernetes Workflow Actions).
  3. Verify the Namespace input is correct for namespace-scoped resources.

Credentials Secret Is Missing or Malformed

Symptom: the pod goes into CrashLoopBackOff immediately and logs show a missing environment variable. Verify the secret exists and contains exactly these keys — RUNNER_ID, RUNNER_SECRET, RUNNER_PDTOKEN:

kubectl get secret pagerduty-automation-runner-credentials -n pagerduty-automation-runner
kubectl describe secret pagerduty-automation-runner-credentials -n pagerduty-automation-runner

To re-create the secret:

kubectl delete secret pagerduty-automation-runner-credentials -n pagerduty-automation-runner

kubectl create secret generic pagerduty-automation-runner-credentials \
  --namespace pagerduty-automation-runner \
  --from-literal=RUNNER_ID="<your-runner-id>" \
  --from-literal=RUNNER_SECRET="<your-runner-secret>" \
  --from-literal=RUNNER_PDTOKEN="<your-pd-api-token>"

kubectl -n pagerduty-automation-runner rollout restart deploy/pagerduty-automation-runner

Checking Runner Health in PagerDuty

Navigate to Incident Workflows Automation Connectors Self-hosted Runners and select the runner by name. The detail page shows its Status (Healthy / Unhealthy), Last seen timestamp (most recent heartbeat), and Active jobs currently being processed. If the runner is Healthy but actions are still failing, the issue is likely in the action's configuration (wrong connection input, wrong namespace, or insufficient RBAC) rather than the runner itself.

Learn More