This patch adds a new "prune" event type to indicate that pruning of a resource
type completed.
This event-type can be used on systems that want to perform actions after
resources have been cleaned up. For example, Docker Desktop performs an fstrim
after resources are deleted (https://github.com/linuxkit/linuxkit/tree/v0.7/pkg/trim-after-delete).
While the current (remove, destroy) events can provide information on _most_
resources, there is currently no event triggered after the BuildKit build-cache
is cleaned.
Prune events have a `reclaimed` attribute, indicating the amount of space that
was reclaimed (in bytes). The attribute can be used, for example, to use as a
threshold for performing fstrim actions. Reclaimed space for `network` events
will always be 0, but the field is added to be consistent with prune events for
other resources.
To test this patch:
Create some resources:
for i in foo bar baz; do \
docker network create network_$i \
&& docker volume create volume_$i \
&& docker run -d --name container_$i -v volume_$i:/volume busybox sh -c 'truncate -s 5M somefile; truncate -s 5M /volume/file' \
&& docker tag busybox:latest image_$i; \
done;
docker pull alpine
docker pull nginx:alpine
echo -e "FROM busybox\nRUN truncate -s 50M bigfile" | DOCKER_BUILDKIT=1 docker build -
Start listening for "prune" events in another shell:
docker events --filter event=prune
Prune containers, networks, volumes, and build-cache:
docker system prune -af --volumes
See the events that are returned:
docker events --filter event=prune
2020-07-25T12:12:09.268491000Z container prune (reclaimed=15728640)
2020-07-25T12:12:09.447890400Z network prune (reclaimed=0)
2020-07-25T12:12:09.452323000Z volume prune (reclaimed=15728640)
2020-07-25T12:12:09.517236200Z image prune (reclaimed=21568540)
2020-07-25T12:12:09.566662600Z builder prune (reclaimed=52428841)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
| ... | ... |
@@ -3,12 +3,15 @@ package build // import "github.com/docker/docker/api/server/backend/build" |
| 3 | 3 |
import ( |
| 4 | 4 |
"context" |
| 5 | 5 |
"fmt" |
| 6 |
+ "strconv" |
|
| 6 | 7 |
|
| 7 | 8 |
"github.com/docker/distribution/reference" |
| 8 | 9 |
"github.com/docker/docker/api/types" |
| 9 | 10 |
"github.com/docker/docker/api/types/backend" |
| 11 |
+ "github.com/docker/docker/api/types/events" |
|
| 10 | 12 |
"github.com/docker/docker/builder" |
| 11 | 13 |
buildkit "github.com/docker/docker/builder/builder-next" |
| 14 |
+ daemonevents "github.com/docker/docker/daemon/events" |
|
| 12 | 15 |
"github.com/docker/docker/image" |
| 13 | 16 |
"github.com/docker/docker/pkg/stringid" |
| 14 | 17 |
"github.com/pkg/errors" |
| ... | ... |
@@ -31,11 +34,12 @@ type Backend struct {
|
| 31 | 31 |
builder Builder |
| 32 | 32 |
imageComponent ImageComponent |
| 33 | 33 |
buildkit *buildkit.Builder |
| 34 |
+ eventsService *daemonevents.Events |
|
| 34 | 35 |
} |
| 35 | 36 |
|
| 36 | 37 |
// NewBackend creates a new build backend from components |
| 37 |
-func NewBackend(components ImageComponent, builder Builder, buildkit *buildkit.Builder) (*Backend, error) {
|
|
| 38 |
- return &Backend{imageComponent: components, builder: builder, buildkit: buildkit}, nil
|
|
| 38 |
+func NewBackend(components ImageComponent, builder Builder, buildkit *buildkit.Builder, es *daemonevents.Events) (*Backend, error) {
|
|
| 39 |
+ return &Backend{imageComponent: components, builder: builder, buildkit: buildkit, eventsService: es}, nil
|
|
| 39 | 40 |
} |
| 40 | 41 |
|
| 41 | 42 |
// RegisterGRPC registers buildkit controller to the grpc server. |
| ... | ... |
@@ -100,6 +104,11 @@ func (b *Backend) PruneCache(ctx context.Context, opts types.BuildCachePruneOpti |
| 100 | 100 |
if err != nil {
|
| 101 | 101 |
return nil, errors.Wrap(err, "failed to prune build cache") |
| 102 | 102 |
} |
| 103 |
+ b.eventsService.Log("prune", events.BuilderEventType, events.Actor{
|
|
| 104 |
+ Attributes: map[string]string{
|
|
| 105 |
+ "reclaimed": strconv.FormatInt(buildCacheSize, 10), |
|
| 106 |
+ }, |
|
| 107 |
+ }) |
|
| 103 | 108 |
return &types.BuildCachePruneReport{SpaceReclaimed: uint64(buildCacheSize), CachesDeleted: cacheIDs}, nil
|
| 104 | 109 |
} |
| 105 | 110 |
|
| ... | ... |
@@ -8131,13 +8131,13 @@ paths: |
| 8131 | 8131 |
|
| 8132 | 8132 |
Various objects within Docker report events when something happens to them. |
| 8133 | 8133 |
|
| 8134 |
- Containers report these events: `attach`, `commit`, `copy`, `create`, `destroy`, `detach`, `die`, `exec_create`, `exec_detach`, `exec_start`, `exec_die`, `export`, `health_status`, `kill`, `oom`, `pause`, `rename`, `resize`, `restart`, `start`, `stop`, `top`, `unpause`, and `update` |
|
| 8134 |
+ Containers report these events: `attach`, `commit`, `copy`, `create`, `destroy`, `detach`, `die`, `exec_create`, `exec_detach`, `exec_start`, `exec_die`, `export`, `health_status`, `kill`, `oom`, `pause`, `rename`, `resize`, `restart`, `start`, `stop`, `top`, `unpause`, `update`, and `prune` |
|
| 8135 | 8135 |
|
| 8136 |
- Images report these events: `delete`, `import`, `load`, `pull`, `push`, `save`, `tag`, and `untag` |
|
| 8136 |
+ Images report these events: `delete`, `import`, `load`, `pull`, `push`, `save`, `tag`, `untag`, and `prune` |
|
| 8137 | 8137 |
|
| 8138 |
- Volumes report these events: `create`, `mount`, `unmount`, and `destroy` |
|
| 8138 |
+ Volumes report these events: `create`, `mount`, `unmount`, `destroy`, and `prune` |
|
| 8139 | 8139 |
|
| 8140 |
- Networks report these events: `create`, `connect`, `disconnect`, `destroy`, `update`, and `remove` |
|
| 8140 |
+ Networks report these events: `create`, `connect`, `disconnect`, `destroy`, `update`, `remove`, and `prune` |
|
| 8141 | 8141 |
|
| 8142 | 8142 |
The Docker daemon reports these events: `reload` |
| 8143 | 8143 |
|
| ... | ... |
@@ -8149,6 +8149,8 @@ paths: |
| 8149 | 8149 |
|
| 8150 | 8150 |
Configs report these events: `create`, `update`, and `remove` |
| 8151 | 8151 |
|
| 8152 |
+ The Builder reports `prune` events |
|
| 8153 |
+ |
|
| 8152 | 8154 |
operationId: "SystemEvents" |
| 8153 | 8155 |
produces: |
| 8154 | 8156 |
- "application/json" |
| ... | ... |
@@ -1,6 +1,8 @@ |
| 1 | 1 |
package events // import "github.com/docker/docker/api/types/events" |
| 2 | 2 |
|
| 3 | 3 |
const ( |
| 4 |
+ // BuilderEventType is the event type that the builder generates |
|
| 5 |
+ BuilderEventType = "builder" |
|
| 4 | 6 |
// ContainerEventType is the event type that containers generate |
| 5 | 7 |
ContainerEventType = "container" |
| 6 | 8 |
// DaemonEventType is the event type that daemon generate |
| ... | ... |
@@ -299,7 +299,7 @@ func newRouterOptions(config *config.Config, d *daemon.Daemon) (routerOptions, e |
| 299 | 299 |
return opts, err |
| 300 | 300 |
} |
| 301 | 301 |
|
| 302 |
- bb, err := buildbackend.NewBackend(d.ImageService(), manager, bk) |
|
| 302 |
+ bb, err := buildbackend.NewBackend(d.ImageService(), manager, bk, d.EventsService) |
|
| 303 | 303 |
if err != nil {
|
| 304 | 304 |
return opts, errors.Wrap(err, "failed to create buildmanager") |
| 305 | 305 |
} |
| ... | ... |
@@ -3,11 +3,13 @@ package images // import "github.com/docker/docker/daemon/images" |
| 3 | 3 |
import ( |
| 4 | 4 |
"context" |
| 5 | 5 |
"fmt" |
| 6 |
+ "strconv" |
|
| 6 | 7 |
"sync/atomic" |
| 7 | 8 |
"time" |
| 8 | 9 |
|
| 9 | 10 |
"github.com/docker/distribution/reference" |
| 10 | 11 |
"github.com/docker/docker/api/types" |
| 12 |
+ "github.com/docker/docker/api/types/events" |
|
| 11 | 13 |
"github.com/docker/docker/api/types/filters" |
| 12 | 14 |
timetypes "github.com/docker/docker/api/types/time" |
| 13 | 15 |
"github.com/docker/docker/errdefs" |
| ... | ... |
@@ -159,7 +161,11 @@ deleteImagesLoop: |
| 159 | 159 |
if canceled {
|
| 160 | 160 |
logrus.Debugf("ImagesPrune operation cancelled: %#v", *rep)
|
| 161 | 161 |
} |
| 162 |
- |
|
| 162 |
+ i.eventsService.Log("prune", events.ImageEventType, events.Actor{
|
|
| 163 |
+ Attributes: map[string]string{
|
|
| 164 |
+ "reclaimed": strconv.FormatUint(rep.SpaceReclaimed, 10), |
|
| 165 |
+ }, |
|
| 166 |
+ }) |
|
| 163 | 167 |
return rep, nil |
| 164 | 168 |
} |
| 165 | 169 |
|
| ... | ... |
@@ -4,10 +4,12 @@ import ( |
| 4 | 4 |
"context" |
| 5 | 5 |
"fmt" |
| 6 | 6 |
"regexp" |
| 7 |
+ "strconv" |
|
| 7 | 8 |
"sync/atomic" |
| 8 | 9 |
"time" |
| 9 | 10 |
|
| 10 | 11 |
"github.com/docker/docker/api/types" |
| 12 |
+ "github.com/docker/docker/api/types/events" |
|
| 11 | 13 |
"github.com/docker/docker/api/types/filters" |
| 12 | 14 |
timetypes "github.com/docker/docker/api/types/time" |
| 13 | 15 |
"github.com/docker/docker/errdefs" |
| ... | ... |
@@ -84,7 +86,9 @@ func (daemon *Daemon) ContainersPrune(ctx context.Context, pruneFilters filters. |
| 84 | 84 |
rep.ContainersDeleted = append(rep.ContainersDeleted, c.ID) |
| 85 | 85 |
} |
| 86 | 86 |
} |
| 87 |
- |
|
| 87 |
+ daemon.EventsService.Log("prune", events.ContainerEventType, events.Actor{
|
|
| 88 |
+ Attributes: map[string]string{"reclaimed": strconv.FormatUint(rep.SpaceReclaimed, 10)},
|
|
| 89 |
+ }) |
|
| 88 | 90 |
return rep, nil |
| 89 | 91 |
} |
| 90 | 92 |
|
| ... | ... |
@@ -210,7 +214,9 @@ func (daemon *Daemon) NetworksPrune(ctx context.Context, pruneFilters filters.Ar |
| 210 | 210 |
return rep, nil |
| 211 | 211 |
default: |
| 212 | 212 |
} |
| 213 |
- |
|
| 213 |
+ daemon.EventsService.Log("prune", events.NetworkEventType, events.Actor{
|
|
| 214 |
+ Attributes: map[string]string{"reclaimed": "0"},
|
|
| 215 |
+ }) |
|
| 214 | 216 |
return rep, nil |
| 215 | 217 |
} |
| 216 | 218 |
|
| ... | ... |
@@ -17,6 +17,10 @@ keywords: "API, Docker, rcli, REST, documentation" |
| 17 | 17 |
|
| 18 | 18 |
[Docker Engine API v1.41](https://docs.docker.com/engine/api/v1.41/) documentation |
| 19 | 19 |
|
| 20 |
+* `GET /events` now returns `prune` events after pruning resources have completed. |
|
| 21 |
+ Prune events are returned for `container`, `network`, `volume`, `image`, and |
|
| 22 |
+ `builder`, and have a `reclaimed` attribute, indicating the amount of space |
|
| 23 |
+ reclaimed (in bytes). |
|
| 20 | 24 |
* `GET /info` now returns a `CgroupVersion` field, containing the cgroup version. |
| 21 | 25 |
* `GET /info` now returns a `DefaultAddressPools` field, containing a list of |
| 22 | 26 |
custom default address pools for local networks, which can be specified in the |
| ... | ... |
@@ -2,6 +2,7 @@ package service // import "github.com/docker/docker/volume/service" |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"context" |
| 5 |
+ "strconv" |
|
| 5 | 6 |
"sync/atomic" |
| 6 | 7 |
|
| 7 | 8 |
"github.com/docker/docker/api/types" |
| ... | ... |
@@ -238,6 +239,9 @@ func (s *VolumesService) Prune(ctx context.Context, filter filters.Args) (*types |
| 238 | 238 |
rep.SpaceReclaimed += uint64(vSize) |
| 239 | 239 |
rep.VolumesDeleted = append(rep.VolumesDeleted, v.Name()) |
| 240 | 240 |
} |
| 241 |
+ s.eventLogger.LogVolumeEvent("", "prune", map[string]string{
|
|
| 242 |
+ "reclaimed": strconv.FormatInt(int64(rep.SpaceReclaimed), 10), |
|
| 243 |
+ }) |
|
| 241 | 244 |
return rep, nil |
| 242 | 245 |
} |
| 243 | 246 |
|