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.
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
| Method | Runs As | Kubernetes Actions? | Prometheus and Grafana Actions? |
|---|---|---|---|
| Helm | Pod inside your cluster | Yes (recommended) | Yes |
| Kubernetes YAML | Pod inside your cluster | Yes | Yes |
| Docker Run | Standalone container | No | Yes |
| Docker Compose | Standalone container | No | Yes |
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).
Option A: Helm (Recommended for Kubernetes Actions)
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.
| Key | Default | Description |
|---|---|---|
credentials.secretName | pagerduty-automation-runner-credentials | Name of the secret holding RUNNER_ID, RUNNER_SECRET, and RUNNER_PDTOKEN. The chart does not create this secret. |
runner.region | na | PagerDuty 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.logOutput | console | Destination for the runner's own logs. Does not affect the Object Logs action. |
image.repository | rundeckpro/ua-runner | Runner image repository. |
image.tag | Chart appVersion | Runner image tag. Ignored when image.digest is set. |
image.digest | — | Pins the image by digest instead of tag. |
serviceAccount.create | true | Creates the runner's service account. |
serviceAccount.name | pagerduty-automation-runner | Fixed name, not derived from the release name, so RBAC bound outside the chart survives renames and reinstalls. |
kubernetesAccess.enabled | true | Mounts the service account token. Set to false to withhold the token even from RBAC bound outside the chart. |
replicaCount | 1 | Number of runner replicas. |
podDisruptionBudget.create | false | Creates a PodDisruptionBudget. Enable only when running more than one replica. |
resources | Requests: 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 Logs | Cause | Fix |
|---|---|---|
401 Unauthorized or authentication failed | Invalid RUNNER_ID, RUNNER_SECRET, or RUNNER_PDTOKEN | Verify credentials match what PagerDuty generated at registration. Re-create the secret if needed. |
connection refused or unable to connect | Network egress blocked | The runner requires outbound HTTPS (port 443) to the PagerDuty API endpoint configured in RUNNER_CLOUD_URL. Check firewall and proxy rules. |
Pod is in CrashLoopBackOff | Container exiting on startup | Run kubectl -n pagerduty-automation-runner describe pod <pod-name> for the exit reason. Usually a missing or malformed secret. |
| No log output at all | Pod not starting | Run 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.
- Confirm the runner pod is running:
kubectl -n pagerduty-automation-runner get pods - Confirm the runner shows Healthy in Incident Workflows Automation Connectors Self-hosted Runners.
- Confirm the Connection Input in the Workflow action references the correct runner.
- 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.
- Verify the ClusterRole and ClusterRoleBinding exist:
kubectl get clusterrole pagerduty-automation-runner
kubectl get clusterrolebinding pagerduty-automation-runner
- 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.
- 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
- 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.
- Check runner logs for the specific error message around the time of the action invocation.
- Verify the Object Type input matches a supported type for that action (refer to the input tables in Kubernetes Workflow Actions).
- 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.