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>
| ... | ... |
@@ -97,10 +97,11 @@ func adjustForAPIVersion(cliVersion string, service *swarm.ServiceSpec) {
|
| 97 | 97 |
} |
| 98 | 98 |
if versions.LessThan(cliVersion, "1.41") {
|
| 99 | 99 |
if service.TaskTemplate.ContainerSpec != nil {
|
| 100 |
- // Capabilities for docker swarm services weren't |
|
| 100 |
+ // Capabilities and Ulimits for docker swarm services weren't |
|
| 101 | 101 |
// supported before API version 1.41 |
| 102 | 102 |
service.TaskTemplate.ContainerSpec.CapabilityAdd = nil |
| 103 | 103 |
service.TaskTemplate.ContainerSpec.CapabilityDrop = nil |
| 104 |
+ service.TaskTemplate.ContainerSpec.Ulimits = nil |
|
| 104 | 105 |
} |
| 105 | 106 |
if service.TaskTemplate.Resources != nil && service.TaskTemplate.Resources.Limits != nil {
|
| 106 | 107 |
// Limits.Pids not supported before API version 1.41 |
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
"testing" |
| 6 | 6 |
|
| 7 | 7 |
"github.com/docker/docker/api/types/swarm" |
| 8 |
+ "github.com/docker/go-units" |
|
| 8 | 9 |
) |
| 9 | 10 |
|
| 10 | 11 |
func TestAdjustForAPIVersion(t *testing.T) {
|
| ... | ... |
@@ -39,6 +40,13 @@ func TestAdjustForAPIVersion(t *testing.T) {
|
| 39 | 39 |
ConfigName: "configRuntime", |
| 40 | 40 |
}, |
| 41 | 41 |
}, |
| 42 |
+ Ulimits: []*units.Ulimit{
|
|
| 43 |
+ {
|
|
| 44 |
+ Name: "nofile", |
|
| 45 |
+ Soft: 100, |
|
| 46 |
+ Hard: 200, |
|
| 47 |
+ }, |
|
| 48 |
+ }, |
|
| 42 | 49 |
}, |
| 43 | 50 |
Placement: &swarm.Placement{
|
| 44 | 51 |
MaxReplicas: 222, |
| ... | ... |
@@ -78,6 +86,10 @@ func TestAdjustForAPIVersion(t *testing.T) {
|
| 78 | 78 |
t.Error("MaxReplicas was stripped from spec")
|
| 79 | 79 |
} |
| 80 | 80 |
|
| 81 |
+ if len(spec.TaskTemplate.ContainerSpec.Ulimits) == 0 {
|
|
| 82 |
+ t.Error("Ulimits were stripped from spec")
|
|
| 83 |
+ } |
|
| 84 |
+ |
|
| 81 | 85 |
// next, does calling this with an earlier version correctly strip fields? |
| 82 | 86 |
adjustForAPIVersion("1.29", spec)
|
| 83 | 87 |
if spec.TaskTemplate.ContainerSpec.Sysctls != nil {
|
| ... | ... |
@@ -100,4 +112,8 @@ func TestAdjustForAPIVersion(t *testing.T) {
|
| 100 | 100 |
t.Error("MaxReplicas was not stripped from spec")
|
| 101 | 101 |
} |
| 102 | 102 |
|
| 103 |
+ if len(spec.TaskTemplate.ContainerSpec.Ulimits) != 0 {
|
|
| 104 |
+ t.Error("Ulimits were not stripped from spec")
|
|
| 105 |
+ } |
|
| 106 |
+ |
|
| 103 | 107 |
} |
| ... | ... |
@@ -3306,6 +3306,22 @@ definitions: |
| 3306 | 3306 |
type: "string" |
| 3307 | 3307 |
example: |
| 3308 | 3308 |
- "CAP_NET_RAW" |
| 3309 |
+ Ulimits: |
|
| 3310 |
+ description: | |
|
| 3311 |
+ A list of resource limits to set in the container. For example: `{"Name": "nofile", "Soft": 1024, "Hard": 2048}`"
|
|
| 3312 |
+ type: "array" |
|
| 3313 |
+ items: |
|
| 3314 |
+ type: "object" |
|
| 3315 |
+ properties: |
|
| 3316 |
+ Name: |
|
| 3317 |
+ description: "Name of ulimit" |
|
| 3318 |
+ type: "string" |
|
| 3319 |
+ Soft: |
|
| 3320 |
+ description: "Soft limit" |
|
| 3321 |
+ type: "integer" |
|
| 3322 |
+ Hard: |
|
| 3323 |
+ description: "Hard limit" |
|
| 3324 |
+ type: "integer" |
|
| 3309 | 3325 |
NetworkAttachmentSpec: |
| 3310 | 3326 |
description: | |
| 3311 | 3327 |
Read-only spec type for non-swarm containers attached to swarm overlay |
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
|
| 6 | 6 |
"github.com/docker/docker/api/types/container" |
| 7 | 7 |
"github.com/docker/docker/api/types/mount" |
| 8 |
+ "github.com/docker/go-units" |
|
| 8 | 9 |
) |
| 9 | 10 |
|
| 10 | 11 |
// DNSConfig specifies DNS related configurations in resolver configuration file (resolv.conf) |
| ... | ... |
@@ -75,4 +76,5 @@ type ContainerSpec struct {
|
| 75 | 75 |
Sysctls map[string]string `json:",omitempty"` |
| 76 | 76 |
CapabilityAdd []string `json:",omitempty"` |
| 77 | 77 |
CapabilityDrop []string `json:",omitempty"` |
| 78 |
+ Ulimits []*units.Ulimit `json:",omitempty"` |
|
| 78 | 79 |
} |
| ... | ... |
@@ -7,6 +7,7 @@ import ( |
| 7 | 7 |
"github.com/docker/docker/api/types/container" |
| 8 | 8 |
mounttypes "github.com/docker/docker/api/types/mount" |
| 9 | 9 |
types "github.com/docker/docker/api/types/swarm" |
| 10 |
+ "github.com/docker/go-units" |
|
| 10 | 11 |
swarmapi "github.com/docker/swarmkit/api" |
| 11 | 12 |
gogotypes "github.com/gogo/protobuf/types" |
| 12 | 13 |
"github.com/pkg/errors" |
| ... | ... |
@@ -39,6 +40,7 @@ func containerSpecFromGRPC(c *swarmapi.ContainerSpec) *types.ContainerSpec {
|
| 39 | 39 |
Sysctls: c.Sysctls, |
| 40 | 40 |
CapabilityAdd: c.CapabilityAdd, |
| 41 | 41 |
CapabilityDrop: c.CapabilityDrop, |
| 42 |
+ Ulimits: ulimitsFromGRPC(c.Ulimits), |
|
| 42 | 43 |
} |
| 43 | 44 |
|
| 44 | 45 |
if c.DNSConfig != nil {
|
| ... | ... |
@@ -267,6 +269,7 @@ func containerToGRPC(c *types.ContainerSpec) (*swarmapi.ContainerSpec, error) {
|
| 267 | 267 |
Sysctls: c.Sysctls, |
| 268 | 268 |
CapabilityAdd: c.CapabilityAdd, |
| 269 | 269 |
CapabilityDrop: c.CapabilityDrop, |
| 270 |
+ Ulimits: ulimitsToGRPC(c.Ulimits), |
|
| 270 | 271 |
} |
| 271 | 272 |
|
| 272 | 273 |
if c.DNSConfig != nil {
|
| ... | ... |
@@ -471,3 +474,31 @@ func isolationToGRPC(i container.Isolation) swarmapi.ContainerSpec_Isolation {
|
| 471 | 471 |
} |
| 472 | 472 |
return swarmapi.ContainerIsolationDefault |
| 473 | 473 |
} |
| 474 |
+ |
|
| 475 |
+func ulimitsFromGRPC(u []*swarmapi.ContainerSpec_Ulimit) []*units.Ulimit {
|
|
| 476 |
+ ulimits := make([]*units.Ulimit, len(u)) |
|
| 477 |
+ |
|
| 478 |
+ for i, ulimit := range u {
|
|
| 479 |
+ ulimits[i] = &units.Ulimit{
|
|
| 480 |
+ Name: ulimit.Name, |
|
| 481 |
+ Soft: ulimit.Soft, |
|
| 482 |
+ Hard: ulimit.Hard, |
|
| 483 |
+ } |
|
| 484 |
+ } |
|
| 485 |
+ |
|
| 486 |
+ return ulimits |
|
| 487 |
+} |
|
| 488 |
+ |
|
| 489 |
+func ulimitsToGRPC(u []*units.Ulimit) []*swarmapi.ContainerSpec_Ulimit {
|
|
| 490 |
+ ulimits := make([]*swarmapi.ContainerSpec_Ulimit, len(u)) |
|
| 491 |
+ |
|
| 492 |
+ for i, ulimit := range u {
|
|
| 493 |
+ ulimits[i] = &swarmapi.ContainerSpec_Ulimit{
|
|
| 494 |
+ Name: ulimit.Name, |
|
| 495 |
+ Soft: ulimit.Soft, |
|
| 496 |
+ Hard: ulimit.Hard, |
|
| 497 |
+ } |
|
| 498 |
+ } |
|
| 499 |
+ |
|
| 500 |
+ return ulimits |
|
| 501 |
+} |
| ... | ... |
@@ -21,6 +21,7 @@ import ( |
| 21 | 21 |
executorpkg "github.com/docker/docker/daemon/cluster/executor" |
| 22 | 22 |
clustertypes "github.com/docker/docker/daemon/cluster/provider" |
| 23 | 23 |
"github.com/docker/go-connections/nat" |
| 24 |
+ "github.com/docker/go-units" |
|
| 24 | 25 |
netconst "github.com/docker/libnetwork/datastore" |
| 25 | 26 |
"github.com/docker/swarmkit/agent/exec" |
| 26 | 27 |
"github.com/docker/swarmkit/api" |
| ... | ... |
@@ -438,6 +439,15 @@ func (c *containerConfig) resources() enginecontainer.Resources {
|
| 438 | 438 |
resources.PidsLimit = &pidsLimit |
| 439 | 439 |
} |
| 440 | 440 |
|
| 441 |
+ resources.Ulimits = make([]*units.Ulimit, len(c.spec().Ulimits)) |
|
| 442 |
+ for i, ulimit := range c.spec().Ulimits {
|
|
| 443 |
+ resources.Ulimits[i] = &units.Ulimit{
|
|
| 444 |
+ Name: ulimit.Name, |
|
| 445 |
+ Soft: ulimit.Soft, |
|
| 446 |
+ Hard: ulimit.Hard, |
|
| 447 |
+ } |
|
| 448 |
+ } |
|
| 449 |
+ |
|
| 441 | 450 |
// If no limits are specified let the engine use its defaults. |
| 442 | 451 |
// |
| 443 | 452 |
// TODO(aluzzardi): We might want to set some limits anyway otherwise |
| ... | ... |
@@ -76,6 +76,10 @@ keywords: "API, Docker, rcli, REST, documentation" |
| 76 | 76 |
single set of stats instead of waiting for two collection cycles to have 2 CPU stats over a 1 second period. |
| 77 | 77 |
* The `KernelMemory` field in `HostConfig.Resources` is now deprecated. |
| 78 | 78 |
* The `KernelMemory` field in `Info` is now deprecated. |
| 79 |
+* `GET /services` now returns `Ulimits` as part of `ContainerSpec`. |
|
| 80 |
+* `GET /services/{id}` now returns `Ulimits` as part of `ContainerSpec`.
|
|
| 81 |
+* `POST /services/create` now accepts `Ulimits` as part of `ContainerSpec`. |
|
| 82 |
+* `POST /services/{id}/update` now accepts `Ulimits` as part of `ContainerSpec`.
|
|
| 79 | 83 |
|
| 80 | 84 |
## v1.40 API changes |
| 81 | 85 |
|