Преглед на файлове

Merge pull request #46857 from vvoland/liverestore-fix-46308

liverestore: Don't remove `--rm` containers on restart
Paweł Gronowski преди 1 година
родител
ревизия
ae6960cf91
променени са 3 файла, в които са добавени 91 реда и са изтрити 3 реда
  1. 6 3
      daemon/daemon.go
  2. 68 0
      integration/daemon/daemon_test.go
  3. 17 0
      integration/internal/process/wait.go

+ 6 - 3
daemon/daemon.go

@@ -495,9 +495,12 @@ func (daemon *Daemon) restore(cfg *configStore) error {
 				restartContainers[c] = make(chan struct{})
 				restartContainers[c] = make(chan struct{})
 				mapLock.Unlock()
 				mapLock.Unlock()
 			} else if c.HostConfig != nil && c.HostConfig.AutoRemove {
 			} 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 !cfg.LiveRestoreEnabled || !alive {
+					mapLock.Lock()
+					removeContainers[c.ID] = c
+					mapLock.Unlock()
+				}
 			}
 			}
 
 
 			c.Lock()
 			c.Lock()

+ 68 - 0
integration/daemon/daemon_test.go

@@ -21,6 +21,7 @@ import (
 	"github.com/docker/docker/daemon/config"
 	"github.com/docker/docker/daemon/config"
 	"github.com/docker/docker/errdefs"
 	"github.com/docker/docker/errdefs"
 	"github.com/docker/docker/integration/internal/container"
 	"github.com/docker/docker/integration/internal/container"
+	"github.com/docker/docker/integration/internal/process"
 	"github.com/docker/docker/pkg/stdcopy"
 	"github.com/docker/docker/pkg/stdcopy"
 	"github.com/docker/docker/testutil"
 	"github.com/docker/docker/testutil"
 	"github.com/docker/docker/testutil/daemon"
 	"github.com/docker/docker/testutil/daemon"
@@ -381,6 +382,73 @@ func TestLiveRestore(t *testing.T) {
 	_ = testutil.StartSpan(baseContext, t)
 	_ = testutil.StartSpan(baseContext, t)
 
 
 	t.Run("volume references", testLiveRestoreVolumeReferences)
 	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 := testutil.StartSpan(baseContext, t)
+
+	run := func(t *testing.T) (*daemon.Daemon, func(), string) {
+		d := daemon.New(t)
+		d.StartWithBusybox(ctx, 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, containertypes.RemoveOptions{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)
+
+		apiClient := d.NewClientT(t)
+
+		// Get PID of the container process.
+		inspect, err := apiClient.ContainerInspect(ctx, cID)
+		assert.NilError(t, err)
+		pid := inspect.State.Pid
+
+		d.Stop(t)
+
+		finishContainer()
+		poll.WaitOn(t, process.NotAlive(pid))
+
+		d.Start(t, "--live-restore", "--iptables=false")
+
+		poll.WaitOn(t, container.IsRemoved(ctx, apiClient, cID))
+	})
 }
 }
 
 
 func testLiveRestoreVolumeReferences(t *testing.T) {
 func testLiveRestoreVolumeReferences(t *testing.T) {

+ 17 - 0
integration/internal/process/wait.go

@@ -0,0 +1,17 @@
+package process
+
+import (
+	procpkg "github.com/docker/docker/pkg/process"
+	"gotest.tools/v3/poll"
+)
+
+// NotAlive verifies the process doesn't exist (finished or never started).
+func NotAlive(pid int) func(log poll.LogT) poll.Result {
+	return func(log poll.LogT) poll.Result {
+		if !procpkg.Alive(pid) {
+			return poll.Success()
+		}
+
+		return poll.Continue("waiting for process to finish")
+	}
+}