
You added a logging limit, but the disk still grows. Two different questions come first: is the growth actually Docker-captured output, and did the container acquire the new configuration?
A historical Stack Overflow question describes growing overlay2 storage even after its author added logging limits and recreated containers. That report does not prove the logging change failed: application files, writable layers and volumes are separate from the logging driver's stdout/stderr storage. This guide uses Docker's current documentation to make that distinction and plan a verifiable change. It is not a diagnosis of that author's machine or a measured rotation experiment.
1. Identify the storage source and effective settings
First use the filesystem and directory checks to identify the affected volume, inode pressure and what is actually growing. Docker logging options govern captured container stdout/stderr. They do not rotate a web server's private file inside a volume, shrink a database, remove images or cap the whole writable layer.
On the intended Docker host or context, these commands inspect configuration. Replace CONTAINER with one actual container name or ID:
docker context show
docker version
docker info --format '{{.LoggingDriver}}'
docker inspect --type container --format '{{json .HostConfig.LogConfig}}' CONTAINER
docker inspect --type container --format '{{.Id}} {{.Created}}' CONTAINER
The daemon default and a container's effective logging configuration answer different questions. A service can override the default, and an existing container can retain the options it had at creation. Record both the container ID and creation time for the later comparison. Empty per-container options can mean inherited defaults; compare them with the driver's documented defaults rather than treating an empty map as proof of rotation.
2. Choose the driver for your collection path
| Choice | Useful distinction |
|---|---|
json-file | Docker's default. Without a size limit it does not rotate by default. Set max-size; max-file is only effective when size rotation is enabled. |
local | Docker recommends it for many non-Kubernetes situations. It rotates and compresses by default, using its own internal format. Check compatibility with your collector before switching. |
Docker documents the local driver's default as five files of 20m each, with automatic compression. Those defaults describe that driver's behavior, not a universal budget for a small VPS. A collector that tails Docker's JSON files may need a different integration before you switch to local.
For a service whose collector supports local, merge the following logging fragment into that service in your real Compose file. app is a placeholder service name; the fragment intentionally has no image and is not a complete application:
services:
app:
logging:
driver: local
options:
max-size: "10m"
max-file: "3"
If your collector requires json-file, use the alternative downloadable fragment with driver: json-file and the same example limits. Choose one configuration for the real service. The values are examples to review against observed output growth, required history and available storage.
10m × 3 is a useful first look at the configured file window, not an exact whole-host disk cap or a retention-time promise. Other containers, application files, metadata and temporary decompression work need space too. A busy application will cycle through the same size window much sooner than a quiet one.
Daemon defaults are a different change
The downloadable daemon JSON shows the equivalent local-driver defaults. Merge the reviewed keys with existing settings; do not replace an existing daemon.json with this small example. Docker documents a daemon restart for a default configuration change, and the new defaults apply to newly created containers. Existing containers do not automatically adopt them. A per-service Compose change avoids needing a daemon-wide default change for this particular task.
3. Validate the intended change, then verify the new container
- Preserve the original service definition and logging configuration. Check persistent data, dependencies, collector support, required log history and a rollback path before approving a recreation. Recreating a container may interrupt the service and replace its writable layer.
- Validate the real merged Compose files. Use
docker compose -f compose.yaml config --quiet, adding the same-ffiles and environment inputs your deployment uses. This validates a configuration model, not runtime rotation. A rendered configuration can contain interpolated secrets; keep it private. - Recreate only the reviewed service through its existing deployment process. A plain container restart is not a recreation. Docker's Compose restart reference explicitly says file changes are not applied by
docker compose restart. This guide does not run a deployment or supply a blanket force-recreate command. - Inspect the actual replacement. Repeat the ID, creation-time and
HostConfig.LogConfigchecks above. A changed source file is not evidence that the running container uses it. - Check the application and the collection path. Confirm intended persistent data and health, emit a small known application message and verify both
docker logsand any external collector. Being able to read one message does not prove rotation or the required retained history. - Rehearse the size boundary in a disposable environment. Record driver/version, chosen limits, known output sequence, what remains readable and any errors. Do not fill a production filesystem to test the limit. Until this check is performed, record rotation acceptance as not run.
4. Rotation and delivery are separate choices
Docker's default delivery mode is blocking. Non-blocking delivery uses an intermediate per-container buffer; Docker documents that new messages are dropped when that buffer is full. It can protect an application from blocked log delivery while sacrificing messages. It is not a way to guarantee both availability and complete history, and it does not replace file-rotation settings. The example fragments leave delivery mode unchanged.
Similarly, rotation is not an off-host archive. If you need audit history or recovery after host loss, define and validate a separate collection and retention path. Keep its capacity and failure behavior in the job's run record.
Configuration examples and change checklist
The YAML and JSON examples were parsed locally to check structure and string-valued options. They were not passed to Docker Compose or Engine, and we did not migrate a service or measure runtime rotation. The checklist is blank so unperformed checks remain visible. Read and adapt it before a change.
What this does not fix
Do not edit, delete or truncate Docker-managed log files to implement this method: the driver documentation says those files are for exclusive daemon access. Rotation also cannot free an unrelated deleted-open application file, shrink a volume or validate a backup. Use the disk investigation guide for the first distinction and the backup peak-space guide for recovery workspace. If growth continues, return to the source inventory instead of increasing the scope of cleanup.
Sources
- Docker: Configure logging drivers — defaults, creation-time configuration and delivery modes.
- Docker: JSON File logging driver — size/count options and managed-file access.
- Docker: Local file logging driver — rotation, compression and defaults.
- Compose services: logging — service-level driver and options.
- Compose restart and Compose config — restart versus changed configuration, and model validation.
Documentation checked November 7, 2026 (Asia/Shanghai). For an ordered route through related material, start with the storage reading path.