Skip to content

Commit d743539

Browse files
author
Changwei Ge
committed
execute nydusd by the systemd-run
Signed-off-by: Changwei Ge <[email protected]>
1 parent fc3a48f commit d743539

File tree

4 files changed

+121
-27
lines changed

4 files changed

+121
-27
lines changed

config/config.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,10 @@ type SnapshotterConfig struct {
219219
DaemonMode string `toml:"daemon_mode"`
220220
// Clean up all the resources when snapshotter is closed
221221
CleanupOnClose bool `toml:"cleanup_on_close"`
222+
// Enable nydus-snapshotter to delegate nydusd creation and reaping membership to host.
223+
// This is useful when nydus-snapshotter is running in a container deployed by Kubernetes, nydus-snapshotter must
224+
// run in the host pid namespace and has privilege to enter the host mnt namespace.
225+
DelegateNydusd bool `toml:"delegate_nydusd"`
222226

223227
SystemControllerConfig SystemControllerConfig `toml:"system"`
224228
MetricsConfig MetricsConfig `toml:"metrics"`

pkg/manager/daemon_adaptor.go

Lines changed: 104 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ import (
1010
"fmt"
1111
"os"
1212
"os/exec"
13+
"runtime"
14+
"strconv"
1315
"strings"
1416
"time"
1517

1618
"github.com/containerd/log"
1719
"github.com/pkg/errors"
20+
"golang.org/x/sys/unix"
1821

1922
"github.com/containerd/nydus-snapshotter/config"
2023
"github.com/containerd/nydus-snapshotter/pkg/daemon"
@@ -36,29 +39,79 @@ const endpointGetBackend string = "/api/v1/daemons/%s/backend"
3639
// ensure the daemon has reached specified state.
3740
// - `d` may have not been inserted into daemonStates and store yet.
3841
func (m *Manager) StartDaemon(d *daemon.Daemon) error {
39-
cmd, err := m.BuildDaemonCommand(d, "", false)
40-
if err != nil {
41-
return errors.Wrapf(err, "create command for daemon %s", d.ID())
42-
}
42+
var nydusdPid int
43+
if m.delegateNydusd {
44+
if err := executeInMntNamespace("/proc/1/ns/mnt", func() error {
45+
var err error
46+
cmd, err := m.BuildDaemonCommand(d, "", false)
47+
if err != nil {
48+
return errors.Wrapf(err, "create command for daemon %s", d.ID())
49+
}
4350

44-
if err := cmd.Start(); err != nil {
45-
return err
51+
o, err := cmd.CombinedOutput()
52+
if err != nil {
53+
return errors.Wrapf(err, "start delegatee %s", d.ID())
54+
}
55+
56+
output := strings.TrimSpace(string(o))
57+
serviceUnit := strings.TrimPrefix(output, "Running as unit:")
58+
59+
// systemctl show --property=MainPID run-rc28cf5fdc45c497cbe6736aea1e2701e.service
60+
// MainPID=1037947
61+
cmd = exec.Command("systemctl", "show", "--property=MainPID", strings.TrimSpace(serviceUnit))
62+
o, err = cmd.CombinedOutput()
63+
if err != nil {
64+
return errors.Wrapf(err, "get nydusd MainPID for delegatee %s", d.ID())
65+
}
66+
output = strings.TrimSpace(string(o))
67+
tokens := strings.Split(output, "=")
68+
if len(tokens) != 2 {
69+
return errors.Errorf("unexpected output %q from systemctl show", output)
70+
}
71+
72+
if tokens[0] != "MainPID" {
73+
return errors.Errorf("unexpected property %q from systemctl show", tokens[0])
74+
}
75+
76+
nydusdPid, err = strconv.Atoi(tokens[1])
77+
if err != nil {
78+
return errors.Wrapf(err, "parse nydusd pid %q from systemctl show", tokens[1])
79+
}
80+
81+
log.L.Infof("Delegatee nydusd %s started with pid %d", d.ID(), nydusdPid)
82+
83+
return nil
84+
}); err != nil {
85+
return errors.Wrapf(err, "start daemon %s", d.ID())
86+
}
87+
} else {
88+
var err error
89+
cmd, err := m.BuildDaemonCommand(d, "", false)
90+
if err != nil {
91+
return errors.Wrapf(err, "create command for daemon %s", d.ID())
92+
}
93+
94+
if err := cmd.Start(); err != nil {
95+
return err
96+
}
97+
98+
nydusdPid = cmd.Process.Pid
4699
}
47100

48101
d.Lock()
49102
defer d.Unlock()
50103

51-
d.States.ProcessID = cmd.Process.Pid
104+
d.States.ProcessID = nydusdPid
52105

53106
// Profile nydusd daemon CPU usage during its startup.
54107
if config.GetDaemonProfileCPUDuration() > 0 {
55-
processState, err := metrics.GetProcessStat(cmd.Process.Pid)
108+
processState, err := metrics.GetProcessStat(nydusdPid)
56109
if err == nil {
57110
timer := time.NewTimer(time.Duration(config.GetDaemonProfileCPUDuration()) * time.Second)
58111

59112
go func() {
60113
<-timer.C
61-
currentProcessState, err := metrics.GetProcessStat(cmd.Process.Pid)
114+
currentProcessState, err := metrics.GetProcessStat(nydusdPid)
62115
if err != nil {
63116
log.L.WithError(err).Warnf("Failed to get daemon %s process state.", d.ID())
64117
return
@@ -75,7 +128,7 @@ func (m *Manager) StartDaemon(d *daemon.Daemon) error {
75128
// TODO: Is it right to commit daemon before nydusd successfully started?
76129
// And it brings extra latency of accessing DB. Only write daemon record to
77130
// DB when nydusd is started?
78-
err = m.UpdateDaemon(d)
131+
err := m.UpdateDaemon(d)
79132
if err != nil {
80133
// Nothing we can do, just ignore it for now
81134
log.L.Errorf("Fail to update daemon info (%+v) to DB: %v", d, err)
@@ -212,14 +265,49 @@ func (m *Manager) BuildDaemonCommand(d *daemon.Daemon, bin string, upgrade bool)
212265
nydusdPath = m.NydusdBinaryPath
213266
}
214267

268+
var cmd *exec.Cmd
215269
log.L.Infof("nydusd command: %s %s", nydusdPath, strings.Join(args, " "))
270+
if m.delegateNydusd {
271+
delegateeCmdFlags := []string{"--description", "nydusd"}
272+
args = append([]string{nydusdPath}, args...)
273+
args = append(delegateeCmdFlags, args...)
274+
cmd = exec.Command("systemd-run", args...)
275+
} else {
276+
cmd = exec.Command(nydusdPath, args...)
277+
// nydusd standard output and standard error rather than its logs are
278+
// always redirected to snapshotter's respectively
279+
cmd.Stdout = os.Stdout
280+
cmd.Stderr = os.Stderr
281+
}
216282

217-
cmd := exec.Command(nydusdPath, args...)
283+
return cmd, nil
284+
}
218285

219-
// nydusd standard output and standard error rather than its logs are
220-
// always redirected to snapshotter's respectively
221-
cmd.Stdout = os.Stdout
222-
cmd.Stderr = os.Stderr
286+
// executeInMntNamespace runs a function in the specified namespace and ensures thread isolation
287+
func executeInMntNamespace(mntNamespacePath string, fn func() error) error {
288+
runtime.LockOSThread()
289+
defer runtime.UnlockOSThread()
223290

224-
return cmd, nil
291+
// Detach from the shared fs of the rest of the Go process in order to
292+
// be able to CLONE_NEWNS.
293+
if err := unix.Unshare(unix.CLONE_FS); err != nil {
294+
return errors.Wrap(err, "failed to unshare filesystem namespace")
295+
}
296+
297+
targetNS, err := os.Open(mntNamespacePath)
298+
if err != nil {
299+
return errors.Wrapf(err, "failed to open target mnt namespace %q", mntNamespacePath)
300+
}
301+
defer targetNS.Close()
302+
303+
if err := unix.Setns(int(targetNS.Fd()), unix.CLONE_NEWNS); err != nil {
304+
return errors.Wrapf(err, "failed to enter the namespace %q", mntNamespacePath)
305+
}
306+
307+
if err := fn(); err != nil {
308+
log.L.WithError(err).Errorf("failed to execute in the mnt namespace %s", mntNamespacePath)
309+
return err
310+
}
311+
312+
return err
225313
}

pkg/manager/manager.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ type Manager struct {
3737
FsDriver string
3838
store Store
3939

40+
delegateNydusd bool
41+
4042
// Fields below are used to manage nydusd daemons.
4143
//
4244
// The `daemonCache` is cache for nydusd daemons stored in `store`.
@@ -59,6 +61,7 @@ type Opt struct {
5961
FsDriver string
6062
NydusdBinaryPath string
6163
RecoverPolicy config.DaemonRecoverPolicy
64+
DelegateNydusd bool // If true, the manager will not start nydusd daemons, but only manage them.
6265
RootDir string // Nydus-snapshotter work directory
6366
}
6467

@@ -93,6 +96,7 @@ func NewManager(opt Opt) (*Manager, error) {
9396
DaemonConfig: opt.DaemonConfig,
9497
CgroupMgr: opt.CgroupMgr,
9598
FsDriver: opt.FsDriver,
99+
delegateNydusd: opt.DelegateNydusd,
96100
}
97101

98102
// FIXME: How to get error if monitor goroutine terminates with error?

snapshot/snapshot.go

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,36 +14,33 @@ import (
1414
"path/filepath"
1515
"strings"
1616

17-
"github.com/pkg/errors"
18-
1917
"github.com/containerd/containerd/v2/core/mount"
2018
"github.com/containerd/containerd/v2/core/snapshots"
2119
"github.com/containerd/containerd/v2/core/snapshots/storage"
2220
snpkg "github.com/containerd/containerd/v2/pkg/snapshotters"
2321
"github.com/containerd/continuity/fs"
2422
"github.com/containerd/log"
23+
"github.com/pkg/errors"
24+
2525
"github.com/containerd/nydus-snapshotter/config"
2626
"github.com/containerd/nydus-snapshotter/config/daemonconfig"
27-
"github.com/containerd/nydus-snapshotter/pkg/rafs"
28-
2927
"github.com/containerd/nydus-snapshotter/pkg/cache"
3028
"github.com/containerd/nydus-snapshotter/pkg/cgroup"
3129
v2 "github.com/containerd/nydus-snapshotter/pkg/cgroup/v2"
3230
"github.com/containerd/nydus-snapshotter/pkg/errdefs"
31+
"github.com/containerd/nydus-snapshotter/pkg/filesystem"
32+
"github.com/containerd/nydus-snapshotter/pkg/label"
3333
mgr "github.com/containerd/nydus-snapshotter/pkg/manager"
3434
"github.com/containerd/nydus-snapshotter/pkg/metrics"
3535
"github.com/containerd/nydus-snapshotter/pkg/metrics/collector"
3636
"github.com/containerd/nydus-snapshotter/pkg/pprof"
37+
"github.com/containerd/nydus-snapshotter/pkg/rafs"
3738
"github.com/containerd/nydus-snapshotter/pkg/referrer"
38-
"github.com/containerd/nydus-snapshotter/pkg/system"
39-
"github.com/containerd/nydus-snapshotter/pkg/tarfs"
40-
41-
"github.com/containerd/nydus-snapshotter/pkg/store"
42-
43-
"github.com/containerd/nydus-snapshotter/pkg/filesystem"
44-
"github.com/containerd/nydus-snapshotter/pkg/label"
4539
"github.com/containerd/nydus-snapshotter/pkg/signature"
4640
"github.com/containerd/nydus-snapshotter/pkg/snapshot"
41+
"github.com/containerd/nydus-snapshotter/pkg/store"
42+
"github.com/containerd/nydus-snapshotter/pkg/system"
43+
"github.com/containerd/nydus-snapshotter/pkg/tarfs"
4744
)
4845

4946
var _ snapshots.Snapshotter = &snapshotter{}
@@ -154,6 +151,7 @@ func NewSnapshotter(ctx context.Context, cfg *config.SnapshotterConfig) (snapsho
154151
FsDriver: config.FsDriverFusedev,
155152
DaemonConfig: daemonConfig,
156153
CgroupMgr: cgroupMgr,
154+
DelegateNydusd: cfg.DelegateNydusd,
157155
})
158156
if err != nil {
159157
return nil, errors.Wrap(err, "create fusedev manager")

0 commit comments

Comments
 (0)