Skip to content

Commit 8b9cb17

Browse files
committed
feature:support live-restore
Signed-off-by: ningmingxiao <[email protected]>
1 parent e8dc913 commit 8b9cb17

File tree

6 files changed

+172
-4
lines changed

6 files changed

+172
-4
lines changed

cmd/nerdctl/container/container_run_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,3 +1103,31 @@ func TestCleanupFIFOs(t *testing.T) {
11031103
}
11041104
testCase.Run(t)
11051105
}
1106+
1107+
func TestContainerLiveRestore(t *testing.T) {
1108+
if runtime.GOOS != "linux" {
1109+
t.Skip("test only support on linux")
1110+
}
1111+
if rootlessutil.IsRootless() {
1112+
t.Skip("containerd restart failed when rootless")
1113+
}
1114+
base := testutil.NewBase(t)
1115+
containerName := testutil.Identifier(t)
1116+
teardown := func() {
1117+
base.Cmd("rm", "-f", containerName).Run()
1118+
}
1119+
defer teardown()
1120+
teardown()
1121+
base.Cmd("run", "-d", "--name", containerName, testutil.CommonImage, "top").AssertOK()
1122+
1123+
inspectedContainer := base.InspectContainer(containerName)
1124+
pid := inspectedContainer.State.Pid
1125+
1126+
restartCmd := exec.Command("service", "containerd", "restart")
1127+
if out, err := restartCmd.CombinedOutput(); err != nil {
1128+
t.Fatalf("cannot restart containerd %q: %v", string(out), err)
1129+
}
1130+
inspectedContainer = base.InspectContainer(containerName)
1131+
assert.Equal(t, inspectedContainer.State.Status, "running")
1132+
assert.Equal(t, inspectedContainer.State.Pid, pid)
1133+
}

go.mod

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ require (
7979
github.com/containerd/errdefs/pkg v0.3.0 // indirect
8080
github.com/containerd/go-runc v1.1.0 // indirect
8181
github.com/containerd/plugin v1.0.0 // indirect
82-
github.com/containerd/ttrpc v1.2.7 // indirect
82+
github.com/containerd/ttrpc v1.2.7
8383
github.com/containers/ocicrypt v1.2.1 // indirect
8484
github.com/creack/pty v1.1.24 // indirect
8585
github.com/djherbis/times v1.6.0 // indirect
@@ -148,4 +148,22 @@ require (
148148
tags.cncf.io/container-device-interface/specs-go v1.0.0 // indirect
149149
)
150150

151+
require (
152+
github.com/checkpoint-restore/checkpointctl v1.3.0 // indirect
153+
github.com/containerd/containerd v1.7.28
154+
github.com/containerd/otelttrpc v0.1.0 // indirect
155+
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
156+
github.com/mdlayher/socket v0.5.1 // indirect
157+
github.com/mdlayher/vsock v1.2.1 // indirect
158+
go.etcd.io/bbolt v1.4.0 // indirect
159+
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect
160+
)
161+
162+
require (
163+
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 // indirect
164+
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20231105174938-2b5cbb29f3e2 // indirect
165+
github.com/google/uuid v1.6.0 // indirect
166+
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
167+
)
168+
151169
replace github.com/containerd/nerdctl/mod/tigron v0.0.0 => ./mod/tigron

go.sum

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
22
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
33
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
4+
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20231105174938-2b5cbb29f3e2 h1:dIScnXFlF784X79oi7MzVT6GWqr/W1uUt0pB5CsDs9M=
5+
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20231105174938-2b5cbb29f3e2/go.mod h1:gCLVsLfv1egrcZu+GoJATN5ts75F2s62ih/457eWzOw=
46
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
57
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
68
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -15,6 +17,8 @@ github.com/Microsoft/hcsshim v0.13.0/go.mod h1:9KWJ/8DgU+QzYGupX4tzMhRQE8h6w90lH
1517
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
1618
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
1719
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
20+
github.com/checkpoint-restore/checkpointctl v1.3.0 h1:bNz5b6s+lxFdG5ZGDba3qSkBtXDDTCG2494dfAbQJ4E=
21+
github.com/checkpoint-restore/checkpointctl v1.3.0/go.mod h1:dqZH4wDvbjnsqFGK2LdUDk21yFQ1dCAtzgRMlG44KDM=
1822
github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok=
1923
github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE=
2024
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
@@ -27,6 +31,8 @@ github.com/containerd/cgroups/v3 v3.0.5 h1:44na7Ud+VwyE7LIoJ8JTNQOa549a8543BmzaJ
2731
github.com/containerd/cgroups/v3 v3.0.5/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins=
2832
github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/qqsc=
2933
github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
34+
github.com/containerd/containerd v1.7.28 h1:Nsgm1AtcmEh4AHAJ4gGlNSaKgXiNccU270Dnf81FQ3c=
35+
github.com/containerd/containerd v1.7.28/go.mod h1:azUkWcOvHrWvaiUjSQH0fjzuHIwSPg1WL5PshGP4Szs=
3036
github.com/containerd/containerd/api v1.9.0 h1:HZ/licowTRazus+wt9fM6r/9BQO7S0vD5lMcWspGIg0=
3137
github.com/containerd/containerd/api v1.9.0/go.mod h1:GhghKFmTR3hNtyznBoQ0EMWr9ju5AqHjcZPsSpTKutI=
3238
github.com/containerd/containerd/v2 v2.1.4 h1:/hXWjiSFd6ftrBOBGfAZ6T30LJcx1dBjdKEeI8xucKQ=
@@ -49,6 +55,8 @@ github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
4955
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
5056
github.com/containerd/nydus-snapshotter v0.15.2 h1:qsHI4M+Wwrf6Jr4eBqhNx8qh+YU0dSiJ+WPmcLFWNcg=
5157
github.com/containerd/nydus-snapshotter v0.15.2/go.mod h1:FfwH2KBkNYoisK/e+KsmNr7xTU53DmnavQHMFOcXwfM=
58+
github.com/containerd/otelttrpc v0.1.0 h1:UOX68eVTE8H/T45JveIg+I22Ev2aFj4qPITCmXsskjw=
59+
github.com/containerd/otelttrpc v0.1.0/go.mod h1:XhoA2VvaGPW1clB2ULwrBZfXVuEWuyOd2NUD1IM0yTg=
5260
github.com/containerd/platforms v1.0.0-rc.1 h1:83KIq4yy1erSRgOVHNk1HYdPvzdJ5CnsWaRoJX4C41E=
5361
github.com/containerd/platforms v1.0.0-rc.1/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4=
5462
github.com/containerd/plugin v1.0.0 h1:c8Kf1TNl6+e2TtMHZt+39yAPDbouRH9WAToRjex483Y=
@@ -96,6 +104,8 @@ github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZ
96104
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
97105
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
98106
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
107+
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
108+
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
99109
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
100110
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
101111
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -196,6 +206,8 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/
196206
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
197207
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
198208
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
209+
github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ=
210+
github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE=
199211
github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
200212
github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
201213
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
@@ -332,10 +344,14 @@ github.com/yuchanns/srslog v1.1.0/go.mod h1:HsLjdv3XV02C3kgBW2bTyW6i88OQE+VYJZIx
332344
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
333345
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
334346
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
347+
go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
348+
go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
335349
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
336350
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
337351
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
338352
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
353+
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
354+
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
339355
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
340356
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
341357
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
@@ -484,6 +500,8 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
484500
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
485501
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
486502
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
503+
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
504+
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo=
487505
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
488506
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
489507
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
Copyright The containerd Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package logging
18+
19+
import (
20+
"context"
21+
"net"
22+
"strings"
23+
"time"
24+
25+
task "github.com/containerd/containerd/api/runtime/task/v3"
26+
containerd "github.com/containerd/containerd/v2/client"
27+
"github.com/containerd/containerd/v2/core/runtime/v2"
28+
"github.com/containerd/containerd/v2/core/runtime/v2/logging"
29+
"github.com/containerd/containerd/v2/pkg/namespaces"
30+
"github.com/containerd/containerd/v2/pkg/shim"
31+
"github.com/containerd/ttrpc"
32+
)
33+
34+
// Connect shim directly to avoid to connect containerd.
35+
func waitContainerExited(ctx context.Context, address string, config *logging.Config, _ containerd.Task) (<-chan containerd.ExitStatus, error) {
36+
ctx = namespaces.WithNamespace(ctx, config.Namespace)
37+
shimCli, err := connectToShim(ctx, strings.TrimPrefix(address, "unix://"), 3, config.ID)
38+
if err != nil {
39+
return nil, err
40+
}
41+
c := make(chan containerd.ExitStatus, 1)
42+
go func() {
43+
defer close(c)
44+
response, err := shimCli.Wait(ctx, &task.WaitRequest{
45+
ID: config.ID,
46+
})
47+
48+
if err != nil {
49+
c <- *containerd.NewExitStatus(containerd.UnknownExitStatus, time.Time{}, err)
50+
return
51+
}
52+
c <- *containerd.NewExitStatus(response.ExitStatus, response.ExitedAt.AsTime(), nil)
53+
}()
54+
return c, nil
55+
}
56+
57+
func connectToShim(ctx context.Context, ctrdEndpoint string, version int, id string) (v2.TaskServiceClient, error) {
58+
addr, err := shim.SocketAddress(ctx, ctrdEndpoint, id, false)
59+
if err != nil {
60+
return nil, err
61+
}
62+
addr = strings.TrimPrefix(addr, "unix://")
63+
conn, err := net.Dial("unix", addr)
64+
if err != nil {
65+
return nil, err
66+
}
67+
68+
client := ttrpc.NewClient(conn)
69+
cli, err := v2.NewTaskClient(client, version)
70+
if err != nil {
71+
return nil, err
72+
}
73+
return cli, nil
74+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//go:build !linux
2+
3+
/*
4+
Copyright The containerd Authors.
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
*/
18+
19+
package logging
20+
21+
import (
22+
"context"
23+
24+
containerd "github.com/containerd/containerd/v2/client"
25+
"github.com/containerd/containerd/v2/core/runtime/v2/logging"
26+
)
27+
28+
func waitContainerExited(ctx context.Context, address string, config *logging.Config, task containerd.Task) (<-chan containerd.ExitStatus, error) {
29+
return task.Wait(ctx)
30+
}

pkg/logging/logging.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ func getContainerWait(ctx context.Context, address string, config *logging.Confi
177177

178178
task, err := con.Task(ctx, nil)
179179
if err == nil {
180-
return task.Wait(ctx)
180+
return waitContainerExited(ctx, strings.TrimPrefix(address, "unix://"), config, task)
181181
}
182182
if !errdefs.IsNotFound(err) {
183183
return nil, err
@@ -193,14 +193,14 @@ func getContainerWait(ctx context.Context, address string, config *logging.Confi
193193
case <-ctx.Done():
194194
return nil, errors.New("timed out waiting for container task to start")
195195
case <-ticker.C:
196-
task, err = con.Task(ctx, nil)
196+
task, err := con.Task(ctx, nil)
197197
if err != nil {
198198
if errdefs.IsNotFound(err) {
199199
continue
200200
}
201201
return nil, err
202202
}
203-
return task.Wait(ctx)
203+
return waitContainerExited(ctx, strings.TrimPrefix(address, "unix://"), config, task)
204204
}
205205
}
206206
}

0 commit comments

Comments
 (0)