From 30006b470ab381e9261e463e4c39ea680b9fe0fd Mon Sep 17 00:00:00 2001 From: ningmingxiao Date: Tue, 19 Aug 2025 20:34:35 +0800 Subject: [PATCH] feature:support live-restore Signed-off-by: ningmingxiao --- .../container_run_restart_linux_test.go | 6 +- go.mod | 9 ++- go.sum | 12 +++ pkg/logging/container_wait_linux.go | 74 +++++++++++++++++++ pkg/logging/container_wait_other.go | 30 ++++++++ pkg/logging/logging.go | 6 +- 6 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 pkg/logging/container_wait_linux.go create mode 100644 pkg/logging/container_wait_other.go diff --git a/cmd/nerdctl/container/container_run_restart_linux_test.go b/cmd/nerdctl/container/container_run_restart_linux_test.go index 795550696f6..04e2721a41f 100644 --- a/cmd/nerdctl/container/container_run_restart_linux_test.go +++ b/cmd/nerdctl/container/container_run_restart_linux_test.go @@ -53,7 +53,8 @@ func TestRunRestart(t *testing.T) { "--name", testContainerName, "-p", fmt.Sprintf("127.0.0.1:%d:80", hostPort), testutil.NginxAlpineImage).AssertOK() - + inspectedContainer := base.InspectContainer(testContainerName) + pid := inspectedContainer.State.Pid check := func(httpGetRetry int) error { resp, err := nettestutil.HTTPGet(fmt.Sprintf("http://127.0.0.1:%d", hostPort), httpGetRetry, false) if err != nil { @@ -87,6 +88,9 @@ func TestRunRestart(t *testing.T) { } time.Sleep(sleep) } + inspectedContainer = base.InspectContainer(testContainerName) + assert.Equal(t, inspectedContainer.State.Status, "running") + assert.Equal(t, inspectedContainer.State.Pid, pid) base.DumpDaemonLogs(10) t.Fatalf("the container does not seem to be restarted") } diff --git a/go.mod b/go.mod index daf8cde5431..87b4a0b8dc7 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,7 @@ require ( github.com/containerd/stargz-snapshotter v0.16.3 //gomodjail:unconfined github.com/containerd/stargz-snapshotter/estargz v0.16.3 //gomodjail:unconfined github.com/containerd/stargz-snapshotter/ipfs v0.16.3 //gomodjail:unconfined + github.com/containerd/ttrpc v1.2.7 github.com/containerd/typeurl/v2 v2.2.3 github.com/containernetworking/cni v1.3.0 //gomodjail:unconfined github.com/containernetworking/plugins v1.7.1 //gomodjail:unconfined @@ -75,15 +76,17 @@ require ( require ( github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect + github.com/checkpoint-restore/checkpointctl v1.3.0 // indirect github.com/cilium/ebpf v0.16.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/go-runc v1.1.0 // indirect + github.com/containerd/otelttrpc v0.1.0 // indirect github.com/containerd/plugin v1.0.0 // indirect - github.com/containerd/ttrpc v1.2.7 // indirect github.com/containers/ocicrypt v1.2.1 // indirect github.com/creack/pty v1.1.24 // indirect github.com/djherbis/times v1.6.0 // indirect github.com/docker/docker-credential-helpers v0.8.2 // indirect + github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-jose/go-jose/v4 v4.0.5 // indirect github.com/go-logr/logr v1.4.2 // indirect @@ -97,6 +100,8 @@ require ( github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-shellwords v1.0.12 // indirect + github.com/mdlayher/socket v0.5.1 // indirect + github.com/mdlayher/vsock v1.2.1 // indirect github.com/miekg/pkcs11 v1.1.1 // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect @@ -129,8 +134,10 @@ require ( github.com/tinylib/msgp v1.3.0 // indirect github.com/vbatts/tar-split v0.11.6 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect + go.etcd.io/bbolt v1.4.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect go.opentelemetry.io/otel v1.35.0 // indirect go.opentelemetry.io/otel/metric v1.35.0 // indirect diff --git a/go.sum b/go.sum index 7c02c493c34..526eb6034d5 100644 --- a/go.sum +++ b/go.sum @@ -15,6 +15,8 @@ github.com/Microsoft/hcsshim v0.13.0/go.mod h1:9KWJ/8DgU+QzYGupX4tzMhRQE8h6w90lH github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/checkpoint-restore/checkpointctl v1.3.0 h1:bNz5b6s+lxFdG5ZGDba3qSkBtXDDTCG2494dfAbQJ4E= +github.com/checkpoint-restore/checkpointctl v1.3.0/go.mod h1:dqZH4wDvbjnsqFGK2LdUDk21yFQ1dCAtzgRMlG44KDM= github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok= github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -49,6 +51,8 @@ github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/nydus-snapshotter v0.15.2 h1:qsHI4M+Wwrf6Jr4eBqhNx8qh+YU0dSiJ+WPmcLFWNcg= github.com/containerd/nydus-snapshotter v0.15.2/go.mod h1:FfwH2KBkNYoisK/e+KsmNr7xTU53DmnavQHMFOcXwfM= +github.com/containerd/otelttrpc v0.1.0 h1:UOX68eVTE8H/T45JveIg+I22Ev2aFj4qPITCmXsskjw= +github.com/containerd/otelttrpc v0.1.0/go.mod h1:XhoA2VvaGPW1clB2ULwrBZfXVuEWuyOd2NUD1IM0yTg= github.com/containerd/platforms v1.0.0-rc.1 h1:83KIq4yy1erSRgOVHNk1HYdPvzdJ5CnsWaRoJX4C41E= github.com/containerd/platforms v1.0.0-rc.1/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4= github.com/containerd/plugin v1.0.0 h1:c8Kf1TNl6+e2TtMHZt+39yAPDbouRH9WAToRjex483Y= @@ -96,6 +100,8 @@ github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZ github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -196,6 +202,8 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/ github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= +github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ= +github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE= github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= @@ -332,10 +340,14 @@ github.com/yuchanns/srslog v1.1.0/go.mod h1:HsLjdv3XV02C3kgBW2bTyW6i88OQE+VYJZIx github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk= +go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= diff --git a/pkg/logging/container_wait_linux.go b/pkg/logging/container_wait_linux.go new file mode 100644 index 00000000000..f27c199d46b --- /dev/null +++ b/pkg/logging/container_wait_linux.go @@ -0,0 +1,74 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package logging + +import ( + "context" + "net" + "strings" + "time" + + task "github.com/containerd/containerd/api/runtime/task/v3" + containerd "github.com/containerd/containerd/v2/client" + "github.com/containerd/containerd/v2/core/runtime/v2" + "github.com/containerd/containerd/v2/core/runtime/v2/logging" + "github.com/containerd/containerd/v2/pkg/namespaces" + "github.com/containerd/containerd/v2/pkg/shim" + "github.com/containerd/ttrpc" +) + +// Connect shim directly to avoid to connect containerd. +func waitContainerExited(ctx context.Context, address string, config *logging.Config, _ containerd.Task) (<-chan containerd.ExitStatus, error) { + ctx = namespaces.WithNamespace(ctx, config.Namespace) + shimCli, err := connectToShim(ctx, strings.TrimPrefix(address, "unix://"), 3, config.ID) + if err != nil { + return nil, err + } + c := make(chan containerd.ExitStatus, 1) + go func() { + defer close(c) + response, err := shimCli.Wait(ctx, &task.WaitRequest{ + ID: config.ID, + }) + + if err != nil { + c <- *containerd.NewExitStatus(containerd.UnknownExitStatus, time.Time{}, err) + return + } + c <- *containerd.NewExitStatus(response.ExitStatus, response.ExitedAt.AsTime(), nil) + }() + return c, nil +} + +func connectToShim(ctx context.Context, ctrdEndpoint string, version int, id string) (v2.TaskServiceClient, error) { + addr, err := shim.SocketAddress(ctx, ctrdEndpoint, id, false) + if err != nil { + return nil, err + } + addr = strings.TrimPrefix(addr, "unix://") + conn, err := net.Dial("unix", addr) + if err != nil { + return nil, err + } + + client := ttrpc.NewClient(conn) + cli, err := v2.NewTaskClient(client, version) + if err != nil { + return nil, err + } + return cli, nil +} diff --git a/pkg/logging/container_wait_other.go b/pkg/logging/container_wait_other.go new file mode 100644 index 00000000000..1f58be73383 --- /dev/null +++ b/pkg/logging/container_wait_other.go @@ -0,0 +1,30 @@ +//go:build !linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package logging + +import ( + "context" + + containerd "github.com/containerd/containerd/v2/client" + "github.com/containerd/containerd/v2/core/runtime/v2/logging" +) + +func waitContainerExited(ctx context.Context, address string, config *logging.Config, task containerd.Task) (<-chan containerd.ExitStatus, error) { + return task.Wait(ctx) +} diff --git a/pkg/logging/logging.go b/pkg/logging/logging.go index 91a3231ee3a..93b0e2ad075 100644 --- a/pkg/logging/logging.go +++ b/pkg/logging/logging.go @@ -177,7 +177,7 @@ func getContainerWait(ctx context.Context, address string, config *logging.Confi task, err := con.Task(ctx, nil) if err == nil { - return task.Wait(ctx) + return waitContainerExited(ctx, strings.TrimPrefix(address, "unix://"), config, task) } if !errdefs.IsNotFound(err) { return nil, err @@ -193,14 +193,14 @@ func getContainerWait(ctx context.Context, address string, config *logging.Confi case <-ctx.Done(): return nil, errors.New("timed out waiting for container task to start") case <-ticker.C: - task, err = con.Task(ctx, nil) + task, err := con.Task(ctx, nil) if err != nil { if errdefs.IsNotFound(err) { continue } return nil, err } - return task.Wait(ctx) + return waitContainerExited(ctx, strings.TrimPrefix(address, "unix://"), config, task) } } }