mirror of
https://github.com/moby/buildkit.git
synced 2026-11-06 05:16:45 +00:00
runcexecutor: share keyring in NoProcessSandbox
In NoProcessSandbox mode the build container runs in the PID namespace
of buildkitd, so a process that a step leaves running in the background
is not killed when the step ends. runc still creates a new session
keyring for every container, and each leftover process keeps that
keyring alive. Each of them takes one key from the per-user quota of the
daemon user (kernel.keys.maxkeys, 200 by default for non-root). Once the
quota is used up, every new container fails with:
unable to join session keyring: unable to create session key: disk
quota exceeded
Restarting buildkitd ends the leftover processes and frees the keys, so
long-running rootless daemons hit this again after some days.
Run runc with --no-new-keyring in this mode, so the build containers
use the session keyring of buildkitd. They already share the PID
namespace and procfs with the daemon, and runc treats the per-container
keyring as best-effort isolation, so this removes nothing the mode
provides. ProcessSandbox mode is unchanged.
Fixes #7310
Refs #6247
Signed-off-by: Joao Otavio Manieri <69759037+JoaoManierii@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ce2b38c3a2
commit
eac3279c43
2 files changed
+38
-4
No files matched your search
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/containerd/console"
|
||||
runc "github.com/containerd/go-runc"
|
||||
"github.com/moby/buildkit/executor"
|
||||
"github.com/moby/buildkit/executor/oci"
|
||||
gatewayapi "github.com/moby/buildkit/frontend/gateway/pb"
|
||||
"github.com/moby/buildkit/util/bklog"
|
||||
"github.com/moby/sys/signal"
|
||||
@@ -34,10 +35,14 @@ func (w *runcExecutor) run(ctx context.Context, id, bundle string, process execu
|
||||
extraArgs = append(extraArgs, "--keep")
|
||||
}
|
||||
_, err := w.runc.Run(ctx, id, bundle, &runc.CreateOpts{
|
||||
NoPivot: w.noPivot,
|
||||
Started: started,
|
||||
IO: io,
|
||||
ExtraArgs: extraArgs,
|
||||
NoPivot: w.noPivot,
|
||||
// Without a PID namespace, processes left behind by a step outlive the
|
||||
// container and keep its session keyring, until the per-user key quota
|
||||
// is exhausted and every new container fails to start.
|
||||
NoNewKeyring: w.processMode == oci.NoProcessSandbox,
|
||||
Started: started,
|
||||
IO: io,
|
||||
ExtraArgs: extraArgs,
|
||||
})
|
||||
return err
|
||||
})
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/moby/buildkit/client"
|
||||
"github.com/moby/buildkit/executor"
|
||||
"github.com/moby/buildkit/executor/oci"
|
||||
"github.com/moby/buildkit/identity"
|
||||
"github.com/moby/buildkit/session"
|
||||
"github.com/moby/buildkit/snapshot"
|
||||
"github.com/moby/buildkit/util/iohelper"
|
||||
@@ -211,6 +212,34 @@ func TestRuncWorkerNoProcessSandbox(t *testing.T) {
|
||||
require.Equal(t, string(selfCmdline), stdout.String())
|
||||
}
|
||||
|
||||
func TestRuncWorkerNoProcessSandboxSessionKeyring(t *testing.T) {
|
||||
t.Parallel()
|
||||
checkRequirement(t)
|
||||
|
||||
workerOpt := newWorkerOpt(t, oci.NoProcessSandbox)
|
||||
w, err := base.NewWorker(t.Context(), workerOpt)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := tests.NewCtx("buildkit-test")
|
||||
sm, err := session.NewManager()
|
||||
require.NoError(t, err)
|
||||
snap := tests.NewBusyboxSourceSnapshot(ctx, t, w, sm)
|
||||
root, err := w.CacheMgr.New(ctx, snap, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
id := identity.NewID()
|
||||
meta := executor.Meta{
|
||||
Args: []string{"/bin/cat", "/proc/keys"},
|
||||
Cwd: "/",
|
||||
}
|
||||
stdout := bytes.NewBuffer(nil)
|
||||
stderr := bytes.NewBuffer(nil)
|
||||
_, err = w.WorkerOpt.Executor.Run(ctx, id, execMount(root, false), nil, executor.ProcessInfo{Meta: meta, Stdout: &iohelper.NopWriteCloser{Writer: stdout}, Stderr: &iohelper.NopWriteCloser{Writer: stderr}}, nil)
|
||||
require.NoError(t, err, "stdout=%q, stderr=%q", stdout.String(), stderr.String())
|
||||
// runc names the session keyring it creates for a container "_ses.<id>".
|
||||
require.NotContains(t, stdout.String(), "_ses."+id)
|
||||
}
|
||||
|
||||
func TestRuncWorkerExec(t *testing.T) {
|
||||
t.Parallel()
|
||||
checkRequirement(t)
|
||||
|
||||
Reference in new issue
Block a user