Bläddra i källkod

Merge pull request #37043 from yongtang/37038-kernelTCP

Add memory.kernelTCP support for linux
Sebastiaan van Stijn 6 år sedan
förälder
incheckning
d3e75e4220

+ 6 - 0
api/server/router/container/container_routes.go

@@ -475,6 +475,12 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
 		}
 	}
 
+	// When using API 1.39 and under, KernelMemoryTCP should be ignored because it
+	// was added in API 1.40.
+	if hostConfig != nil && versions.LessThan(version, "1.40") {
+		hostConfig.KernelMemoryTCP = 0
+	}
+
 	ccr, err := s.backend.ContainerCreate(types.ContainerCreateConfig{
 		Name:             name,
 		Config:           config,

+ 4 - 0
api/swagger.yaml

@@ -429,6 +429,10 @@ definitions:
         description: "Kernel memory limit in bytes."
         type: "integer"
         format: "int64"
+      KernelMemoryTCP:
+        description: "Sets hard limit for kernel TCP buffer memory."
+        type: "integer"
+        format: "int64"
       MemoryReservation:
         description: "Memory soft limit in bytes."
         type: "integer"

+ 1 - 0
api/types/container/host_config.go

@@ -329,6 +329,7 @@ type Resources struct {
 	DeviceCgroupRules    []string        // List of rule to be added to the device cgroup
 	DiskQuota            int64           // Disk limit (in bytes)
 	KernelMemory         int64           // Kernel memory limit (in bytes)
+	KernelMemoryTCP      int64           // Sets hard limit for kernel TCP buffer memory
 	MemoryReservation    int64           // Memory soft limit (in bytes)
 	MemorySwap           int64           // Total memory usage (memory + swap); set `-1` to enable unlimited swap
 	MemorySwappiness     *int64          // Tuning container memory swappiness behaviour

+ 1 - 0
api/types/types.go

@@ -158,6 +158,7 @@ type Info struct {
 	MemoryLimit        bool
 	SwapLimit          bool
 	KernelMemory       bool
+	KernelMemoryTCP    bool
 	CPUCfsPeriod       bool `json:"CpuCfsPeriod"`
 	CPUCfsQuota        bool `json:"CpuCfsQuota"`
 	CPUShares          bool

+ 4 - 0
daemon/daemon_unix.go

@@ -111,6 +111,10 @@ func getMemoryResources(config containertypes.Resources) *specs.LinuxMemory {
 		memory.Kernel = &config.KernelMemory
 	}
 
+	if config.KernelMemoryTCP != 0 {
+		memory.KernelTCP = &config.KernelMemoryTCP
+	}
+
 	return &memory
 }
 

+ 1 - 0
daemon/info_unix.go

@@ -20,6 +20,7 @@ func (daemon *Daemon) fillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo)
 	v.MemoryLimit = sysInfo.MemoryLimit
 	v.SwapLimit = sysInfo.SwapLimit
 	v.KernelMemory = sysInfo.KernelMemory
+	v.KernelMemoryTCP = sysInfo.KernelMemoryTCP
 	v.OomKillDisable = sysInfo.OomKillDisable
 	v.CPUCfsPeriod = sysInfo.CPUCfsPeriod
 	v.CPUCfsQuota = sysInfo.CPUCfsQuota

+ 1 - 0
docs/api/version-history.md

@@ -32,6 +32,7 @@ keywords: "API, Docker, rcli, REST, documentation"
 * `POST /swarm/init` now accepts a `DataPathPort` property to set data path port number.
 * `GET /info` now returns information about `DataPathPort` that is currently used in swarm
 * `GET /swarm` endpoint now returns DataPathPort info
+* `POST /containers/create` now takes `KernelMemoryTCP` field to set hard limit for kernel TCP buffer memory.
 
 ## V1.39 API changes
 

+ 51 - 0
integration/container/run_linux_test.go

@@ -0,0 +1,51 @@
+package container // import "github.com/docker/docker/integration/container"
+
+import (
+	"context"
+	"strconv"
+	"strings"
+	"testing"
+	"time"
+
+	containertypes "github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/api/types/versions"
+	"github.com/docker/docker/integration/internal/container"
+	"github.com/docker/docker/internal/test/request"
+	"gotest.tools/assert"
+	is "gotest.tools/assert/cmp"
+	"gotest.tools/poll"
+	"gotest.tools/skip"
+)
+
+func TestKernelTCPMemory(t *testing.T) {
+	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
+	skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.40"), "skip test from new feature")
+	skip.If(t, !testEnv.DaemonInfo.KernelMemoryTCP)
+
+	defer setupTest(t)()
+	client := request.NewAPIClient(t)
+	ctx := context.Background()
+
+	const (
+		kernelMemoryTCP int64 = 200 * 1024 * 1024
+	)
+
+	cID := container.Run(t, ctx, client, func(c *container.TestContainerConfig) {
+		c.HostConfig.Resources = containertypes.Resources{
+			KernelMemoryTCP: kernelMemoryTCP,
+		}
+	})
+
+	poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
+
+	inspect, err := client.ContainerInspect(ctx, cID)
+	assert.NilError(t, err)
+	assert.Check(t, is.Equal(kernelMemoryTCP, inspect.HostConfig.KernelMemoryTCP))
+
+	res, err := container.Exec(ctx, client, cID,
+		[]string{"cat", "/sys/fs/cgroup/memory/memory.kmem.tcp.limit_in_bytes"})
+	assert.NilError(t, err)
+	assert.Assert(t, is.Len(res.Stderr(), 0))
+	assert.Equal(t, 0, res.ExitCode)
+	assert.Check(t, is.Equal(strconv.FormatInt(kernelMemoryTCP, 10), strings.TrimSpace(res.Stdout())))
+}

+ 3 - 0
pkg/sysinfo/sysinfo.go

@@ -47,6 +47,9 @@ type cgroupMemInfo struct {
 
 	// Whether kernel memory limit is supported or not
 	KernelMemory bool
+
+	// Whether kernel memory TCP limit is supported or not
+	KernelMemoryTCP bool
 }
 
 type cgroupCPUInfo struct {

+ 5 - 0
pkg/sysinfo/sysinfo_linux.go

@@ -95,6 +95,10 @@ func checkCgroupMem(cgMounts map[string]string, quiet bool) cgroupMemInfo {
 	if !quiet && !kernelMemory {
 		logrus.Warn("Your kernel does not support kernel memory limit")
 	}
+	kernelMemoryTCP := cgroupEnabled(mountPoint, "memory.kmem.tcp.limit_in_bytes")
+	if !quiet && !kernelMemoryTCP {
+		logrus.Warn("Your kernel does not support kernel memory TCP limit")
+	}
 
 	return cgroupMemInfo{
 		MemoryLimit:       true,
@@ -103,6 +107,7 @@ func checkCgroupMem(cgMounts map[string]string, quiet bool) cgroupMemInfo {
 		OomKillDisable:    oomKillDisable,
 		MemorySwappiness:  memorySwappiness,
 		KernelMemory:      kernelMemory,
+		KernelMemoryTCP:   kernelMemoryTCP,
 	}
 }