This a correction that is forf from original work of [anders.eficode](https://gitea.com/anders.eficode) on [pull request #160](https://gitea.com/gitea/helm-actions/pulls/160) Description of the change Adds statefulset.dind.resources and statefulset.runner.resources as optional per-container resource overrides. When set, each takes precedence over the shared statefulset.resources for that container. When unset (default {}), statefulset.resources is used as before. Benefits The DinD sidecar and the runner container have very different resource profiles — DinD is memory-hungry (image layer cache, concurrent builds, image pulls) while the runner is a lightweight coordinator that is mostly idle between jobs. Separate resource limits allow right-sizing each container independently, avoiding the choice between over-provisioning the runner or under-provisioning DinD. Possible drawbacks None. Fully backward-compatible — both new values default to {}, causing the shared statefulset.resources fallback to apply exactly as before. Checklist - [x] Parameters are documented in the `values.yaml` and added to the `README.md` using [readme-generator-for-helm](https://github.com/bitnami-labs/readme-generator-for-helm) - [x] Breaking changes are documented in the `README.md` - [x] Helm templating unittests are added (required when changing anything in `templates` folder) - [x] Bash unittests are added (required when changing anything in `scripts` folder) - [x] All added template resources MUST render a namespace in metadata --------- Co-authored-by: Le Prévost-Corvellec Arnault <arnault.le.prevost.corvellec@carbon-it.com> Co-authored-by: Anders <lantzanders@gmail.com> Reviewed-on: https://gitea.com/gitea/helm-actions/pulls/168 Reviewed-by: DaanSelen <135789+daanselen@noreply.gitea.com> Co-authored-by: Arnault_LPC <194310+arnault_lpc@noreply.gitea.com>
5.3 KiB
Resource limits and capacity
By default, all resource values are empty ({}). Without explicit limits, runner pods can consume unbounded CPU and memory on a node. This guide explains how to configure resource usage properly.
Pod architecture
Each runner pod contains two resource-consuming containers:
| Container | Role | Helm value |
|---|---|---|
runner |
Polls Gitea and orchestrates CI jobs | statefulset.runner.resources |
dind |
Docker-in-Docker daemon; executes job containers | statefulset.dind.resources |
The DinD container runs as a native sidecar (initContainer with restartPolicy: Always).
Helm resource keys
Three values control Kubernetes resource requests and limits:
| Key | Purpose |
|---|---|
statefulset.resources |
Shared fallback applied to both containers when no override is set |
statefulset.runner.resources |
Override for the runner container only |
statefulset.dind.resources |
Override for the dind container only |
Precedence:
statefulset.runner.resources → else statefulset.resources
statefulset.dind.resources → else statefulset.resources
Recommendation: set statefulset.runner.resources and statefulset.dind.resources
explicitly instead of relying on the shared fallback. The runner process is lightweight;
DinD and CI workloads need most of the budget.
Example: separate runner and DinD limits
enabled: true
giteaRootURL: https://gitea.example.com
existingSecret: runner-secret
existingSecretKey: runner-token
statefulset:
replicas: 1
runner:
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
config: |
log:
level: info
cache:
enabled: false
runner:
capacity: 1
container:
require_docker: true
docker_timeout: 300s
dind:
resources:
requests:
cpu: 500m
memory: 2Gi
limits:
cpu: 2
memory: 4Gi
Two layers of limiting
Kubernetes limits and act-runner job limits serve different purposes. Use both for a robust setup.
1. Kubernetes limits (Helm values)
These apply to the runner and dind containers in the pod.
dindlimits cap the Docker daemon and everything it runs inside the pod (images, build caches, job containers).runnerlimits cap the act-runner process itself.
If neither is set, a runaway build can exhaust the entire node.
2. Per-job Docker limits (container.options)
CI jobs run as Docker containers spawned by act-runner through the Docker socket. They are
not separate Kubernetes containers. Configure per-job limits in statefulset.runner.config
— see act-runner configuration
and config.example.yaml.
act-runner settings that affect resource usage
Settings such as runner.capacity and container.options live in statefulset.runner.config, not in the Helm resource values. Refer to the runner documentation for details:
- act-runner configuration
- config.example.yaml in the Gitea/runner repository
When concurrent jobs or per-job Docker limits increase expected load, size statefulset.dind.resources accordingly on the Helm side.
Capacity planning
These formulas apply to the Helm resource values (statefulset.runner.resources, statefulset.dind.resources, statefulset.replicas):
Per pod
pod budget ≈ runner.limits + dind.limits
Per node
node budget ≈ (runner.limits + dind.limits) × statefulset.replicas + system overhead
Example with the configuration above and replicas: 3:
- runner: 512Mi × 3 = 1.5Gi
- dind: 4Gi × 3 = 12Gi
- total: ~13.5Gi minimum, excluding other workloads on the node
Use statefulset.nodeSelector and statefulset.tolerations to place runners on dedicated nodes when needed.
Why not only set statefulset.resources?
Before chart 0.1.2, one value was copied to both containers. Requests are where it hurts most: the scheduler reserves capacity per container, and both inherit the same numbers.
# Only statefulset.resources — requests copied to runner AND dind:
statefulset:
resources:
requests:
cpu: 500m
memory: 2Gi # what DinD needs…
# runner also requests 500m + 2Gi → pod ~1 CPU + ~4Gi reserved (mostly wasted)
# dind requests 500m + 2Gi ✓
statefulset:
resources:
requests:
cpu: 100m
memory: 256Mi # what the runner actually needs…
# runner requests 100m + 256Mi ✓
# dind requests 100m + 256Mi too → tiny slot, builds starve ✗
# Separate overrides — scheduler sees the real footprint:
statefulset:
resources: {}
runner:
resources:
requests:
cpu: 100m
memory: 256Mi
dind:
resources:
requests:
cpu: 500m
memory: 2Gi
# pod requests ~600m CPU + ~2.25Gi RAM — not 1 CPU + 4Gi, nor 200m + 512Mi
Limits follow the same split. Unset overrides ({}) still fall back to statefulset.resources.