From 5cb86180321bccae09bb69b8b3dfb5cd88fa862c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20=22WanzenBug=22=20Wanzenb=C3=B6ck?= Date: Thu, 13 Jun 2024 09:50:08 +0200 Subject: [PATCH] containerd: add option to set parent cgroup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using the "runc.v2" runtime, it is possible to configure containerd to start runc with the "systemd_cgroup" flag. This will cause runc to use systemd to manage the container cgroups. For this configuration to work, runc needs the cgroup name to be of a special form: "::". This is already implemented in the containerd runtime package, provided that a parent cgroup of the form "::" is set. This commit adds the option to configure such a parent cgroup for the containerd worker. By default, it will still use an empty string as cgroup parent, keeping existing behaviour. Using a configuration like: [worker.containerd] defaultCgroupParent = "system.slice:buildkit:" [worker.containerd.runtime] name = "io.containerd.runc.v2" [worker.containerd.runtime.options] SystemdCgroup = true a user is able to have their container cgroups managed by systemd. This makes it possible to set global resource constraints on a per-container basis using systemd drop-in configuration. When using the example above, the following file restricts every container spawned by buildkit to use only 1 CPU and 1G of RAM: $ cat /etc/systemd/system/buildkit-.scope.d/limits.conf [Scope] CPUQuota=100% MemoryMax=1G Signed-off-by: Moritz "WanzenBug" Wanzenböck --- cmd/buildkitd/config/config.go | 2 ++ cmd/buildkitd/main_containerd_worker.go | 2 +- docs/buildkitd.toml.md | 2 ++ worker/containerd/containerd.go | 7 ++++--- worker/containerd/containerd_test.go | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/cmd/buildkitd/config/config.go b/cmd/buildkitd/config/config.go index d8da19ecafec..32eaa7bd615b 100644 --- a/cmd/buildkitd/config/config.go +++ b/cmd/buildkitd/config/config.go @@ -142,6 +142,8 @@ type ContainerdConfig struct { MaxParallelism int `toml:"max-parallelism"` + DefaultCgroupParent string `toml:"defaultCgroupParent"` + Rootless bool `toml:"rootless"` } diff --git a/cmd/buildkitd/main_containerd_worker.go b/cmd/buildkitd/main_containerd_worker.go index ae8b2316d39f..5d2dcacd7354 100644 --- a/cmd/buildkitd/main_containerd_worker.go +++ b/cmd/buildkitd/main_containerd_worker.go @@ -328,7 +328,7 @@ func containerdWorkerInitializer(c *cli.Context, common workerInitializerOpt) ([ Options: opts, } } - opt, err := containerd.NewWorkerOpt(common.config.Root, cfg.Address, snapshotter, cfg.Namespace, cfg.Rootless, cfg.Labels, dns, nc, common.config.Workers.Containerd.ApparmorProfile, common.config.Workers.Containerd.SELinux, parallelismSem, common.traceSocket, runtime, ctd.WithTimeout(60*time.Second)) + opt, err := containerd.NewWorkerOpt(common.config.Root, cfg.Address, snapshotter, cfg.Namespace, cfg.DefaultCgroupParent, cfg.Rootless, cfg.Labels, dns, nc, common.config.Workers.Containerd.ApparmorProfile, common.config.Workers.Containerd.SELinux, parallelismSem, common.traceSocket, runtime, ctd.WithTimeout(60*time.Second)) if err != nil { return nil, err } diff --git a/docs/buildkitd.toml.md b/docs/buildkitd.toml.md index b117bf6e576f..9abe6d87f6fa 100644 --- a/docs/buildkitd.toml.md +++ b/docs/buildkitd.toml.md @@ -104,6 +104,8 @@ insecure-entitlements = [ "network.host", "security.insecure" ] # maintain a pool of reusable CNI network namespaces to amortize the overhead # of allocating and releasing the namespaces cniPoolSize = 16 + # defaultCgroupParent sets the parent cgroup of all containers. + defaultCgroupParent = "buildkit" [worker.containerd.labels] "foo" = "bar" diff --git a/worker/containerd/containerd.go b/worker/containerd/containerd.go index 42987b727b21..d9629ad66137 100644 --- a/worker/containerd/containerd.go +++ b/worker/containerd/containerd.go @@ -33,7 +33,7 @@ type RuntimeInfo = containerdexecutor.RuntimeInfo // NewWorkerOpt creates a WorkerOpt. func NewWorkerOpt( root string, - address, snapshotterName, ns string, + address, snapshotterName, ns, cgroupParent string, rootless bool, labels map[string]string, dns *oci.DNSConfig, @@ -62,6 +62,7 @@ func NewWorkerOpt( client, snapshotterName, ns, + cgroupParent, rootless, labels, dns, @@ -74,7 +75,7 @@ func NewWorkerOpt( ) } -func newContainerd(root string, client *containerd.Client, snapshotterName, ns string, rootless bool, labels map[string]string, dns *oci.DNSConfig, nopt netproviders.Opt, apparmorProfile string, selinux bool, parallelismSem *semaphore.Weighted, traceSocket string, runtime *RuntimeInfo) (base.WorkerOpt, error) { +func newContainerd(root string, client *containerd.Client, snapshotterName, ns, cgroupParent string, rootless bool, labels map[string]string, dns *oci.DNSConfig, nopt netproviders.Opt, apparmorProfile string, selinux bool, parallelismSem *semaphore.Weighted, traceSocket string, runtime *RuntimeInfo) (base.WorkerOpt, error) { if strings.Contains(snapshotterName, "/") { return base.WorkerOpt{}, errors.Errorf("bad snapshotter name: %q", snapshotterName) } @@ -176,7 +177,7 @@ func newContainerd(root string, client *containerd.Client, snapshotterName, ns s Labels: xlabels, MetadataStore: md, NetworkProviders: np, - Executor: containerdexecutor.New(client, root, "", np, dns, apparmorProfile, selinux, traceSocket, rootless, runtime), + Executor: containerdexecutor.New(client, root, cgroupParent, np, dns, apparmorProfile, selinux, traceSocket, rootless, runtime), Snapshotter: snap, ContentStore: cs, Applier: winlayers.NewFileSystemApplierWithWindows(cs, df), diff --git a/worker/containerd/containerd_test.go b/worker/containerd/containerd_test.go index 82e804a4fcbc..d6bbb8dbddee 100644 --- a/worker/containerd/containerd_test.go +++ b/worker/containerd/containerd_test.go @@ -31,7 +31,7 @@ func TestContainerdWorkerIntegration(t *testing.T) { func newWorkerOpt(t *testing.T, addr string) base.WorkerOpt { tmpdir := t.TempDir() rootless := false - workerOpt, err := NewWorkerOpt(tmpdir, addr, "overlayfs", "buildkit-test", rootless, nil, nil, netproviders.Opt{Mode: "host"}, "", false, nil, "", nil) + workerOpt, err := NewWorkerOpt(tmpdir, addr, "overlayfs", "buildkit-test", "", rootless, nil, nil, netproviders.Opt{Mode: "host"}, "", false, nil, "", nil) require.NoError(t, err) return workerOpt }