diff --git a/daemon/daemon.go b/daemon/daemon.go index a2849cbfbf..8e3b699a14 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -643,18 +643,25 @@ func (daemon *Daemon) restore(ctx context.Context, cfg *configStore, containers } group.Wait() - for id := range removeContainers { + for id, c := range removeContainers { group.Add(1) - go func(cid string) { + go func(cid string, c *container.Container) { _ = sem.Acquire(context.Background(), 1) + defer group.Done() + defer sem.Release(1) + + if c.State.IsDead() { + if err := daemon.cleanupContainer(c, backend.ContainerRmConfig{ForceRemove: true, RemoveVolume: true}); err != nil { + log.G(ctx).WithField("container", cid).WithError(err).Error("failed to remove dead container") + } + return + } if err := daemon.containerRm(&cfg.Config, cid, &backend.ContainerRmConfig{ForceRemove: true, RemoveVolume: true}); err != nil { log.G(ctx).WithField("container", cid).WithError(err).Error("failed to remove container") } - sem.Release(1) - group.Done() - }(id) + }(id, c) } group.Wait() diff --git a/integration/container/remove_test.go b/integration/container/remove_test.go index d36f728832..6a340b32f1 100644 --- a/integration/container/remove_test.go +++ b/integration/container/remove_test.go @@ -8,6 +8,7 @@ import ( containertypes "github.com/moby/moby/api/types/container" "github.com/moby/moby/client" "github.com/moby/moby/v2/integration/internal/container" + "github.com/moby/moby/v2/internal/testutil/daemon" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" "gotest.tools/v3/fs" @@ -107,3 +108,26 @@ func TestRemoveInvalidContainer(t *testing.T) { assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound)) assert.Check(t, is.ErrorContains(err, "No such container")) } + +func TestRemoveDeadContainersOnDaemonRestart(t *testing.T) { + skip.If(t, testEnv.IsRemoteDaemon) + skip.If(t, testEnv.DaemonInfo.OSType == "windows", "FIXME: Windows CI does not support multiple daemons yet") + + ctx := setupTest(t) + d := daemon.New(t) + d.StartWithBusybox(ctx, t) + defer d.Stop(t) + + apiClient := d.NewClientT(t) + container.Run(ctx, t, apiClient, container.WithCmd("top"), container.WithAutoRemove) + + list, err := apiClient.ContainerList(ctx, client.ContainerListOptions{All: true}) + assert.NilError(t, err) + assert.Check(t, is.Len(list.Items, 1)) + + d.Restart(t) + + list, err = apiClient.ContainerList(ctx, client.ContainerListOptions{All: true}) + assert.NilError(t, err) + assert.Check(t, is.Len(list.Items, 0)) +}