Add ulimits support to services

Add Ulimits field to the ContainerSpec API type and wire it to Swarmkit.

This is related to #40639.

Signed-off-by: Albin Kerouanton <albin@akerouanton.name>
This commit is contained in:
Albin Kerouanton 2020-07-26 13:42:33 +02:00
parent 1fdb1033c4
commit c76f380bea
No known key found for this signature in database
GPG Key ID: 630B8E1DCBDB1864
7 changed files with 81 additions and 1 deletions

View File

@ -97,10 +97,11 @@ func adjustForAPIVersion(cliVersion string, service *swarm.ServiceSpec) {
}
if versions.LessThan(cliVersion, "1.41") {
if service.TaskTemplate.ContainerSpec != nil {
// Capabilities for docker swarm services weren't
// Capabilities and Ulimits for docker swarm services weren't
// supported before API version 1.41
service.TaskTemplate.ContainerSpec.CapabilityAdd = nil
service.TaskTemplate.ContainerSpec.CapabilityDrop = nil
service.TaskTemplate.ContainerSpec.Ulimits = nil
}
if service.TaskTemplate.Resources != nil && service.TaskTemplate.Resources.Limits != nil {
// Limits.Pids not supported before API version 1.41

View File

@ -5,6 +5,7 @@ import (
"testing"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/go-units"
)
func TestAdjustForAPIVersion(t *testing.T) {
@ -39,6 +40,13 @@ func TestAdjustForAPIVersion(t *testing.T) {
ConfigName: "configRuntime",
},
},
Ulimits: []*units.Ulimit{
{
Name: "nofile",
Soft: 100,
Hard: 200,
},
},
},
Placement: &swarm.Placement{
MaxReplicas: 222,
@ -78,6 +86,10 @@ func TestAdjustForAPIVersion(t *testing.T) {
t.Error("MaxReplicas was stripped from spec")
}
if len(spec.TaskTemplate.ContainerSpec.Ulimits) == 0 {
t.Error("Ulimits were stripped from spec")
}
// next, does calling this with an earlier version correctly strip fields?
adjustForAPIVersion("1.29", spec)
if spec.TaskTemplate.ContainerSpec.Sysctls != nil {
@ -100,4 +112,8 @@ func TestAdjustForAPIVersion(t *testing.T) {
t.Error("MaxReplicas was not stripped from spec")
}
if len(spec.TaskTemplate.ContainerSpec.Ulimits) != 0 {
t.Error("Ulimits were not stripped from spec")
}
}

View File

@ -3306,6 +3306,22 @@ definitions:
type: "string"
example:
- "CAP_NET_RAW"
Ulimits:
description: |
A list of resource limits to set in the container. For example: `{"Name": "nofile", "Soft": 1024, "Hard": 2048}`"
type: "array"
items:
type: "object"
properties:
Name:
description: "Name of ulimit"
type: "string"
Soft:
description: "Soft limit"
type: "integer"
Hard:
description: "Hard limit"
type: "integer"
NetworkAttachmentSpec:
description: |
Read-only spec type for non-swarm containers attached to swarm overlay

View File

@ -5,6 +5,7 @@ import (
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/mount"
"github.com/docker/go-units"
)
// DNSConfig specifies DNS related configurations in resolver configuration file (resolv.conf)
@ -75,4 +76,5 @@ type ContainerSpec struct {
Sysctls map[string]string `json:",omitempty"`
CapabilityAdd []string `json:",omitempty"`
CapabilityDrop []string `json:",omitempty"`
Ulimits []*units.Ulimit `json:",omitempty"`
}

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/docker/api/types/container"
mounttypes "github.com/docker/docker/api/types/mount"
types "github.com/docker/docker/api/types/swarm"
"github.com/docker/go-units"
swarmapi "github.com/docker/swarmkit/api"
gogotypes "github.com/gogo/protobuf/types"
"github.com/pkg/errors"
@ -39,6 +40,7 @@ func containerSpecFromGRPC(c *swarmapi.ContainerSpec) *types.ContainerSpec {
Sysctls: c.Sysctls,
CapabilityAdd: c.CapabilityAdd,
CapabilityDrop: c.CapabilityDrop,
Ulimits: ulimitsFromGRPC(c.Ulimits),
}
if c.DNSConfig != nil {
@ -267,6 +269,7 @@ func containerToGRPC(c *types.ContainerSpec) (*swarmapi.ContainerSpec, error) {
Sysctls: c.Sysctls,
CapabilityAdd: c.CapabilityAdd,
CapabilityDrop: c.CapabilityDrop,
Ulimits: ulimitsToGRPC(c.Ulimits),
}
if c.DNSConfig != nil {
@ -471,3 +474,31 @@ func isolationToGRPC(i container.Isolation) swarmapi.ContainerSpec_Isolation {
}
return swarmapi.ContainerIsolationDefault
}
func ulimitsFromGRPC(u []*swarmapi.ContainerSpec_Ulimit) []*units.Ulimit {
ulimits := make([]*units.Ulimit, len(u))
for i, ulimit := range u {
ulimits[i] = &units.Ulimit{
Name: ulimit.Name,
Soft: ulimit.Soft,
Hard: ulimit.Hard,
}
}
return ulimits
}
func ulimitsToGRPC(u []*units.Ulimit) []*swarmapi.ContainerSpec_Ulimit {
ulimits := make([]*swarmapi.ContainerSpec_Ulimit, len(u))
for i, ulimit := range u {
ulimits[i] = &swarmapi.ContainerSpec_Ulimit{
Name: ulimit.Name,
Soft: ulimit.Soft,
Hard: ulimit.Hard,
}
}
return ulimits
}

View File

@ -21,6 +21,7 @@ import (
executorpkg "github.com/docker/docker/daemon/cluster/executor"
clustertypes "github.com/docker/docker/daemon/cluster/provider"
"github.com/docker/go-connections/nat"
"github.com/docker/go-units"
netconst "github.com/docker/libnetwork/datastore"
"github.com/docker/swarmkit/agent/exec"
"github.com/docker/swarmkit/api"
@ -438,6 +439,15 @@ func (c *containerConfig) resources() enginecontainer.Resources {
resources.PidsLimit = &pidsLimit
}
resources.Ulimits = make([]*units.Ulimit, len(c.spec().Ulimits))
for i, ulimit := range c.spec().Ulimits {
resources.Ulimits[i] = &units.Ulimit{
Name: ulimit.Name,
Soft: ulimit.Soft,
Hard: ulimit.Hard,
}
}
// If no limits are specified let the engine use its defaults.
//
// TODO(aluzzardi): We might want to set some limits anyway otherwise

View File

@ -76,6 +76,10 @@ keywords: "API, Docker, rcli, REST, documentation"
single set of stats instead of waiting for two collection cycles to have 2 CPU stats over a 1 second period.
* The `KernelMemory` field in `HostConfig.Resources` is now deprecated.
* The `KernelMemory` field in `Info` is now deprecated.
* `GET /services` now returns `Ulimits` as part of `ContainerSpec`.
* `GET /services/{id}` now returns `Ulimits` as part of `ContainerSpec`.
* `POST /services/create` now accepts `Ulimits` as part of `ContainerSpec`.
* `POST /services/{id}/update` now accepts `Ulimits` as part of `ContainerSpec`.
## v1.40 API changes