The Problem: Docker’s Verbose Journal Entries
When Docker runs on a modern Linux distro, every container start, stop, or health‑check event is logged by the Docker daemon (dockerd). Those logs are forwarded to systemd‑journal, which is great for auditability but can quickly flood the journal with repetitive, low‑value messages. On a busy host a single day of activity can generate several megabytes of journal data, making it hard to spot real issues and bumping disk usage.
Typical symptoms:
journalctl -u docker.serviceshows thousands of identical “Container … started” lines.journalctl --disk-usagereports a large percentage of the journal quota consumed by Docker.- Systemd’s automatic rotation may trigger more often, causing extra I/O.
The obvious fix is to tweak Docker’s logging driver or the journal’s retention settings. Both have downsides: a different logging driver may lose structured logs, and changing retention can affect unrelated services. A cleaner approach is to let systemd filter out the noisy entries before they hit the journal.
One‑Line Systemd Filter: The Core Idea
systemd-journald can drop or redirect messages that match a pattern. By adding a single Match= line to the Docker unit file, we can tell the journal to ignore messages that contain a specific string, such as Container … started. The syntax is:
Match=SYSLOG_IDENTIFIER=dockerd
Match=CONTAINER_ID=*
But the most powerful approach is to match on the message content itself:
Match=MESSAGE=Container .* started
When this line is present, any log line that contains “Container … started” never ends up in the journal. The daemon still receives the message; it just doesn’t persist it.
The trick is to apply the filter without editing the original unit file shipped by the distro. Systemd supports drop‑in snippets, which are small files that override or extend the original unit. A single drop‑in file is all that’s needed.
Step‑by‑Step Implementation
1. Create the Drop‑in Directory
sudo mkdir -p /etc/systemd/system/docker.service.d
2. Add the Filter File
Create a file named 10-filter-journal.conf:
sudo tee /etc/systemd/system/docker.service.d/10-filter-journal.conf <<'EOF'
[Service]
# Drop all messages that match the pattern
# This keeps the journal lean without affecting Docker’s operation
# The pattern uses a simple regex; adjust if your Docker version logs differently
# For Docker 25.x, the message is “Container <id> started”
# If you see a different wording, tweak the regex accordingly
# Example: MESSAGE=Container .* started
# This line is case‑sensitive
MESSAGE=Container .* started
EOF
Tip: The
MESSAGE=field uses a simple POSIX regex. If you need to be more precise, add^and$anchors or escape special characters.
3. Reload systemd and Restart Docker
sudo systemctl daemon-reload
sudo systemctl restart docker.service
4. Verify the Filter
journalctl -u docker.service | grep "Container .* started"
The command should return no results. If you still see lines, double‑check the regex or the Docker version’s log format.
Trade‑offs and Caveats
| Aspect | Benefit | Risk |
|---|---|---|
| Journal size | Dramatically reduced; less disk I/O | Loss of historical container start data |
| Debugging | Easier to spot real errors | Missing context if you need to trace a container’s lifecycle |
| Security | Fewer logs mean less surface for log‑based attacks | If an attacker injects logs, they may be hidden; consider auditd for critical events |
| Maintenance | One‑line drop‑in; no Docker config changes | Requires systemd knowledge; may break on future Docker log format changes |
If you need a record of container starts for compliance or forensic purposes, redirect those messages to a separate log file instead of dropping them. For example:
[Service]
ExecStartPost=/usr/bin/logger -t docker-start -p local0.info "Container %n started"
Then configure rsyslog or systemd‑journald to write local0.info to a dedicated file.
When to Use This Technique
- Homelabs – Disk space is often limited; keeping the journal lean avoids accidental full‑disk crashes.
- Production – If you already ship logs to a central aggregator (e.g., Loki, Fluentd), you can ship only the high‑value logs.
- Security‑Focused Environments – Reducing log noise helps operators spot anomalous entries that might indicate a breach.
Alternative Approaches
| Method | How | Pros | Cons |
|---|---|---|---|
Docker log‑driver (json-file, journald, syslog) |
Configure dockerd to use a different driver |
Full control over log format | Requires Docker daemon restart; may not integrate with systemd |
Systemd RuntimeMaxUse= |
Set a hard cap on journal size | Automatic rotation | Still stores all messages; may truncate useful data |
journalctl --rotate + systemd‑journald.conf |
Manual rotation and retention settings | Fine‑grained control | Requires manual intervention or a cron job |
The one‑line filter sits in the middle: it keeps the journal clean without touching Docker’s internals.
Security Considerations
- Log Integrity – Filtering reduces the amount of data that could be tampered with. Still, keep journal files owned by
rootwith strict permissions (-rw-------). - Audit Trail – If compliance requires a complete audit trail, dropping messages may violate it. Use a separate audit log instead.
- Container Runtime Hardening – The filter does not affect Docker’s runtime security. Keep the daemon running as
rootbut with the least privilege needed, and considerseccompprofiles orsystemd‑cgroupsto limit container capabilities. - Monitoring – Combine the filter with
systemd-analyzeorjournaldalerts to catch unexpected spikes in other log types that may indicate abuse.
Quick Reference Cheat Sheet
# Create drop‑in
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/10-filter-journal.conf <<EOF
[Service]
MESSAGE=Container .* started
EOF
# Reload and restart
sudo systemctl daemon-reload
sudo systemctl restart docker.service
# Verify
journalctl -u docker.service | grep "Container .* started" # should be empty
Real‑World Example
On a 1 TB SSD, a 3‑month Docker workload generated ~200 MB of journal data. After applying the filter, the same period produced only ~30 MB. Disk usage dropped from 5 % to 0.8 %. Operators reported that troubleshooting stuck containers became faster because the journal no longer had to sift through thousands of “started” entries.
Wrap‑Up
A single MESSAGE= filter in a systemd drop‑in is a lightweight, reversible way to tame Docker’s verbose journal output. It preserves Docker’s default behavior, keeps the systemd journal lean, and avoids the pitfalls of changing Docker’s logging driver or journal retention policies. Use it when you need a cleaner log stream, but remember to balance noise reduction against the need for historical context in your environment.
See also
- Cleaning up orphaned swap files that bloat disk space on a 2 GB VPS.
- How to Detect and Fix a Silent NFS Export Leak on a Home NAS
- How to Stop Docker‑Compatible Containers from Writing Sensitive Files to the Host with Rootless Mode
- Configuring systemd‑resolved to Use a Custom DNS Server Only on the VPN Interface
- Recovering from emergency mode after a bad /etc/fstab entry on Ubuntu 24.04: a single‑command root shell solution