GitHub Actions Runner in Kubernetes without Cert-manager

There is actions-runner-controller Kubernetes controller for GitHub self hosted action runners.

It is possible to run it without Cert-manager

The drawback is possible slower registration of runners, but we have no dependency on Cert-manager which might be important in some scenarious when you not fully control cluster or want everything to be losely coupled.


From previous notes about creating self signed cert I ended up with following script:

rm -rf *.pem *.csr *.srl || true

# Step 1: CA
# ----------

# create CA, it is secret, keep it safe
openssl genrsa -out ca.private.pem 2048

# create public CA, give it to everyone so they can add it to trusted root
openssl req -x509 -new -key ca.private.pem -out ca.public.pem -days 10000 -subj "/C=UA/L=Kiev"

# Step 2: Certificate
# -------------------

# create certificate, it is secret, keep it safe
openssl genrsa -out cert.private.pem 2048

# create "certificate signing request" (csr)
openssl req -new -key cert.private.pem -out cert.csr -subj "/CN=actions-runner-controller-webhook.actions-runner-system.svc"

# config
cat <<EOT >> cert.conf
subjectAltName = @alt_names
DNS.1 = actions-runner-controller-webhook.actions-runner-system.svc
DNS.2 = actions-runner-controller-webhook.actions-runner-system.svc.cluster.local

# sign it with our CA
openssl x509 -req -in cert.csr -CA ca.public.pem -CAkey ca.private.pem -CAcreateserial -out cert.public.pem -days 10000 -extensions SAN -extfile cert.conf

# clean
rm -rf *.csr *.srl cert.conf || true

# check
openssl x509 -in cert.public.pem -text -noout | grep DNS

Important note here is that cert should have SAN with exactly that DNS names for controller to work

The next step will be to prepare namespace and add this certificates

kubectl create ns actions-runner-system
kubectl create secret tls actions-runner-controller-serving-cert -n actions-runner-system --cert=cert.public.pem --key=cert.private.pem

Actions Runner Controller

Now it is time for controller

helm upgrade actions-runner-controller actions-runner-controller \
  --install \
  --namespace actions-runner-system \
  --repo \
  -f values.yml


Values are pretty default ones, the important changes are:

  • certManagerEnabled: false - to disable Cert-manager
  • caBundle: xxxxxx== - base64 encoded content of ca.public.pem created in previous step
  create: true
  github_token: ghp_xxxxxxxxxxxxxxx

# POI: disable cert manager
certManagerEnabled: false

  # POI: cat ca.public.pem | base64
  caBundle: xxxxxxxxxxxxxxxxxxxxxxxxxxxx=

  poolDestination: app

podAnnotations: "true" /metrics "8080"

GitHub Actions Runner

once again nothing important here, everything may be left as default

cat <<EOT >> runner.yml
kind: RunnerDeployment
  name: gha
  namespace: actions-runner-system
  replicas: 1
      dockerdWithinRunnerContainer: true
      organization: rabotaua
        - 'gha'
        - 'gha-dev'
        poolDestination: app
          cpu: "1.0"
          memory: "4Gi"
          cpu: "1.0"
          memory: "4Gi"
      # dockerdContainerResources:
      #   limits:
      #     cpu: "2.0"
      #     memory: "8Gi"
      #   requests:
      #     cpu: "1.0"
      #     memory: "4Gi"

kubectl apply -f runner.yml

And if everything done right we should see our runner:

kubectl -n actions-runner-system get runners
kubectl -n actions-runner-system get po -l runner-deployment-name=gha
kubectl -n actions-runner-system top po -l runner-deployment-name=gha


To cleanup everything use something like this:

# Step 1: Runner
kubectl -n actions-runner-system delete runnerdeployment gha
# Step 2: Helm
helm -n actions-runner-system uninstall actions-runner-controller
# Step 3: Namespace
kubectl delete ns actions-runner-system