Skip to content

Commit 4cb480d

Browse files
authored
Merge pull request #4546 from kolyshkin/criu-opt
Add `runc_nocriu` build tag to opt out of c/r
2 parents e075206 + 47dc185 commit 4cb480d

File tree

6 files changed

+100
-63
lines changed

6 files changed

+100
-63
lines changed

.github/workflows/validate.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,14 @@ jobs:
7676
uses: actions/setup-go@v5
7777
with:
7878
go-version: "${{ env.GO_VERSION }}"
79+
- name: install deps
80+
run: |
81+
sudo apt update
82+
sudo apt -y install libseccomp-dev
7983
- name: compile with no build tags
8084
run: make BUILDTAGS=""
85+
- name: compile with runc_nocriu build tag
86+
run: make EXTRA_BUILDTAGS="runc_nocriu"
8187

8288
codespell:
8389
runs-on: ubuntu-24.04

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,17 @@ e.g. to disable seccomp:
103103
make BUILDTAGS=""
104104
```
105105

106+
To add some more build tags to the default set, use the `EXTRA_BUILDTAGS`
107+
make variable, e.g. to disable checkpoint/restore:
108+
109+
```bash
110+
make EXTRA_BUILDTAGS="runc_nocriu"
111+
```
112+
106113
| Build Tag | Feature | Enabled by Default | Dependencies |
107114
|---------------|---------------------------------------|--------------------|---------------------|
108115
| `seccomp` | Syscall filtering using `libseccomp`. | yes | `libseccomp` |
116+
| `runc_nocriu` | **Disables** runc checkpoint/restore. | no | `criu` |
109117

110118
The following build tags were used earlier, but are now obsoleted:
111119
- **runc_nodmz** (since runc v1.2.1 runc dmz binary is dropped)

checkpoint.go

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"path/filepath"
99
"strconv"
1010

11-
criu "github.com/checkpoint-restore/go-criu/v6/rpc"
1211
"github.com/moby/sys/userns"
1312
"github.com/opencontainers/runtime-spec/specs-go"
1413
"github.com/sirupsen/logrus"
@@ -132,6 +131,7 @@ func criuOptions(context *cli.Context) (*libcontainer.CriuOpts, error) {
132131
StatusFd: context.Int("status-fd"),
133132
LsmProfile: context.String("lsm-profile"),
134133
LsmMountContext: context.String("lsm-mount-context"),
134+
ManageCgroupsMode: context.String("manage-cgroups-mode"),
135135
}
136136

137137
// CRIU options below may or may not be set.
@@ -152,21 +152,6 @@ func criuOptions(context *cli.Context) (*libcontainer.CriuOpts, error) {
152152
}
153153
}
154154

155-
switch context.String("manage-cgroups-mode") {
156-
case "":
157-
// do nothing
158-
case "soft":
159-
opts.ManageCgroupsMode = criu.CriuCgMode_SOFT
160-
case "full":
161-
opts.ManageCgroupsMode = criu.CriuCgMode_FULL
162-
case "strict":
163-
opts.ManageCgroupsMode = criu.CriuCgMode_STRICT
164-
case "ignore":
165-
opts.ManageCgroupsMode = criu.CriuCgMode_IGNORE
166-
default:
167-
return nil, errors.New("Invalid manage-cgroups-mode value")
168-
}
169-
170155
// runc doesn't manage network devices and their configuration.
171156
nsmask := unix.CLONE_NEWNET
172157

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//go:build runc_nocriu
2+
3+
package libcontainer
4+
5+
import "errors"
6+
7+
var ErrNoCR = errors.New("this runc binary has not been compiled with checkpoint/restore support enabled (runc_nocriu)")
8+
9+
func (c *Container) Restore(process *Process, criuOpts *CriuOpts) error {
10+
return ErrNoCR
11+
}
12+
13+
func (c *Container) Checkpoint(criuOpts *CriuOpts) error {
14+
return ErrNoCR
15+
}

libcontainer/criu_linux.go

Lines changed: 64 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//go:build !runc_nocriu
2+
13
package libcontainer
24

35
import (
@@ -295,6 +297,11 @@ func (c *Container) Checkpoint(criuOpts *CriuOpts) error {
295297
return errors.New("invalid directory to save checkpoint")
296298
}
297299

300+
cgMode, err := criuCgMode(criuOpts.ManageCgroupsMode)
301+
if err != nil {
302+
return err
303+
}
304+
298305
// Since a container can be C/R'ed multiple times,
299306
// the checkpoint directory may already exist.
300307
if err := os.Mkdir(criuOpts.ImagesDirectory, 0o700); err != nil && !os.IsExist(err) {
@@ -309,22 +316,23 @@ func (c *Container) Checkpoint(criuOpts *CriuOpts) error {
309316
defer imageDir.Close()
310317

311318
rpcOpts := criurpc.CriuOpts{
312-
ImagesDirFd: proto.Int32(int32(imageDir.Fd())),
313-
LogLevel: proto.Int32(4),
314-
LogFile: proto.String(logFile),
315-
Root: proto.String(c.config.Rootfs),
316-
ManageCgroups: proto.Bool(true),
317-
NotifyScripts: proto.Bool(true),
318-
Pid: proto.Int32(int32(c.initProcess.pid())),
319-
ShellJob: proto.Bool(criuOpts.ShellJob),
320-
LeaveRunning: proto.Bool(criuOpts.LeaveRunning),
321-
TcpEstablished: proto.Bool(criuOpts.TcpEstablished),
322-
ExtUnixSk: proto.Bool(criuOpts.ExternalUnixConnections),
323-
FileLocks: proto.Bool(criuOpts.FileLocks),
324-
EmptyNs: proto.Uint32(criuOpts.EmptyNs),
325-
OrphanPtsMaster: proto.Bool(true),
326-
AutoDedup: proto.Bool(criuOpts.AutoDedup),
327-
LazyPages: proto.Bool(criuOpts.LazyPages),
319+
ImagesDirFd: proto.Int32(int32(imageDir.Fd())),
320+
LogLevel: proto.Int32(4),
321+
LogFile: proto.String(logFile),
322+
Root: proto.String(c.config.Rootfs),
323+
ManageCgroups: proto.Bool(true), // Obsoleted by ManageCgroupsMode.
324+
ManageCgroupsMode: &cgMode,
325+
NotifyScripts: proto.Bool(true),
326+
Pid: proto.Int32(int32(c.initProcess.pid())),
327+
ShellJob: proto.Bool(criuOpts.ShellJob),
328+
LeaveRunning: proto.Bool(criuOpts.LeaveRunning),
329+
TcpEstablished: proto.Bool(criuOpts.TcpEstablished),
330+
ExtUnixSk: proto.Bool(criuOpts.ExternalUnixConnections),
331+
FileLocks: proto.Bool(criuOpts.FileLocks),
332+
EmptyNs: proto.Uint32(criuOpts.EmptyNs),
333+
OrphanPtsMaster: proto.Bool(true),
334+
AutoDedup: proto.Bool(criuOpts.AutoDedup),
335+
LazyPages: proto.Bool(criuOpts.LazyPages),
328336
}
329337

330338
// if criuOpts.WorkDirectory is not set, criu default is used.
@@ -381,12 +389,6 @@ func (c *Container) Checkpoint(criuOpts *CriuOpts) error {
381389
rpcOpts.TrackMem = proto.Bool(true)
382390
}
383391

384-
// append optional manage cgroups mode
385-
if criuOpts.ManageCgroupsMode != 0 {
386-
mode := criuOpts.ManageCgroupsMode
387-
rpcOpts.ManageCgroupsMode = &mode
388-
}
389-
390392
var t criurpc.CriuReqType
391393
if criuOpts.PreDump {
392394
feat := criurpc.CriuFeatures{
@@ -634,6 +636,12 @@ func (c *Container) Restore(process *Process, criuOpts *CriuOpts) error {
634636
if criuOpts.ImagesDirectory == "" {
635637
return errors.New("invalid directory to restore checkpoint")
636638
}
639+
640+
cgMode, err := criuCgMode(criuOpts.ManageCgroupsMode)
641+
if err != nil {
642+
return err
643+
}
644+
637645
logDir := criuOpts.ImagesDirectory
638646
imageDir, err := os.Open(criuOpts.ImagesDirectory)
639647
if err != nil {
@@ -663,22 +671,23 @@ func (c *Container) Restore(process *Process, criuOpts *CriuOpts) error {
663671
req := &criurpc.CriuReq{
664672
Type: &t,
665673
Opts: &criurpc.CriuOpts{
666-
ImagesDirFd: proto.Int32(int32(imageDir.Fd())),
667-
EvasiveDevices: proto.Bool(true),
668-
LogLevel: proto.Int32(4),
669-
LogFile: proto.String(logFile),
670-
RstSibling: proto.Bool(true),
671-
Root: proto.String(root),
672-
ManageCgroups: proto.Bool(true),
673-
NotifyScripts: proto.Bool(true),
674-
ShellJob: proto.Bool(criuOpts.ShellJob),
675-
ExtUnixSk: proto.Bool(criuOpts.ExternalUnixConnections),
676-
TcpEstablished: proto.Bool(criuOpts.TcpEstablished),
677-
FileLocks: proto.Bool(criuOpts.FileLocks),
678-
EmptyNs: proto.Uint32(criuOpts.EmptyNs),
679-
OrphanPtsMaster: proto.Bool(true),
680-
AutoDedup: proto.Bool(criuOpts.AutoDedup),
681-
LazyPages: proto.Bool(criuOpts.LazyPages),
674+
ImagesDirFd: proto.Int32(int32(imageDir.Fd())),
675+
EvasiveDevices: proto.Bool(true),
676+
LogLevel: proto.Int32(4),
677+
LogFile: proto.String(logFile),
678+
RstSibling: proto.Bool(true),
679+
Root: proto.String(root),
680+
ManageCgroups: proto.Bool(true), // Obsoleted by ManageCgroupsMode.
681+
ManageCgroupsMode: &cgMode,
682+
NotifyScripts: proto.Bool(true),
683+
ShellJob: proto.Bool(criuOpts.ShellJob),
684+
ExtUnixSk: proto.Bool(criuOpts.ExternalUnixConnections),
685+
TcpEstablished: proto.Bool(criuOpts.TcpEstablished),
686+
FileLocks: proto.Bool(criuOpts.FileLocks),
687+
EmptyNs: proto.Uint32(criuOpts.EmptyNs),
688+
OrphanPtsMaster: proto.Bool(true),
689+
AutoDedup: proto.Bool(criuOpts.AutoDedup),
690+
LazyPages: proto.Bool(criuOpts.LazyPages),
682691
},
683692
}
684693

@@ -757,12 +766,6 @@ func (c *Container) Restore(process *Process, criuOpts *CriuOpts) error {
757766
c.restoreNetwork(req, criuOpts)
758767
}
759768

760-
// append optional manage cgroups mode
761-
if criuOpts.ManageCgroupsMode != 0 {
762-
mode := criuOpts.ManageCgroupsMode
763-
req.Opts.ManageCgroupsMode = &mode
764-
}
765-
766769
var (
767770
fds []string
768771
fdJSON []byte
@@ -1184,3 +1187,20 @@ func (c *Container) criuNotifications(resp *criurpc.CriuResp, process *Process,
11841187
}
11851188
return nil
11861189
}
1190+
1191+
func criuCgMode(mode string) (criurpc.CriuCgMode, error) {
1192+
switch mode {
1193+
case "":
1194+
return criurpc.CriuCgMode_DEFAULT, nil
1195+
case "soft":
1196+
return criurpc.CriuCgMode_SOFT, nil
1197+
case "full":
1198+
return criurpc.CriuCgMode_FULL, nil
1199+
case "strict":
1200+
return criurpc.CriuCgMode_STRICT, nil
1201+
case "ignore":
1202+
return criurpc.CriuCgMode_IGNORE, nil
1203+
default:
1204+
return 0, errors.New("invalid manage-cgroups-mode value")
1205+
}
1206+
}

libcontainer/criu_opts_linux.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package libcontainer
22

3-
import criu "github.com/checkpoint-restore/go-criu/v6/rpc"
4-
53
type CriuPageServerInfo struct {
64
Address string // IP address of CRIU page server
75
Port int32 // port number of CRIU page server
@@ -24,11 +22,16 @@ type CriuOpts struct {
2422
PreDump bool // call criu predump to perform iterative checkpoint
2523
PageServer CriuPageServerInfo // allow to dump to criu page server
2624
VethPairs []VethPairName // pass the veth to criu when restore
27-
ManageCgroupsMode criu.CriuCgMode // dump or restore cgroup mode
2825
EmptyNs uint32 // don't c/r properties for namespace from this mask
2926
AutoDedup bool // auto deduplication for incremental dumps
3027
LazyPages bool // restore memory pages lazily using userfaultfd
3128
StatusFd int // fd for feedback when lazy server is ready
3229
LsmProfile string // LSM profile used to restore the container
3330
LsmMountContext string // LSM mount context value to use during restore
31+
32+
// ManageCgroupsMode tells how criu should manage cgroups during
33+
// checkpoint or restore. Possible values are: "soft", "full",
34+
// "strict", "ignore", or "" (empty string) for criu default.
35+
// See https://criu.org/CGroups for more details.
36+
ManageCgroupsMode string
3437
}

0 commit comments

Comments
 (0)