Skip to main content
Version: 1.0-beta

engine.json

The Dagger Engine reads /etc/dagger/engine.json at startup. A missing file uses the default settings. If the file has a key that the engine does not know, the engine does not start.

  • Helm chart: put the file contents in the engine.configJson value. The chart restarts the engine pods when the value changes
  • Engine container started by hand: mount the file at /etc/dagger/engine.json, then restart the container after each change

The machine-readable schema is published at engine.schema.json.

A few settings are only available in engine.toml. See Settings only in engine.toml.

Log level​

logLevel sets how much the engine logs:

{
"logLevel": "info"
}

From the quietest to the most verbose, the levels are error, warn, info, debug, debugextra, and trace. The default is debug.

Registries​

registries changes how the engine connects to a container registry. Use it to pull through a mirror, to use a registry that does not have TLS, or to trust a private certificate authority. Each key is a registry host, with its port if it is not the default:

{
"registries": {
"docker.io": {
"mirrors": ["mirror.internal:5000"]
},
"mirror.internal:5000": {
"http": true
},
"registry.internal": {
"ca": ["/etc/dagger/certs/internal-ca.pem"]
}
}
}
  • mirrors: hosts that the engine tries first when it pulls from this registry. If a mirror is not available, the engine pulls from the registry
  • http: connect with HTTP instead of HTTPS
  • insecure: connect with HTTPS, but do not verify the certificate of the registry
  • ca: certificate authority files that the engine trusts for this registry. The paths are in the engine container, so mount the files there

A mirror is a registry host too. If the mirror uses HTTP or a private certificate authority, give it its own entry, as mirror.internal:5000 has above.

Security​

By default, a Container.withExec call can set insecureRootCapabilities to run with full root capabilities. To refuse these calls on the engine, set security.insecureRootCapabilities to false:

{
"security": {
"insecureRootCapabilities": false
}
}

A call that asks for these capabilities then fails with security.insecure is not allowed.

Garbage collection​

The engine prunes its local cache automatically. The gc settings control how much disk space the cache may use:

{
"gc": {
"maxUsedSpace": "200GB",
"reservedSpace": "10GB",
"minFreeSpace": "20%"
}
}
  • maxUsedSpace: when the cache grows larger than this, the engine prunes it back to this size.
  • reservedSpace: pruning for maxUsedSpace aims to keep at least this much of the cache.
  • minFreeSpace: when free disk space falls below this, the engine prunes enough of the cache to restore it.

These are targets. The engine prunes whole cache entries, so a pass can remove more than its target asks for.

A disk space value is a number of bytes (512000000), a size with a unit ("512MB"), or a percentage of the disk holding the engine state ("10%"). The defaults are a reservedSpace of 10% of the disk up to 10GB, a minFreeSpace of 20%, and a maxUsedSpace of 75%.

The engine turns these settings into a list of pruning policies. To control pruning in more detail, set gc.policies instead. Each policy can match entries by filter and has its own space settings. A policy's keepDuration keeps entries used within that time out of the policy, even when free space is below minFreeSpace. An entry whose cache TTL has expired is not kept. End a custom list with a policy that matches all entries, has space settings, and has no keepDuration, so recent entries can still be pruned when the disk fills:

{
"gc": {
"policies": [
{
"keepDuration": "72h",
"maxUsedSpace": "75%",
"minFreeSpace": "20%"
},
{
"all": true,
"maxUsedSpace": "75%",
"reservedSpace": "10GB",
"minFreeSpace": "20%"
}
]
}
}

Other gc settings:

  • enabled: set to false to turn off garbage collection. Do this only for a short-lived engine, because the cache then grows until the disk is full
  • sweepSize: the minimum amount of space that one pruning pass removes. It is a disk space value, or a percentage of the space between reservedSpace and maxUsedSpace
  • dagqlCache.maxEstimatedBytes and dagqlCache.targetEstimatedBytes: limits for the in-memory metadata cache, in bytes. When the estimated size is larger than maxEstimatedBytes, the engine prunes it down to targetEstimatedBytes. Zero uses the built-in default

Engine resource metrics​

Engine resource metrics are disabled by default. Enable them explicitly:

{
"telemetry": {
"resourceMetrics": true
}
}

Configure the exporter in the engine process environment:

OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=https://collector.example/v1/metrics
OTEL_EXPORTER_OTLP_METRICS_PROTOCOL=http/protobuf

The metrics endpoint is required. For HTTP, include the full path, such as /v1/metrics. A generic OTEL_EXPORTER_OTLP_ENDPOINT alone does not enable engine resource export. If resource metrics are enabled without a metrics endpoint, the engine logs a warning and continues without resource export.

The protocol defaults to http/protobuf; grpc is also supported. The metrics-specific protocol setting takes precedence over OTEL_EXPORTER_OTLP_PROTOCOL. The standard OTel exporter also reads the supported environment settings for headers, TLS, compression, and timeouts. See OTLP exporter configuration.

Collection uses the OTel periodic reader. Its default interval is 60 seconds; OTEL_METRIC_EXPORT_INTERVAL sets the interval in milliseconds. Each collection reads the cgroup files directly. A graceful engine shutdown collects a final sample with a bounded timeout; an abrupt termination can lose the last sample.

Separation from client telemetry​

Engine resource metrics use a separate meter provider, reader, and exporter. They do not use client telemetry providers or the client telemetry proxy. Client and execution metrics, traces, logs, and Prometheus reporting keep their existing configuration and routes.

Setting an OTLP endpoint does not enable engine resource metrics on its own. In particular, an endpoint injected into a nested engine does not enable this feature unless that engine also has telemetry.resourceMetrics set to true. A deliberately enabled nested engine still needs a compatible OTLP receiver; the client proxy is not the receiver for this stream.

Accounting boundary​

The engine discovers its unified cgroup from /proc/self/cgroup. It reports CPU, memory, and network bytes charged to that cgroup, including its descendants. Network bytes are split by direction and by internal or external traffic. In the standard layout, engine processes and helpers are in /init, while user containers, including nested engines, are in sibling /buildkit cgroups. Those user workloads are excluded from the parent engine's resource metrics. A different layout or a configured execution parent below the engine cgroup can include user workloads.

CPU time values are cumulative microseconds. Memory values are bytes; memory peak is the cgroup-lifetime peak, not an interval maximum. Missing cgroup sources are reported through availability metrics and do not prevent engine startup. Enabling export does not classify an engine as a managed Daggerland engine or change cgroup placement.

CPU throttling​

dagger.engine.cpu.throttled.time and dagger.engine.cpu.periods report CPU quota enforcement statistics from the engine process cgroup's cpu.stat. The period metric counts total and throttled quota enforcement periods, not general CPU scheduling periods. These counters apply only to this cgroup's own quota. They exclude throttling caused by ancestor cgroups.

For example, a container CPU limit can apply at the parent of both /init and /buildkit:

Engine container cgroup (CPU quota)
├── /init (engine metrics)
└── /buildkit (user workloads)

That parent quota can prevent /init from running while /init/cpu.stat still reports zero throttling. A zero value does not mean that the engine was not throttled. CPU usage still reports the CPU time actually consumed by the observed cgroup and its descendants.

See the Linux cgroup v2 CPU interface documentation.

Settings only in engine.toml​

The engine also reads /etc/dagger/engine.toml, which uses the BuildKit buildkitd.toml format. Use it only for the settings in this section. With the Helm chart, put the file contents in the engine.config value. Otherwise, mount the file at /etc/dagger/engine.toml.

Registry client certificates​

If a registry requires a client certificate, set a keypair for it:

[registry."registry.internal:5000"]
ca = ["/etc/dagger/certs/ca.pem"]

[[registry."registry.internal:5000".keypair]]
key = "/etc/dagger/certs/client.key"
cert = "/etc/dagger/certs/client.pem"

Keep all the settings for this registry in engine.toml. An engine.json entry for the same host replaces the engine.toml entry, including its keypair.

DNS search domains and options​

[dns] adds search domains and resolver options to /etc/resolv.conf in each container that the engine runs:

[dns]
searchDomains = ["corp.example"]
options = ["ndots:2"]

The engine sets the name server itself, so nameservers has no effect.

Precedence​

When both files configure the same thing, engine.json wins:

  • logLevel replaces debug and trace
  • security replaces insecure-entitlements
  • A registries entry replaces the [registry] entry for the same host
  • gc.policies replaces the engine.toml policies and space settings. The engine.toml setting gckeepstorage corresponds to reservedSpace, so on its own it does not limit the cache size