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.configJsonvalue. 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 registryhttp: connect with HTTP instead of HTTPSinsecure: connect with HTTPS, but do not verify the certificate of the registryca: 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 formaxUsedSpaceaims 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 tofalseto turn off garbage collection. Do this only for a short-lived engine, because the cache then grows until the disk is fullsweepSize: the minimum amount of space that one pruning pass removes. It is a disk space value, or a percentage of the space betweenreservedSpaceandmaxUsedSpacedagqlCache.maxEstimatedBytesanddagqlCache.targetEstimatedBytes: limits for the in-memory metadata cache, in bytes. When the estimated size is larger thanmaxEstimatedBytes, the engine prunes it down totargetEstimatedBytes. 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:
logLevelreplacesdebugandtracesecurityreplacesinsecure-entitlements- A
registriesentry replaces the[registry]entry for the same host gc.policiesreplaces theengine.tomlpolicies and space settings. Theengine.tomlsettinggckeepstoragecorresponds toreservedSpace, so on its own it does not limit the cache size