liverestore: Don't remove --rm containers on restart

When live-restore is enabled, containers with autoremove enabled
shouldn't be forcibly killed when engine restarts.
They still should be removed if they exited while the engine was down
though.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit c5ea3d595c)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
This commit is contained in:
Paweł Gronowski 2023-11-28 10:21:25 +01:00
parent 7cbc844564
commit f0b5ca47fb
No known key found for this signature in database
GPG key ID: B85EFCFE26DEF92A
2 changed files with 67 additions and 3 deletions

View file

@ -472,9 +472,12 @@ func (daemon *Daemon) restore() error {
restartContainers[c] = make(chan struct{})
mapLock.Unlock()
} else if c.HostConfig != nil && c.HostConfig.AutoRemove {
mapLock.Lock()
removeContainers[c.ID] = c
mapLock.Unlock()
// Remove the container if live-restore is disabled or if the container has already exited.
if !daemon.configStore.LiveRestoreEnabled || !alive {
mapLock.Lock()
removeContainers[c.ID] = c
mapLock.Unlock()
}
}
c.Lock()

View file

@ -14,6 +14,7 @@ import (
"strings"
"syscall"
"testing"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/mount"
@ -370,6 +371,66 @@ func TestLiveRestore(t *testing.T) {
skip.If(t, runtime.GOOS == "windows", "cannot start multiple daemons on windows")
t.Run("volume references", testLiveRestoreVolumeReferences)
t.Run("autoremove", testLiveRestoreAutoRemove)
}
func testLiveRestoreAutoRemove(t *testing.T) {
skip.If(t, testEnv.IsRootless(), "restarted rootless daemon will have a new process namespace")
t.Parallel()
ctx := context.Background()
run := func(t *testing.T) (*daemon.Daemon, func(), string) {
d := daemon.New(t)
d.StartWithBusybox(t, "--live-restore", "--iptables=false")
t.Cleanup(func() {
d.Stop(t)
d.Cleanup(t)
})
tmpDir := t.TempDir()
apiClient := d.NewClientT(t)
cID := container.Run(ctx, t, apiClient,
container.WithBind(tmpDir, "/v"),
// Run until a 'stop' file is created.
container.WithCmd("sh", "-c", "while [ ! -f /v/stop ]; do sleep 0.1; done"),
container.WithAutoRemove)
t.Cleanup(func() { apiClient.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{Force: true}) })
finishContainer := func() {
file, err := os.Create(filepath.Join(tmpDir, "stop"))
assert.NilError(t, err, "Failed to create 'stop' file")
file.Close()
}
return d, finishContainer, cID
}
t.Run("engine restart shouldnt kill alive containers", func(t *testing.T) {
d, finishContainer, cID := run(t)
d.Restart(t, "--live-restore", "--iptables=false")
apiClient := d.NewClientT(t)
_, err := apiClient.ContainerInspect(ctx, cID)
assert.NilError(t, err, "Container shouldn't be removed after engine restart")
finishContainer()
poll.WaitOn(t, container.IsRemoved(ctx, apiClient, cID))
})
t.Run("engine restart should remove containers that exited", func(t *testing.T) {
d, finishContainer, cID := run(t)
d.Stop(t)
finishContainer()
time.Sleep(time.Millisecond * 200)
d.Start(t, "--live-restore", "--iptables=false")
poll.WaitOn(t, container.IsRemoved(ctx, d.NewClientT(t), cID))
})
}
func testLiveRestoreVolumeReferences(t *testing.T) {