Skip to content

Add support for memory swap settings for services#51114

Merged
vvoland merged 1 commit intomoby:masterfrom
dperny:memory_flags_for_swarm
Oct 24, 2025
Merged

Add support for memory swap settings for services#51114
vvoland merged 1 commit intomoby:masterfrom
dperny:memory_flags_for_swarm

Conversation

@dperny
Copy link
Contributor

@dperny dperny commented Oct 6, 2025

- What I did

Updated #37872 to the latest master branch.

- How I did it

  • Changed API version of the relevant settings to v1.52
  • Update various segments to deal with bit rot

- How to verify it

Comes with integration tests!

- Human readable description for the release notes

- Add support for memory swappiness in Swarm services.
  * `GET /services` now returns `SwapBytes` and `MemorySwappiness` fields as part of the `Resource` requirements.
  * `GET /services/{id}` now returns `SwapBytes` and `MemorySwappiness` fields as part of the `Resource` requirements.
  * `POST /services/create` now accepts `SwapBytes` and `MemorySwappiness` fields as part of the `Resource` requirements.
  * `POST /services/{id}/update` now accepts `SwapBytes` and `MemorySwappiness` fields as part of the `Resource` requirements.
  * `GET /tasks` now returns `SwapBytes` and `MemorySwappiness` fields as part of the `Resource` requirements.
  * `GET /tasks/{id}` now returns `SwapBytes` and `MemorySwappiness` fields as part of the `Resource` requirements.

@dperny
Copy link
Contributor Author

dperny commented Oct 6, 2025

Throwing this up as a draft for right now because I'm still dealing with the bit rot a bit.

@dperny dperny force-pushed the memory_flags_for_swarm branch 2 times, most recently from f0b5ae0 to 71fcf94 Compare October 7, 2025 17:04
@corhere corhere added area/api API kind/feature Functionality or other elements that the project doesn't currently have. Features are new and shiny impact/api impact/changelog area/swarm labels Oct 7, 2025
@dperny
Copy link
Contributor Author

dperny commented Oct 8, 2025

Removed the section of integration tests which exec'd into the container to check that memory swappiness was actually set. If memory swappiness is set on the container config, we should trust that it is set on the container, and the test of that is a different test entirely.

@dperny dperny force-pushed the memory_flags_for_swarm branch 10 times, most recently from 9ed391c to d71c18d Compare October 9, 2025 17:17
@dperny
Copy link
Contributor Author

dperny commented Oct 9, 2025

This test passes locally on my machine, but fails in CI. I'm not sure why.

@dperny dperny force-pushed the memory_flags_for_swarm branch from d71c18d to e2158c7 Compare October 9, 2025 18:12
@corhere corhere added this to the 29.0.0 milestone Oct 9, 2025
if service.TaskTemplate.Resources != nil {
if service.TaskTemplate.Resources.SwapBytes != nil {
// Setting services' swap size wasn't supported before
// API version 1.40
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// API version 1.40
// API version 1.52

@dperny dperny force-pushed the memory_flags_for_swarm branch 3 times, most recently from e33ae68 to cba4404 Compare October 13, 2025 15:10
@thompson-shaun thompson-shaun moved this from New to Complete in 🔦 Maintainer spotlight Oct 16, 2025
@thompson-shaun thompson-shaun added the release-blocker PRs we want to block a release on label Oct 16, 2025
Copy link
Contributor

@austinvazquez austinvazquez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a minor comment to touchup API v1.52 swagger as well.

Comment on lines +4339 to +4340
type: "integer"
format: "int64"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably should add that the minimum is -1, and add nullable and omit empty;

Suggested change
type: "integer"
format: "int64"
type: "integer"
format: "int64"
minimum: -1
x-nullable: true
x-omitempty: true

❓ ❓ ❓ do we need pointers though? Given that we have explicit -1 means "unset previous", would that already give enough information to distinguish "don't set" if the value is 0? (int-pointers can be finicky to deal with)

If a non-pointer value would work for us, we could change it, and remove the x-nullable;

Suggested change
type: "integer"
format: "int64"
type: "integer"
format: "int64"
minimum: -1
x-omitempty: true

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, -1 isn't "set default" it's "set unlimited". The null pointer is "set-default".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right, so

  • -1 means unlimited
  • nil means "default" (memory x 2 total)
  • 0 means disable (no swap)
  • 1 means 1 byte (or memory + 1 byte - I never know 😂) - 1 probably not an acceptable (or not a "sensible") value, but that's a separate topic 😂

Comment on lines 142 to 146
// Amount of swap in bytes - can only be used together with a memory limit
// -1 means unlimited
// a null pointer keeps the default behaviour of granting twice the memory
// amount in swap
SwapBytes *int64
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Amount of swap in bytes - can only be used together with a memory limit
// -1 means unlimited
// a null pointer keeps the default behaviour of granting twice the memory
// amount in swap
SwapBytes *int64
// Amount of swap in bytes - can only be used together with a memory limit
// -1 means unlimited. A null pointer keeps the default behaviour of granting
// twice the memory amount in swap.
SwapBytes *int64 `json:"SwapBytes,omitzero"`

Or (see my other comment)

Suggested change
// Amount of swap in bytes - can only be used together with a memory limit
// -1 means unlimited
// a null pointer keeps the default behaviour of granting twice the memory
// amount in swap
SwapBytes *int64
// Amount of swap in bytes - can only be used together with a memory limit
// -1 means unlimited. A zero value keeps the default behaviour of granting
// twice the memory amount in swap.
SwapBytes int64 `json:"SwapBytes,omitzero"`

Comment on lines +4347 to +4348
type: "integer"
format: "int64"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
type: "integer"
format: "int64"
format: "int64"
minimum: -1
maximum: 100
x-nullable: true
x-omitempty: true

// Tune container memory swappiness (0 to 100) - if not specified, defaults
// to the container OS's default - generally 60, or the value predefined in
// the image; set to -1 to unset a previously set value
MemorySwappiness *int64
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
MemorySwappiness *int64
MemorySwappiness *int64 `json:"MemorySwappiness,omitzero"`

Or (if we don't need a pointer)

Suggested change
MemorySwappiness *int64
MemorySwappiness int64 `json:"MemorySwappiness,omitzero"`

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOL, it could even be an int8, but from a quick look; looks like Swagger only knows about int32 and int64, so probably not worth changing?

return resources
}

func int64PointerFromGRPC(v *gogotypes.Int64Value) *int64 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated to this PR, but wondering what our chances are to move away from gogo-protobuf; would it be possible?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be possible. It would not be pleasant.

Comment on lines +535 to +537
} else if swapBytes >= 0 {
// resources.MemorySwap is actually the sum of the memory + the swap
resources.MemorySwap = resources.Memory + swapBytes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I guess this was the problem, so 0 is a valid value for this one? :sadpanda:

(if there's still a way to handle this without pointers, I'm still all ears though!)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

☝️ I guess an explicit SwapEnable / SwapDisable could be an option for that, but not sure if we did elsewhere.

@dperny dperny force-pushed the memory_flags_for_swarm branch from cba4404 to c2e008c Compare October 17, 2025 14:59
@dperny
Copy link
Contributor Author

dperny commented Oct 17, 2025

Updated with requested changes to swagger.yaml, v1.52.yaml, and the json annotations.

@dperny dperny force-pushed the memory_flags_for_swarm branch from c2e008c to d64d445 Compare October 17, 2025 15:07
@dperny
Copy link
Contributor Author

dperny commented Oct 17, 2025

Solved the conflict in CHANGELOG.md

@dperny dperny force-pushed the memory_flags_for_swarm branch from d64d445 to 544f200 Compare October 17, 2025 15:14
Comment on lines +81 to +86
if versions.LessThan(cliVersion, "1.52") {
if service.TaskTemplate.Resources != nil {
service.TaskTemplate.Resources.SwapBytes = nil
service.TaskTemplate.Resources.MemorySwappiness = nil
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated, but I wonder if we ever described / documented the behavior when using an older client to update a service;

  • create service with (say) a v29 client, and set swap options
  • update service with (say) a v25 client
  • 💥 swap options are gone

Don't know what a good solution is for that (other than versioning the spec with some schema version and returning warnings if features are set that are not supported in the API version)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the case with any of the settings gated behind the API version.

@thaJeztah
Copy link
Member

OHMAN; before I forget and blame myself; I see there was a pending thing on the other PR; #37872 (comment)

  • swap should go into the Limits struct
  • and that in turns mean that Limits and Reservations are now going to be two separate structs
    And all the changes that this entails.

And there was a related PR;

But I honestly forgot the details (it's been a while)

With integration tests

Relevant Swarmkit PR: moby/swarmkit#2816
(updated the vendored version of Swarkit to that)

Signed-off-by: Jean Rouge <[email protected]>

Updated for latest master, fixed bitrot.

Signed-off-by: Drew Erny <[email protected]>
@dperny dperny force-pushed the memory_flags_for_swarm branch from 544f200 to 3a90dd8 Compare October 20, 2025 15:34
@dperny
Copy link
Contributor Author

dperny commented Oct 20, 2025

I think it's not worthwhile to chase down the path proposed in the old PR -- the gains in cleanliness are outweighed by the increased scope of change.

Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@vvoland vvoland merged commit ea59a8d into moby:master Oct 24, 2025
247 of 250 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/api API area/daemon Core Engine area/dependencies area/docs area/swarm impact/api impact/changelog kind/feature Functionality or other elements that the project doesn't currently have. Features are new and shiny module/api release-blocker PRs we want to block a release on status/4-merge

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Limiting SWAP usage in Swarm Mode?

8 participants