Configuration
Collector Configuration
The collector runs alongside CI workloads, reads /proc, and pushes a run summary to the receiver on shutdown.
Collector Flags
| Flag | Environment Variable | Description | Default |
|---|---|---|---|
--interval | — | Collection interval (e.g., 5s, 1m) | 5s |
--proc-path | — | Path to proc filesystem | /proc |
--log-level | — | Log level: debug, info, warn, error | info |
--log-format | — | Output format: json, text | json |
--top | — | Number of top processes to include | 5 |
--push-endpoint | — | HTTP endpoint to push metrics to | — |
--push-token | COLLECTOR_PUSH_TOKEN | Bearer token for push endpoint auth | — |
--hardware-profile | RUNNER_HARDWARE_PROFILE | Hardware profile: JSON, preset name, or empty for auto-detect | auto-detect |
--carbon-provider | RUNNER_CARBON_PROVIDER | Carbon intensity provider: energy-charts (default, full 3-tier: Energy Charts → FfE → static), ffe (legacy alias, same chain), static (static table only) | energy-charts |
--carbon-zone | RUNNER_CARBON_ZONE | Carbon intensity zone | DE |
--pue | RUNNER_PUE | Power Usage Effectiveness multiplier | 1.3 |
Carbon Zone
The carbon zone determines which electricity grid is used for carbon intensity estimation.
| Flag | Env | Default | Description |
|---|---|---|---|
--carbon-zone | RUNNER_CARBON_ZONE | DE | ISO 3166-1 alpha-2 country code for the electricity grid zone |
Supported zones:
| Zone | Country | Typical CI (gCO₂eq/kWh) | Notes |
|---|---|---|---|
AT | Austria | ~67 | Hydro-dominated |
BE | Belgium | ~179 | Gas + nuclear mix |
CH | Switzerland | ~42 | Hydro + nuclear |
DE | Germany | ~258 | Mixed (coal/gas/wind/solar) |
DK | Denmark | ~88 | Wind-heavy |
ES | Spain | ~94 | Solar + wind + gas |
FI | Finland | ~59 | Nuclear + hydro + biomass |
FR | France | ~24 | Nuclear-dominated |
IT | Italy | ~206 | Gas-heavy |
NL | Netherlands | ~369 | Gas-dominated |
NO | Norway | ~28 | Hydro-dominated |
PL | Poland | ~505 | Coal-dominated |
SE | Sweden | ~33 | Hydro + nuclear |
Example:
# French grid (nuclear-dominated, very low CI)
./collector --carbon-zone FR
# Or via environment variable
RUNNER_CARBON_ZONE=PL ./collector
Provider chain per zone:
- DE: Energy Charts → FfE blob projection → static (seasonal/weekday)
- All others: Energy Charts → static (seasonal/weekday table with 192 values)
FfE projection data is only available for Germany. For all other zones, the static fallback provides a seasonal/weekday/hourly profile (192 values) when Energy Charts is unavailable.
CI Context Environment Variables
These environment variables identify the CI run context. They are typically set automatically by GitHub Actions / Forgejo Actions.
| Variable | Description | Example |
|---|---|---|
GITHUB_REPOSITORY_OWNER | Organization name | my-org |
GITHUB_REPOSITORY | Full repository path | my-org/my-repo |
GITHUB_WORKFLOW | Workflow filename | ci.yml |
GITHUB_JOB | Job name | build |
GITHUB_RUN_ID | Unique run identifier | run-123 |
CGROUP_PROCESS_MAP | JSON: process name to container name | {"node":"runner"} |
CGROUP_LIMITS | JSON: per-container CPU/memory limits | See below |
CGROUP_LIMITS Format
{
"runner": { "cpu": "2", "memory": "1Gi" },
"sidecar": { "cpu": "500m", "memory": "256Mi" }
}
CPU supports Kubernetes notation ("2" = 2 cores, "500m" = 0.5 cores). Memory supports Ki, Mi, Gi, Ti (binary) or K, M, G, T (decimal).
Note: The collector reads
GITHUB_REPOSITORY(e.g.,my-org/my-repo) and automatically strips the organization prefix before pushing — the payload’srepositoryfield contains onlymy-repo. When generating push tokens viaPOST /api/v1/token, therepositoryfield must use the short name (without the org prefix).
Receiver Configuration
The receiver stores metric summaries, serves the web UI, and provides the sizing and query APIs.
Receiver Flags
| Flag | Environment Variable | Description | Default |
|---|---|---|---|
--addr | — | HTTP listen address | :8080 |
--db | — | SQLite database path | metrics.db |
--read-token | RECEIVER_READ_TOKEN | Pre-shared token for read/admin endpoints | — |
--hmac-key | RECEIVER_HMAC_KEY | Secret key for push token generation/validation | — |
--token-ttl | — | Time-to-live for push tokens | 2h |
--auth-mode | RECEIVER_AUTH_MODE | Authentication mode: none, oidc, gateway | auto-detect |
--cpu-sizing-mode | RECEIVER_CPU_SIZING_MODE | CPU sizing mode: observe or enforce | observe |
--memory-qos | RECEIVER_MEMORY_QOS | Memory QoS class: guaranteed or burstable | guaranteed |
--log-level | RECEIVER_LOG_LEVEL | Log level: debug, info, warn, error | info |
OIDC / Authentication Flags
| Flag | Environment Variable | Description | Default |
|---|---|---|---|
--oidc-issuer | RECEIVER_OIDC_ISSUER | OIDC issuer URL | — |
--oidc-client-id | RECEIVER_OIDC_CLIENT_ID | OIDC client ID | — |
--oidc-client-secret | RECEIVER_OIDC_CLIENT_SECRET | OIDC client secret | — |
--oidc-redirect-uri | RECEIVER_OIDC_REDIRECT_URI | OIDC redirect URI | — |
--session-ttl | — | Session cookie TTL | 12h |
--session-signing-key | RECEIVER_SESSION_SIGNING_KEY | Hex-encoded 32-byte session signing key | auto-generate |
--cookie-secure | RECEIVER_COOKIE_SECURE | Set Secure flag on auth cookies; disable for plain HTTP | true |
--allowed-org | RECEIVER_ALLOWED_ORG | Allowed organization for OIDC login | — |
--logout-url | RECEIVER_LOGOUT_URL | External logout URL for gateway mode | — |
JWT Claim Mapping
| Flag | Environment Variable | Description | Default |
|---|---|---|---|
--claim-sub | RECEIVER_CLAIM_SUB | JWT claim for user ID | sub |
--claim-name | RECEIVER_CLAIM_NAME | JWT claim for display name | name |
--claim-email | RECEIVER_CLAIM_EMAIL | JWT claim for email | email |
--claim-groups | RECEIVER_CLAIM_GROUPS | JWT claim for groups array | groups |
--claim-org | RECEIVER_CLAIM_ORG | JWT claim for organization | org |
--org-from-groups | RECEIVER_ORG_FROM_GROUPS | Org extraction from groups: first, match, none | first |
GARM Integration Flags
| Flag | Environment Variable | Description | Default |
|---|---|---|---|
--garm-url | GARM_URL | GARM base URL for WebSocket event enrichment | — |
--garm-user | GARM_USER | GARM username for JWT authentication | — |
--garm-password | GARM_PASSWORD | GARM password for JWT authentication | — |
--garm-cache-ttl | GARM_CACHE_TTL | TTL for pending GARM event cache | 60s |
OOM Detection & Notification Flags
| Flag | Environment Variable | Description | Default |
|---|---|---|---|
--max-memory | RECEIVER_MAX_MEMORY | Node ceiling for memory (overrides auto-detection from /proc/meminfo) | auto (90% node RAM) |
--max-cpu | RECEIVER_MAX_CPU | Node ceiling for CPU | auto |
--notify-enabled | RECEIVER_NOTIFY_ENABLED | Enable commit status notifications on OOM | false |
--notify-base-url | RECEIVER_NOTIFY_BASE_URL | Forge base URL (auto-detected if unset) | — |
--notify-token | RECEIVER_NOTIFY_TOKEN | API token for forge commit status API | — |
Multi-Provider Flags
| Flag | Environment Variable | Description | Default |
|---|---|---|---|
--ci-provider | CI_PROVIDER | CI provider: forgejo, github, gitlab | forgejo |
GitLab-Specific Variables
These variables are relevant when CI_PROVIDER=gitlab:
| Variable | Description | Default |
|---|---|---|
CI_SIZER_RUNNER_NAME | Override runner name (defaults to pod name for GitLab) | pod name |
CGROUP_STRATEGY | Cgroup mapping strategy: default or exclusion | default |
Set CGROUP_STRATEGY=exclusion for GitLab pods where the build container process name is unpredictable. See GitLab Integration for details.
Authentication Modes
CI Sizer supports three authentication modes, configured via --auth-mode:
| Mode | Description |
|---|---|
none | Token-only authentication. All protected endpoints accept the Bearer read token. |
oidc | Direct OIDC login via Dex, Keycloak, or Entra ID. Most endpoints require an OIDC session cookie; sizing endpoints also accept a Bearer read token for programmatic access. |
gateway | External API gateway (e.g., APISIX) handles authentication and forwards JWTs. All protected endpoints accept the gateway JWT or Bearer read token. |
When --auth-mode is not set, the receiver auto-detects: if --oidc-client-id is provided, it defaults to oidc; otherwise it defaults to none.
Kubernetes Deployment
Receiver Deployment
docker build -f Dockerfile --target receiver -t ci-sizer-receiver:local .
kubectl create namespace ci-sizer
kubectl -n ci-sizer create secret generic receiver-secrets \
--from-literal=read-token=my-secret-token \
--from-literal=hmac-key=my-hmac-key
apiVersion: apps/v1
kind: Deployment
metadata:
name: receiver
spec:
replicas: 1
selector:
matchLabels:
app: receiver
template:
metadata:
labels:
app: receiver
spec:
containers:
- name: receiver
image: ci-sizer-receiver:local
ports:
- containerPort: 8080
env:
- name: RECEIVER_READ_TOKEN
valueFrom:
secretKeyRef:
name: receiver-secrets
key: read-token
- name: RECEIVER_HMAC_KEY
valueFrom:
secretKeyRef:
name: receiver-secrets
key: hmac-key
args: ["--addr=:8080", "--db=/data/metrics.db"]
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
emptyDir: {}
For persistent storage, replace the
emptyDirvolume with aPersistentVolumeClaim.
For plain HTTP deployments (local dev, port-forward), set
RECEIVER_COOKIE_SECURE=falseto prevent OIDC login failures caused by browsers rejectingSecurecookies over HTTP.
Collector Sidecar
The collector runs as a sidecar in CI pods with shareProcessNamespace: true. Generate a push token first, then deploy:
apiVersion: v1
kind: Pod
metadata:
name: ci-run-test
spec:
shareProcessNamespace: true
restartPolicy: Never
containers:
- name: runner
image: busybox:latest
command: ["/bin/sh", "-c", "while true; do dd if=/dev/zero of=/dev/null bs=1M count=100 2>/dev/null; sleep 1; done"]
resources:
limits:
cpu: "500m"
memory: "256Mi"
- name: collector
image: ci-sizer-collector:local
args: ["--interval=2s", "--top=5", "--push-endpoint=http://receiver.ci-sizer.svc.cluster.local/api/v1/metrics"]
env:
- name: COLLECTOR_PUSH_TOKEN
value: "<PUSH_TOKEN>"
- name: GITHUB_REPOSITORY_OWNER
value: "my-org"
- name: GITHUB_REPOSITORY
value: "my-org/my-repo"
- name: GITHUB_WORKFLOW
value: "ci.yml"
- name: GITHUB_JOB
value: "build"
- name: GITHUB_RUN_ID
value: "test-run-001"
resources:
limits:
cpu: "100m"
memory: "64Mi"