New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Plugins on swarm #33575
Plugins on swarm #33575
Conversation
8322070
to
977fcc8
Compare
9ab7953
to
97dec15
Compare
Ok, I think this is ready for design review, and code is in a pretty good state. ping @aaronlehmann |
efcd344
to
9b02932
Compare
Sorry for the delay. +1 for pb encoding. In the "original" design, that was the intention we just left it out of the Generic Runtime PR as we didn't have anything to use yet. |
Yes, I think protobuf would be better. |
api/types/swarm/task.go
Outdated
@@ -66,7 +66,8 @@ type TaskSpec struct { | |||
// parameters have been changed. | |||
ForceUpdate uint64 | |||
|
|||
Runtime RuntimeType `json:",omitempty"` | |||
Runtime RuntimeType `json:",omitempty"` | |||
PluginSpec *PluginSpec `json:",omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest putting this next to ContainerSpec
in the struct definition and adding a comment that they are mutually exclusive. We should probably change ContainerSpec
to be a pointer (and make sure no code assumes it exists).
logrus.WithFields(logrus.Fields{ | ||
"controller": "plugin", | ||
}).Debug("Prepare") | ||
|
||
// TODO(@cpuguy83): support digest pinning |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like tag+digest is already supported. What else needs to be done?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we pin this before sending off to swarm?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pinning happens on the CLI side starting with API 1.30.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(See docker/cli#30)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok makes sense to do that there.
} | ||
|
||
if canonical, ok := remote.(canonicalWithTag); ok { | ||
remote, err = reference.WithDigest(reference.TrimNamed(remote), canonical.Digest()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be possible to pass a reference with both a tag and a digest to the pull code. This wasn't working properly earlier, but it was fixed recently.
Not sure if there are any plugin-specific issues with doing this, but ideally there shouldn't be.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So you are saying to drop the TrimNamed
bit?
if err != context.Canceled { | ||
t.Fatal(err) | ||
} | ||
case <-time.After(500 * time.Millisecond): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is 500 ms enough? I like to be very conservative with timeouts in test so that loaded machines don't cause spurious failures.
daemon/cluster/convert/service.go
Outdated
switch g.Kind { | ||
case string(types.RuntimePlugin): | ||
var p types.GenericPluginPayload | ||
json.Unmarshal(g.Payload.Value, &p) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we'll change this to gRPC anyway, but the error needs to be checked.
@@ -50,14 +50,16 @@ func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Serv | |||
return nil, err | |||
} | |||
|
|||
if len(options.Filters.Get("runtime")) == 0 { | |||
// Default to using the container runtime filter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wondering if we should do this in the CLI instead of the API. No strong preference though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer the CLI, but I didn't want to make a breaking change to the API here.
d2 := s.AddDaemon(c, true, true) | ||
d3 := s.AddDaemon(c, true, false) | ||
|
||
time.Sleep(1 * time.Second) // make sure all daemons are ready to accept |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this sleep is necessary. I don't recall any other tests that create services doing this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I copied this from the test above it. I can remove.
s.Spec.TaskTemplate.Runtime = "plugin" | ||
s.Spec.TaskTemplate.PluginSpec = &swarm.PluginSpec{ | ||
Name: "test", | ||
Remote: "cpuguy83/docker-logdriver-test", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm hoping we can avoid adding new dependencies on Docker Hub in tests; see #30626
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I keep putting this off... I'll work on something for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, added a plugin builder + some registry integration. Check it out in integration-cli/fixtures/plugin.
plugin/events.go
Outdated
"github.com/docker/docker/api/types" | ||
) | ||
|
||
// Event is emitted for actions performed on the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I remember this truncated comment from swarmkit :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Such a coincidence :)
This commit extends SwarmKit secret management with pluggable secret backends support, using the current cluster configuration to understand if secrets are being stored locally, or need to be retrieved from a remote secret store. The solution will use the existing docker plugin framework. The approach is to add a new `driver` parameter to existing secrets, which defines whether the values are loaded from SwarmKit or from one of the secret plugins. The loading of secrets is done using the standard docker plugin infrastructure, which is already accessible in swarmkit and used in other flows (e.g., networking) Remarks: * I've added support to mock the plugin subsystem in controlapi server, I preferred this approach over loading the full plugin subsystem. Work still needed in this CR: - [ ] More unit tests (pending initial iteration) - [ ] Customized error handling Work still needed to complete this feature: - [ ] Inject secrets as part of plugin initialization - [ ] CLI support in docker References: moby/moby#33575 Signed-off-by: liron <liron@twistlock.com>
This commit extends SwarmKit secret management with pluggable secret backends support. The solution uses the existing docker plugin framework for loading plugins and the existing SwarmKit data backend for storing them. The approach is to add a new `driver` parameter to existing secrets, which defines whether the values are taken as is or fetched from one of the secret plugins. The loading of secrets is done using the standard docker plugin infrastructure, which is already accessible in SwarmKit and used in other flows (e.g., networking). The fetched values are are stored as regular SwarmKit secrets. Remarks: * I've added support for mocking the plugin subsystem when settings up the controlapi server. I preferred this approach over loading the full plugin subsystem in UT. Work still needed in this CR: - [ ] More unit tests (pending initial iteration) - [ ] Customized error handling (e.g., customize error string for Not Found) Work still needed to complete this feature: - [ ] Inject secrets as part of plugin initialization - [ ] CLI support in docker - [ ] Docs - [ ] Support scheduling plugins in swarm moby/moby#33575 Signed-off-by: liron <liron@twistlock.com>
This commit extends SwarmKit secret management with pluggable secret backends support. The solution uses the existing docker plugin framework for loading plugins and the existing SwarmKit data backend for storing them. The approach is to add a new `driver` parameter to existing secrets, which defines whether the values are taken as is or fetched from one of the secret plugins. The loading of secrets is done using the standard docker plugin infrastructure, which is already accessible in SwarmKit and used in other flows (e.g., networking). The fetched values are are stored as regular SwarmKit secrets. Remarks: * I've added support for mocking the plugin subsystem when settings up the controlapi server. I preferred this approach over loading the full plugin subsystem in UT. Work still needed in this CR: - [ ] More unit tests (pending initial iteration) - [ ] Customized error handling (e.g., customize error string for Not Found) Work still needed to complete this feature: - [ ] Inject secrets as part of plugin initialization - [ ] CLI support in docker - [ ] Docs - [ ] Support scheduling plugins in swarm moby/moby#33575 Signed-off-by: liron <liron@twistlock.com>
This commit extends SwarmKit secret management with pluggable secret backends support. The solution uses the existing docker plugin framework for loading plugins and the existing SwarmKit data backend for storing them. The approach is to add a new `driver` parameter to existing secrets, which defines whether the values are taken as is or fetched from one of the secret plugins. The loading of secrets is done using the standard docker plugin infrastructure, which is already accessible in SwarmKit and used in other flows (e.g., networking). The fetched values are are stored as regular SwarmKit secrets. Remarks: * I've added support for mocking the plugin subsystem when settings up the controlapi server. I preferred this approach over loading the full plugin subsystem in UT. Work still needed in this CR: - [ ] More unit tests (pending initial iteration) - [ ] Customized error handling (e.g., customize error string for Not Found) Work still needed to complete this feature: - [ ] Inject secrets as part of plugin initialization - [ ] CLI support in docker - [ ] Docs - [ ] Support scheduling plugins in swarm moby/moby#33575 Signed-off-by: liron <liron@twistlock.com>
f4a5e00
to
72c3bcf
Compare
Rebased, fixed imports, added client side validation for service spec to create/update. |
All tests passed after windowsRS1 rerun. Merging. |
💥 thanks @cpuguy83 for putting this together! |
Just step 1, still need:
|
@cpuguy83 do we have |
This commit extends SwarmKit secret management with pluggable secret backends support. The solution uses the existing docker plugin framework for loading plugins and the existing SwarmKit data backend for storing them. The approach is to add a new `driver` parameter to existing secrets, which defines whether the values are taken as is or fetched from one of the secret plugins. The loading of secrets is done using the standard docker plugin infrastructure, which is already accessible in SwarmKit and used in other flows (e.g., networking). The fetched values are evaluated before assigning them to worker nodes, so the payload is not stored in the raft store. Remarks: * I've added support for mocking the plugin subsystem when settings up the controlapi server. I preferred this approach over loading the full plugin subsystem in UT. Work still needed in this CR: - [ ] More unit tests (pending initial iteration) - [ ] Customized error handling (e.g., customize error string for Not Found) Work still needed to complete this feature: - [ ] Inject secrets as part of plugin initialization - [ ] CLI support in docker - [ ] Docs - [ ] Support scheduling plugins in swarm moby/moby#33575 Signed-off-by: liron <liron@twistlock.com>
This commit extends SwarmKit secret management with pluggable secret backends support. The solution uses the existing docker plugin framework for loading plugins and the existing SwarmKit data backend for storing them. The approach is to add a new `driver` parameter to existing secrets, which defines whether the values are taken as is or fetched from one of the secret plugins. The loading of secrets is done using the standard docker plugin infrastructure, which is already accessible in SwarmKit and used in other flows (e.g., networking). The fetched values are evaluated before assigning them to worker nodes, so the payload is not stored in the raft store. Remarks: * I've added support for mocking the plugin subsystem when settings up the controlapi server. I preferred this approach over loading the full plugin subsystem in UT. Work still needed in this CR: - [ ] More unit tests (pending initial iteration) - [ ] Customized error handling (e.g., customize error string for Not Found) Work still needed to complete this feature: - [ ] Inject secrets as part of plugin initialization - [ ] CLI support in docker - [ ] Docs - [ ] Support scheduling plugins in swarm moby/moby#33575 Signed-off-by: liron <liron@twistlock.com>
This commit extends SwarmKit secret management with pluggable secret backends support. The solution uses the existing docker plugin framework for loading plugins and the existing SwarmKit data backend for storing them. The approach is to add a new `driver` parameter to existing secrets, which defines whether the values are taken as is or fetched from one of the secret plugins. The loading of secrets is done using the standard docker plugin infrastructure, which is already accessible in SwarmKit and used in other flows (e.g., networking). The fetched values are evaluated before assigning them to worker nodes, so the payload is not stored in the raft store. Remarks: * I've added support for mocking the plugin subsystem when settings up the controlapi server. I preferred this approach over loading the full plugin subsystem in UT. Work still needed in this CR: - [ ] More unit tests (pending initial iteration) - [ ] Customized error handling (e.g., customize error string for Not Found) Work still needed to complete this feature: - [ ] Inject secrets as part of plugin initialization - [ ] CLI support in docker - [ ] Docs - [ ] Support scheduling plugins in swarm moby/moby#33575 Signed-off-by: liron <liron@twistlock.com>
} | ||
if len(imgPlatforms) > 0 { | ||
service.TaskTemplate.Placement.Platforms = imgPlatforms | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This (and the other changes to this file) seem like the wrong place to handle these concerns. Every other function in this package is only concerned with translating a golang struct into an HTTP request, performing the request, and translating the response into a goland struct.
With this change we've introduced a bunch of application logic and validation that does not belong here.
I think this needs to be extracted to some other package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @thaJeztah re docker/cli#386
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is all pre-existing, just re-organized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, my mistake, looks like it was first introduced and modified in a few PRs starting around #33239
} | ||
|
||
if err := validateServiceSpec(service); err != nil { | ||
return types.ServiceCreateResponse{}, err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same problem here
Support deploying plugins via swarm services
Modifies the services API to support deploying plugins (previously only
supported containers).
This makes use of some of the existing work around generic service
runtimes.
With this change you can
curl -X POST myDocker:2375/services/create
with aPluginSpec
defined in theTaskTemplate
.The plugin defined by in the
PluginSpec
will be deployed similar to a"global mode" service.
Work still needed:
The format of the plugin request that is sent to swarm is currently just a json encoded object specified in
api/types/swarm
... wondering if it would be better to change this to protobuf.Ping @ehazlett @tiborvass
What this does not tackle: