Skip to content

Commit

Permalink
daemon: load and cache sysInfo on initialization
Browse files Browse the repository at this point in the history
The `daemon.RawSysInfo()` function can be a heavy operation, as it collects
information about all cgroups on the host, networking, AppArmor, Seccomp, etc.

While looking at our code, I noticed that various parts in the code call this
function, potentially even _multiple times_ per container, for example, it is
called from:

- `verifyPlatformContainerSettings()`
- `oci.WithCgroups()` if the daemon has `cpu-rt-period` or `cpu-rt-runtime` configured
- in `ContainerDecoder.DecodeConfig()`, which is called on boith `container create` and `container commit`

Given that this information is not expected to change during the daemon's
lifecycle, and various information coming from this (such as seccomp and
apparmor status) was already cached, we may as well load it once, and cache
the results in the daemon instance.

This patch updates `daemon.RawSysInfo()` to use a `sync.Once()` so that
it's only executed once for the daemon's lifecycle.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
  • Loading branch information
thaJeztah committed Jan 12, 2022
1 parent f045d0d commit 483aa62
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 34 deletions.
11 changes: 4 additions & 7 deletions daemon/container_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,18 @@ import (
func (daemon *Daemon) saveAppArmorConfig(container *container.Container) error {
container.AppArmorProfile = "" // we don't care about the previous value.

if !daemon.apparmorEnabled {
if !daemon.RawSysInfo().AppArmor {
return nil // if apparmor is disabled there is nothing to do here.
}

if err := parseSecurityOpt(container, container.HostConfig); err != nil {
return errdefs.InvalidParameter(err)
}

if !container.HostConfig.Privileged {
if container.AppArmorProfile == "" {
container.AppArmorProfile = defaultAppArmorProfile
}

} else {
if container.HostConfig.Privileged {
container.AppArmorProfile = unconfinedAppArmorProfile
} else if container.AppArmorProfile == "" {
container.AppArmorProfile = defaultAppArmorProfile
}
return nil
}
20 changes: 16 additions & 4 deletions daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import (
"github.com/docker/docker/pkg/fileutils"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/plugingetter"
"github.com/docker/docker/pkg/sysinfo"
"github.com/docker/docker/pkg/system"
"github.com/docker/docker/pkg/truncindex"
"github.com/docker/docker/plugin"
Expand Down Expand Up @@ -92,8 +93,8 @@ type Daemon struct {
netController libnetwork.NetworkController
volumes *volumesservice.VolumesService
root string
seccompEnabled bool
apparmorEnabled bool
sysInfoOnce sync.Once
sysInfo *sysinfo.SysInfo
shutdown bool
idMapping *idtools.IdentityMapping
graphDriver string // TODO: move graphDriver field to an InfoService
Expand Down Expand Up @@ -1034,8 +1035,6 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
d.EventsService = events.New()
d.root = config.Root
d.idMapping = idMapping
d.seccompEnabled = sysInfo.Seccomp
d.apparmorEnabled = sysInfo.AppArmor

d.linkIndex = newLinkIndex()

Expand Down Expand Up @@ -1472,3 +1471,16 @@ func (daemon *Daemon) BuilderBackend() builder.Backend {
*images.ImageService
}{daemon, daemon.imageService}
}

// RawSysInfo returns *sysinfo.SysInfo .
func (daemon *Daemon) RawSysInfo() *sysinfo.SysInfo {
daemon.sysInfoOnce.Do(func() {
// We check if sysInfo is not set here, to allow some test to
// override the actual sysInfo.
if daemon.sysInfo == nil {
daemon.loadSysInfo()
}
})

return daemon.sysInfo
}
13 changes: 6 additions & 7 deletions daemon/daemon_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -1731,19 +1731,14 @@ func (daemon *Daemon) setupSeccompProfile() error {
return nil
}

// RawSysInfo returns *sysinfo.SysInfo .
func (daemon *Daemon) RawSysInfo() *sysinfo.SysInfo {
func (daemon *Daemon) loadSysInfo() {
var siOpts []sysinfo.Opt
if daemon.getCgroupDriver() == cgroupSystemdDriver {
if euid := os.Getenv("ROOTLESSKIT_PARENT_EUID"); euid != "" {
siOpts = append(siOpts, sysinfo.WithCgroup2GroupPath("/user.slice/user-"+euid+".slice"))
}
}
return sysinfo.New(siOpts...)
}

func recursiveUnmount(target string) error {
return mount.RecursiveUnmount(target)
daemon.sysInfo = sysinfo.New(siOpts...)
}

func (daemon *Daemon) initLibcontainerd(ctx context.Context) error {
Expand All @@ -1757,3 +1752,7 @@ func (daemon *Daemon) initLibcontainerd(ctx context.Context) error {
)
return err
}

func recursiveUnmount(target string) error {
return mount.RecursiveUnmount(target)
}
5 changes: 2 additions & 3 deletions daemon/daemon_unsupported.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const platformSupported = false
func setupResolvConf(config *config.Config) {
}

// RawSysInfo returns *sysinfo.SysInfo .
func (daemon *Daemon) RawSysInfo() *sysinfo.SysInfo {
return sysinfo.New()
func (daemon *Daemon) loadSysInfo() {
daemon.sysInfo = sysinfo.New()
}
5 changes: 2 additions & 3 deletions daemon/daemon_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -650,9 +650,8 @@ func (daemon *Daemon) initRuntimes(_ map[string]types.Runtime) error {
func setupResolvConf(config *config.Config) {
}

// RawSysInfo returns *sysinfo.SysInfo .
func (daemon *Daemon) RawSysInfo() *sysinfo.SysInfo {
return sysinfo.New()
func (daemon *Daemon) loadSysInfo() {
daemon.sysInfo = sysinfo.New()
}

func (daemon *Daemon) initLibcontainerd(ctx context.Context) error {
Expand Down
2 changes: 1 addition & 1 deletion daemon/seccomp_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func WithSeccomp(daemon *Daemon, c *container.Container) coci.SpecOpts {
if c.HostConfig.Privileged {
return nil
}
if !daemon.seccompEnabled {
if !daemon.RawSysInfo().Seccomp {
if c.SeccompProfile != "" && c.SeccompProfile != dconfig.SeccompProfileDefault {
return fmt.Errorf("seccomp is not enabled in your kernel, cannot run a custom seccomp profile")
}
Expand Down
20 changes: 11 additions & 9 deletions daemon/seccomp_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/docker/docker/container"
dconfig "github.com/docker/docker/daemon/config"
doci "github.com/docker/docker/oci"
"github.com/docker/docker/pkg/sysinfo"
"github.com/docker/docker/profiles/seccomp"
specs "github.com/opencontainers/runtime-spec/specs-go"
"gotest.tools/v3/assert"
Expand All @@ -31,7 +32,7 @@ func TestWithSeccomp(t *testing.T) {
{
comment: "unconfined seccompProfile runs unconfined",
daemon: &Daemon{
seccompEnabled: true,
sysInfo: &sysinfo.SysInfo{Seccomp: true},
},
c: &container.Container{
SeccompProfile: dconfig.SeccompProfileUnconfined,
Expand All @@ -45,7 +46,7 @@ func TestWithSeccomp(t *testing.T) {
{
comment: "privileged container w/ custom profile runs unconfined",
daemon: &Daemon{
seccompEnabled: true,
sysInfo: &sysinfo.SysInfo{Seccomp: true},
},
c: &container.Container{
SeccompProfile: "{ \"defaultAction\": \"SCMP_ACT_LOG\" }",
Expand All @@ -59,7 +60,7 @@ func TestWithSeccomp(t *testing.T) {
{
comment: "privileged container w/ default runs unconfined",
daemon: &Daemon{
seccompEnabled: true,
sysInfo: &sysinfo.SysInfo{Seccomp: true},
},
c: &container.Container{
SeccompProfile: "",
Expand All @@ -73,7 +74,7 @@ func TestWithSeccomp(t *testing.T) {
{
comment: "privileged container w/ daemon profile runs unconfined",
daemon: &Daemon{
seccompEnabled: true,
sysInfo: &sysinfo.SysInfo{Seccomp: true},
seccompProfile: []byte("{ \"defaultAction\": \"SCMP_ACT_ERRNO\" }"),
},
c: &container.Container{
Expand All @@ -88,7 +89,7 @@ func TestWithSeccomp(t *testing.T) {
{
comment: "custom profile when seccomp is disabled returns error",
daemon: &Daemon{
seccompEnabled: false,
sysInfo: &sysinfo.SysInfo{Seccomp: false},
},
c: &container.Container{
SeccompProfile: "{ \"defaultAction\": \"SCMP_ACT_ERRNO\" }",
Expand All @@ -103,7 +104,7 @@ func TestWithSeccomp(t *testing.T) {
{
comment: "empty profile name loads default profile",
daemon: &Daemon{
seccompEnabled: true,
sysInfo: &sysinfo.SysInfo{Seccomp: true},
},
c: &container.Container{
SeccompProfile: "",
Expand All @@ -122,7 +123,7 @@ func TestWithSeccomp(t *testing.T) {
{
comment: "load container's profile",
daemon: &Daemon{
seccompEnabled: true,
sysInfo: &sysinfo.SysInfo{Seccomp: true},
},
c: &container.Container{
SeccompProfile: "{ \"defaultAction\": \"SCMP_ACT_ERRNO\" }",
Expand All @@ -143,7 +144,7 @@ func TestWithSeccomp(t *testing.T) {
{
comment: "load daemon's profile",
daemon: &Daemon{
seccompEnabled: true,
sysInfo: &sysinfo.SysInfo{Seccomp: true},
seccompProfile: []byte("{ \"defaultAction\": \"SCMP_ACT_ERRNO\" }"),
},
c: &container.Container{
Expand All @@ -165,7 +166,7 @@ func TestWithSeccomp(t *testing.T) {
{
comment: "load prioritise container profile over daemon's",
daemon: &Daemon{
seccompEnabled: true,
sysInfo: &sysinfo.SysInfo{Seccomp: true},
seccompProfile: []byte("{ \"defaultAction\": \"SCMP_ACT_ERRNO\" }"),
},
c: &container.Container{
Expand All @@ -185,6 +186,7 @@ func TestWithSeccomp(t *testing.T) {
}(),
},
} {
x := x
t.Run(x.comment, func(t *testing.T) {
opts := WithSeccomp(x.daemon, x.c)
err := opts(nil, nil, nil, &x.inSpec)
Expand Down

0 comments on commit 483aa62

Please sign in to comment.