Browse code

Add memory.kernelTCP support for linux

This fix tries to address the issue raised in 37038 where
there were no memory.kernelTCP support for linux.

This fix add MemoryKernelTCP to HostConfig, and pass
the config to runtime-spec.

Additional test case has been added.

This fix fixes 37038.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>

Yong Tang authored on 2018/05/12 04:46:11
Showing 9 changed files
... ...
@@ -429,6 +429,10 @@ definitions:
429 429
         description: "Kernel memory limit in bytes."
430 430
         type: "integer"
431 431
         format: "int64"
432
+      KernelMemoryTCP:
433
+        description: "Sets hard limit for kernel TCP buffer memory."
434
+        type: "integer"
435
+        format: "int64"
432 436
       MemoryReservation:
433 437
         description: "Memory soft limit in bytes."
434 438
         type: "integer"
... ...
@@ -329,6 +329,7 @@ type Resources struct {
329 329
 	DeviceCgroupRules    []string        // List of rule to be added to the device cgroup
330 330
 	DiskQuota            int64           // Disk limit (in bytes)
331 331
 	KernelMemory         int64           // Kernel memory limit (in bytes)
332
+	KernelMemoryTCP      int64           // Sets hard limit for kernel TCP buffer memory
332 333
 	MemoryReservation    int64           // Memory soft limit (in bytes)
333 334
 	MemorySwap           int64           // Total memory usage (memory + swap); set `-1` to enable unlimited swap
334 335
 	MemorySwappiness     *int64          // Tuning container memory swappiness behaviour
... ...
@@ -158,6 +158,7 @@ type Info struct {
158 158
 	MemoryLimit        bool
159 159
 	SwapLimit          bool
160 160
 	KernelMemory       bool
161
+	KernelMemoryTCP    bool
161 162
 	CPUCfsPeriod       bool `json:"CpuCfsPeriod"`
162 163
 	CPUCfsQuota        bool `json:"CpuCfsQuota"`
163 164
 	CPUShares          bool
... ...
@@ -111,6 +111,10 @@ func getMemoryResources(config containertypes.Resources) *specs.LinuxMemory {
111 111
 		memory.Kernel = &config.KernelMemory
112 112
 	}
113 113
 
114
+	if config.KernelMemoryTCP != 0 {
115
+		memory.KernelTCP = &config.KernelMemoryTCP
116
+	}
117
+
114 118
 	return &memory
115 119
 }
116 120
 
... ...
@@ -20,6 +20,7 @@ func (daemon *Daemon) fillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo)
20 20
 	v.MemoryLimit = sysInfo.MemoryLimit
21 21
 	v.SwapLimit = sysInfo.SwapLimit
22 22
 	v.KernelMemory = sysInfo.KernelMemory
23
+	v.KernelMemoryTCP = sysInfo.KernelMemoryTCP
23 24
 	v.OomKillDisable = sysInfo.OomKillDisable
24 25
 	v.CPUCfsPeriod = sysInfo.CPUCfsPeriod
25 26
 	v.CPUCfsQuota = sysInfo.CPUCfsQuota
... ...
@@ -32,6 +32,7 @@ keywords: "API, Docker, rcli, REST, documentation"
32 32
 * `POST /swarm/init` now accepts a `DataPathPort` property to set data path port number.
33 33
 * `GET /info` now returns information about `DataPathPort` that is currently used in swarm
34 34
 * `GET /swarm` endpoint now returns DataPathPort info
35
+* `POST /containers/create` now takes `KernelMemoryTCP` field to set hard limit for kernel TCP buffer memory.
35 36
 
36 37
 ## V1.39 API changes
37 38
 
38 39
new file mode 100644
... ...
@@ -0,0 +1,49 @@
0
+package container // import "github.com/docker/docker/integration/container"
1
+
2
+import (
3
+	"context"
4
+	"strconv"
5
+	"strings"
6
+	"testing"
7
+	"time"
8
+
9
+	containertypes "github.com/docker/docker/api/types/container"
10
+	"github.com/docker/docker/integration/internal/container"
11
+	"github.com/docker/docker/internal/test/request"
12
+	"gotest.tools/assert"
13
+	is "gotest.tools/assert/cmp"
14
+	"gotest.tools/poll"
15
+	"gotest.tools/skip"
16
+)
17
+
18
+func TestKernelTCPMemory(t *testing.T) {
19
+	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
20
+	skip.If(t, !testEnv.DaemonInfo.KernelMemoryTCP)
21
+
22
+	defer setupTest(t)()
23
+	client := request.NewAPIClient(t)
24
+	ctx := context.Background()
25
+
26
+	const (
27
+		kernelMemoryTCP int64 = 200 * 1024 * 1024
28
+	)
29
+
30
+	cID := container.Run(t, ctx, client, func(c *container.TestContainerConfig) {
31
+		c.HostConfig.Resources = containertypes.Resources{
32
+			KernelMemoryTCP: kernelMemoryTCP,
33
+		}
34
+	})
35
+
36
+	poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
37
+
38
+	inspect, err := client.ContainerInspect(ctx, cID)
39
+	assert.NilError(t, err)
40
+	assert.Check(t, is.Equal(kernelMemoryTCP, inspect.HostConfig.KernelMemoryTCP))
41
+
42
+	res, err := container.Exec(ctx, client, cID,
43
+		[]string{"cat", "/sys/fs/cgroup/memory/memory.kmem.tcp.limit_in_bytes"})
44
+	assert.NilError(t, err)
45
+	assert.Assert(t, is.Len(res.Stderr(), 0))
46
+	assert.Equal(t, 0, res.ExitCode)
47
+	assert.Check(t, is.Equal(strconv.FormatInt(kernelMemoryTCP, 10), strings.TrimSpace(res.Stdout())))
48
+}
... ...
@@ -47,6 +47,9 @@ type cgroupMemInfo struct {
47 47
 
48 48
 	// Whether kernel memory limit is supported or not
49 49
 	KernelMemory bool
50
+
51
+	// Whether kernel memory TCP limit is supported or not
52
+	KernelMemoryTCP bool
50 53
 }
51 54
 
52 55
 type cgroupCPUInfo struct {
... ...
@@ -95,6 +95,10 @@ func checkCgroupMem(cgMounts map[string]string, quiet bool) cgroupMemInfo {
95 95
 	if !quiet && !kernelMemory {
96 96
 		logrus.Warn("Your kernel does not support kernel memory limit")
97 97
 	}
98
+	kernelMemoryTCP := cgroupEnabled(mountPoint, "memory.kmem.tcp.limit_in_bytes")
99
+	if !quiet && !kernelMemoryTCP {
100
+		logrus.Warn("Your kernel does not support kernel memory TCP limit")
101
+	}
98 102
 
99 103
 	return cgroupMemInfo{
100 104
 		MemoryLimit:       true,
... ...
@@ -103,6 +107,7 @@ func checkCgroupMem(cgMounts map[string]string, quiet bool) cgroupMemInfo {
103 103
 		OomKillDisable:    oomKillDisable,
104 104
 		MemorySwappiness:  memorySwappiness,
105 105
 		KernelMemory:      kernelMemory,
106
+		KernelMemoryTCP:   kernelMemoryTCP,
106 107
 	}
107 108
 }
108 109