Skip to content

Commit ad96811

Browse files
committed
swarm: Add memory swap support (no stack/compose support)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
1 parent 6ba06b5 commit ad96811

File tree

4 files changed

+62
-6
lines changed

4 files changed

+62
-6
lines changed

cli/command/service/opts.go

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -235,15 +235,17 @@ type resourceOptions struct {
235235
resCPU opts.NanoCPUs
236236
resMemBytes opts.MemBytes
237237
resGenericResources []string
238+
swapBytes opts.MemBytes
239+
memSwappiness int64
238240
}
239241

240-
func (r *resourceOptions) ToResourceRequirements() (*swarm.ResourceRequirements, error) {
242+
func (r *resourceOptions) ToResourceRequirements(flags *pflag.FlagSet) (*swarm.ResourceRequirements, error) {
241243
generic, err := ParseGenericResources(r.resGenericResources)
242244
if err != nil {
243245
return nil, err
244246
}
245247

246-
return &swarm.ResourceRequirements{
248+
resreq := &swarm.ResourceRequirements{
247249
Limits: &swarm.Limit{
248250
NanoCPUs: r.limitCPU.Value(),
249251
MemoryBytes: r.limitMemBytes.Value(),
@@ -254,7 +256,20 @@ func (r *resourceOptions) ToResourceRequirements() (*swarm.ResourceRequirements,
254256
MemoryBytes: r.resMemBytes.Value(),
255257
GenericResources: generic,
256258
},
257-
}, nil
259+
}
260+
261+
// SwapBytes and MemorySwappiness are *int64 (pointers), so we need to have
262+
// a variable we can take a pointer to. Additionally, we need to ensure
263+
// that these values are only set if they are set as options.
264+
if flags.Changed(flagSwapBytes) {
265+
swapBytes := r.swapBytes.Value()
266+
resreq.SwapBytes = &swapBytes
267+
}
268+
if flags.Changed(flagMemSwappiness) {
269+
resreq.MemorySwappiness = &r.memSwappiness
270+
}
271+
272+
return resreq, nil
258273
}
259274

260275
type restartPolicyOptions struct {
@@ -734,7 +749,7 @@ func (options *serviceOptions) ToService(ctx context.Context, apiClient client.N
734749
return networks[i].Target < networks[j].Target
735750
})
736751

737-
resources, err := options.resources.ToResourceRequirements()
752+
resources, err := options.resources.ToResourceRequirements(flags)
738753
if err != nil {
739754
return service, err
740755
}
@@ -889,6 +904,10 @@ func addServiceFlags(flags *pflag.FlagSet, options *serviceOptions, defaultFlagV
889904
flags.Var(&options.resources.resMemBytes, flagReserveMemory, "Reserve Memory")
890905
flags.Int64Var(&options.resources.limitPids, flagLimitPids, 0, "Limit maximum number of processes (default 0 = unlimited)")
891906
flags.SetAnnotation(flagLimitPids, "version", []string{"1.41"})
907+
flags.Var(&options.resources.swapBytes, flagSwapBytes, "Swap Bytes (-1 for unlimited)")
908+
flags.SetAnnotation(flagLimitPids, "version", []string{"1.52"})
909+
flags.Int64Var(&options.resources.memSwappiness, flagMemSwappiness, -1, "Tune memory swappiness (0-100), -1 to reset to default")
910+
flags.SetAnnotation(flagLimitPids, "version", []string{"1.52"})
892911

893912
flags.Var(&options.stopGrace, flagStopGracePeriod, flagDesc(flagStopGracePeriod, "Time to wait before force killing a container (ns|us|ms|s|m|h)"))
894913
flags.Var(&options.replicas, flagReplicas, "Number of tasks")
@@ -1073,6 +1092,8 @@ const (
10731092
flagUlimitAdd = "ulimit-add"
10741093
flagUlimitRemove = "ulimit-rm"
10751094
flagOomScoreAdj = "oom-score-adj"
1095+
flagSwapBytes = "memory-swap"
1096+
flagMemSwappiness = "memory-swappiness"
10761097
)
10771098

10781099
func toNetipAddrSlice(ips []string) []netip.Addr {

cli/command/service/opts_test.go

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,10 @@ func TestResourceOptionsToResourceRequirements(t *testing.T) {
163163
},
164164
}
165165

166+
flags := newCreateCommand(nil).Flags()
167+
166168
for _, opt := range incorrectOptions {
167-
_, err := opt.ToResourceRequirements()
169+
_, err := opt.ToResourceRequirements(flags)
168170
assert.Check(t, is.ErrorContains(err, ""))
169171
}
170172

@@ -178,12 +180,41 @@ func TestResourceOptionsToResourceRequirements(t *testing.T) {
178180
}
179181

180182
for _, opt := range correctOptions {
181-
r, err := opt.ToResourceRequirements()
183+
r, err := opt.ToResourceRequirements(flags)
182184
assert.NilError(t, err)
183185
assert.Check(t, is.Len(r.Reservations.GenericResources, len(opt.resGenericResources)))
184186
}
185187
}
186188

189+
func TestResourceOptionsToResourceRequirementsSwap(t *testing.T) {
190+
// first, check that no flag set means no field set in the return
191+
flags := newCreateCommand(nil).Flags()
192+
193+
// These should be the default values of the field.
194+
swapOptions := resourceOptions{
195+
swapBytes: 0,
196+
memSwappiness: -1,
197+
}
198+
199+
r, err := swapOptions.ToResourceRequirements(flags)
200+
assert.NilError(t, err)
201+
assert.Check(t, is.Nil(r.SwapBytes))
202+
assert.Check(t, is.Nil(r.MemorySwappiness))
203+
204+
// now set the flags and some values
205+
flags.Set(flagSwapBytes, "86000")
206+
flags.Set(flagMemSwappiness, "23")
207+
swapOptions.swapBytes = 86000
208+
swapOptions.memSwappiness = 23
209+
210+
r, err = swapOptions.ToResourceRequirements(flags)
211+
assert.NilError(t, err)
212+
assert.Check(t, r.SwapBytes != nil)
213+
assert.Check(t, is.Equal(*(r.SwapBytes), int64(86000)))
214+
assert.Check(t, r.MemorySwappiness != nil)
215+
assert.Check(t, is.Equal(*(r.MemorySwappiness), int64(23)))
216+
}
217+
187218
func TestToServiceNetwork(t *testing.T) {
188219
nws := []network.Inspect{
189220
{

docs/reference/commandline/service_create.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ Create a new service
4040
| `--log-driver` | `string` | | Logging driver for service |
4141
| `--log-opt` | `list` | | Logging driver options |
4242
| `--max-concurrent` | `uint` | | Number of job tasks to run concurrently (default equal to --replicas) |
43+
| `--memory-swap` | `bytes` | `0` | Swap Bytes (-1 for unlimited) |
44+
| `--memory-swappiness` | `int64` | `-1` | Tune memory swappiness (0-100), -1 to reset to default |
4345
| `--mode` | `string` | `replicated` | Service mode (`replicated`, `global`, `replicated-job`, `global-job`) |
4446
| [`--mount`](#mount) | `mount` | | Attach a filesystem mount to the service |
4547
| `--name` | `string` | | Service name |

docs/reference/commandline/service_update.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ Update a service
5353
| `--log-driver` | `string` | | Logging driver for service |
5454
| `--log-opt` | `list` | | Logging driver options |
5555
| `--max-concurrent` | `uint` | | Number of job tasks to run concurrently (default equal to --replicas) |
56+
| `--memory-swap` | `bytes` | `0` | Swap Bytes (-1 for unlimited) |
57+
| `--memory-swappiness` | `int64` | `-1` | Tune memory swappiness (0-100), -1 to reset to default |
5658
| [`--mount-add`](#mount-add) | `mount` | | Add or update a mount on a service |
5759
| `--mount-rm` | `list` | | Remove a mount by its target path |
5860
| [`--network-add`](#network-add) | `network` | | Add a network |

0 commit comments

Comments
 (0)