-
Notifications
You must be signed in to change notification settings - Fork 5.2k
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
Proposal: kubectl extension #122
Conversation
I have a strong need for this feature. For the service-catalog, there is a need to build macros and other extensions for resources in a not-Kubernetes API server. It would be tremendously useful if there were a way to register these with 'normal' kubectl instead of publishing a wholly different binary. |
We need it for API servers providing new resource types as well. I think that starting really small like executing your binary with all the flags, is the minimal useful thing we could provide and it doesn't preclude doing something fancy with proxies later. |
Proposal | ||
-------- | ||
|
||
Define a system for `kubectl` that allows new subcommands and subcommand trees to be added by placing an executable in a specific |
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 prefer to support both containerized command and in-directory command. It is more extensible to for kubectl to respond to specific handler definitions (e.g. similar to how clink works)
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.
Yes - IMHO the primary should be on containerized extensions.
We have a use-case where we are shipping TPRs and require custom commands for them. Thus shipping kubectl extensions in containers (or DaemonSets then) would be very convenient. And would fit much bette rinto the broader story.
Just my 2ct
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 love containers as much as anyone but I feel that plugins ala git are much simpler thing to tackle on all of the platforms kubectl supports today.
I love this feature to extend kubectl to search out tree subcommands and support certain volume features. |
cc @kubernetes/sig-cli |
So far from the discussions in the original PR, I'm seeing 3 potential kinds of extensions:
For binary extensions, I believe there is great value in allowing contributors to write plugins in other languages (not only Go). Plugins could be other compiled languages, Ruby scripts, bash scripts, etc; if we define an integration point not specific to Go (e.g. RPC instead of gorpc, or even REST with YAML/JSON, etc). Interesting related project: https://npf.io/2015/05/pie/. |
That said, I wrote a PoC for item 1 (binary extensions). There are potential security issues like mentioned, but it's interesting to see what can be done. The architecture is pretty similar to Helm plugins. Give
@pmorie can you take a look at the PoC above? How good/bad that addresses your need? |
I like this idea; it would be great to add some concrete examples to the doc. One use case I think is particularly important is to allow the creator of a Third Party Resource to control what "get" and "describe" show for their resource (e.g. what data, how it is formatted in the screen output, etc.). |
I think it would be awesome for API servers to be able to indicate
formatted get and describe output of any resource - would get you most of
the way there on new API servers, you would just need to implement macros
as extensions. Might not be what you would always want to do, but would be
handy for prototyping and getting new things in front of people with lower
complexity.
…On Sat, Dec 3, 2016 at 7:19 PM David Oppenheimer ***@***.***> wrote:
I like this idea; it would be great to add some concrete examples to the
doc.
One use case I think is particularly important is to allow the creator of
a Third Party Resource to control what "get" and "describe" show for their
resource (e.g. what data, how it is formatted in the screen output, etc.).
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#122 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAWXmN74v1CSGhvkBibPlxtnFKwjoIE8ks5rEgcVgaJpZM4LBtnz>
.
|
yes, there is just another proposal describe this. |
behavior (such as complex inference of commands) may not be supported in order to reduce the complexity of the lookup. | ||
|
||
Kubectl would lazily include the appropriate commands in preference to the internal command structure if detected (a user asking for | ||
`kubectl a b c` would *first* check for `kubectl-a-b-c`, `kubectl-a-b`, or `kubectl-a` before loading the internal command). |
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 this the solution to address the usecase of providing my own getter (or other existing command) for TPR, iow. if I want to have kubectl get mynewtpr/foo
I need to define kubectl-get-mynewtpr
?
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.
get/edit/delete by resource/name, create/update from file should work without custom extensions
if you want commands like kubectl create mytype some-name --custom-option-1=something
, you would need custom extensions
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 want to start with a limited number of places to hook in custom extensions (like kubectl create x
, kubectl set x
). We also shouldn't differentiate between thirdpartyresources and other types unknown to kubectl (they should behave the same externally from the API)
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.
The lookup scheme from @soltysh above looks okay to me. The only drawback is that the extensions needs to have the boilerplate to do nice output.
It would work in my case wher I'd like to output some useful informations for a TPR.
But that is a problem which can be addressed later by making the default kubectl
output functionality reusable.
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 kubectl describe <resource-type>
another case targeted here?
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 kubectl describe another case targeted here?
I don't think so... I think that was supposed to be addressed by enabling returning descriptive info about a resource from the server (#123)
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.
For Helm, we backed off this approach because it got very confusing to the user. It was nearly impossible to tell whether a command was executing a plugin or not.
Envision this from the user's perspective. User A has command kubectl foo bar baz
. User B tries to execute the same command, and it doesn't work. User A doesn't know which of their many installed plugins provides this behavior. How do they resolve the situation?
Our solution was to only expose a top level subcommand to plugins. This leads to a flat top-level namespace, but also makes it very clear which plugin is being invoked.
As a side benefit, it made the help system much simpler.
|
||
All kubectl command extensions MUST: | ||
|
||
* Support the `-h` and `--help` flags to display a help page |
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.
We could probably make extensions authors live's easier by refactoring kubectl and providing pieces of it as libraries.
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.
We made this same requirement, and also used the plugin metadata file to load help text into helm
at runtime. The consistency is a HUGE boon to users. 👍
We also required that certain flags (like --debug
) follow the same conventions as Helm.
Implementation-wise, what we actually did was parse these flags in the top-level binary, swallow the flags, and then converted them into environment variables. The benefit here (aside from being closer to Cobra's intent) is that the top-level CLI enforces consistency and the actual toggling of flags on and off is an implementation detail:
|
||
All kubectl command extensions SHOULD: | ||
|
||
* Follow the display and output conventions of normal kubectl commands. |
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.
There will probably be some details to work out around how extension versioning is handled:
- different versions of the extensions themselves (are these versioned independently from k8s versions?)
- extension kubernetes client (e.g. golang client) version vs server version skew
- extension kubernetes client version vs kubectl version skew
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.
extensions version should be independently from k8s version.
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.
But may have a dependency on the k8s version? e.g. "requires 1.7"?
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 think support defining compatible k8s version is must have. Like >1.4.0 & <1.5.0
(or other syntax).
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 definitely necessary, extension plugin should be able to define k8s version requirement, and itself version should be independent.
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.
@adohe indeed.
location on disk, like Git. Allow third parties to extend kubectl by placing their extensions in that directory. Ensure that help | ||
and other logic correctly includes those extensions. | ||
|
||
A kubectl command extension would be an executable located in `EXEC_PATH` (an arbitrary directory to be defined that follows similar |
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.
Non-goal: Provide extensions as new flags to non-extension commands. E.g. kubectl get pod -o <my-own-extension-format>
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.
Another non-goal that is often requested: new auth mechanisms
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.
Hrm - this one comes up a lot, simply because we have no way other than "recompile the world". Are you just skeptical of how we can solve this cleanly?
|
||
A kubectl command extension would be an executable located in `EXEC_PATH` (an arbitrary directory to be defined that follows similar | ||
conventions in Linux) with a name pattern like `kubectl-COMMAND[-SUBCOMMAND[...]]` with one or many sub parts. The presence of | ||
a command extension overrides any built in command. |
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.
Speaking for Helm, we started with a similar naming convention and later backed off. While it worked for Git, we felt like placing requirements on the naming convention of the plugin executable was limiting to plugin authors. It also required lots of name munging in code.
So we went from that requirement to having a single source location in $HELM_HOME (analogous to ~/.kube
where plugin metadata could go. The metadata included information on the name of the actual binary.
That model got us the additional benefit of being able to read in the metadata file in order to generate top-level help text. In that way, helm -h
could read the Usage:
field in the plugin metadata for each plugin, and then display plugin help text alongside built-in help text.
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.
The presence of a command extension overrides any built in command.
This seems like asking for trouble.
- Letting plugins override core commands is very fragmenting (examples wouldn't work consistently)
- Multiple plugins could target overriding the same core command
- I would expect commands like
kubectl get
andkubectl describe
to be high-value targets for plugins trying to add in pretty-printing for their own types, and those are extremely difficult to wrap accurately - Even if plugins are trying to behave well and pick names that don't conflict, future kubectl additions could be rendered inert by a plugin that had claimed the name for itself
- It makes support really tough ("run
kubectl get foo
. wait, what plugins do you have installed?")
I like this approach. Based on Helm's implementation, we have seen people build plugins ranging from simple (more like Git aliases) to highly complex (multi-subcommand Python or Go programs). And I think If there are any questions about the pros and cons of Helm's approach, what we've learned, or how we did particular things, I'm happy to answer. |
WDYT of merging this document as-is, and updating it to reflect changes to design as needed? |
|
@pwittrock works for me. |
@pwittrock works for me too. However, along with @liggitt, i wouldn't mind seeing short verbiage about command name collisions, e.g.
But also fine with it being added later. Plugins are well plowed ground (git, helm etc.) and see no reason to do anything more exotic here. |
Automatic merge from submit-queue kubectl binary plugins **What this PR does / why we need it**: Introduces the ability to extend `kubectl` by adding third-party plugins that will be exposed through `kubectl`. Plugins are executable commands written in any language. To be included as a plugin, a binary or script file has to 1. be located under one of the supported plugin path locations: 1.1 `~/.kubectl/plugins` dir 1.2. one or more directory set in the `KUBECTL_PLUGINS_PATH` env var 1.3. the `kubectl/plugins` dir under one or more directory set in the `XDG_DATA_DIRS` env var, which defaults to `/usr/local/share:/usr/share` 2. in any of the plugin path above, have a subfolder with the plugin file(s) 3. in the subfolder, contain at least a `plugin.yaml` file that describes the plugin Example: ``` $ cat ~/.kube/plugins/myplugin/plugin.yaml name: "myplugin" shortDesc: "My plugin's short description" command: "echo Hello plugins!" $ kubectl myplugin Hello plugins! ``` ~~In case the plugin declares `tunnel: true`, the plugin engine will pass the `KUBECTL_PLUGIN_API_HOST` env var when calling the plugin binary. Plugins can then access the Kube REST API in "http://$KUBECTL_PLUGIN_API_HOST/api" using the same context currently in use by `kubectl`.~~ Test plugins are provided in `pkg/kubectl/plugins/examples`. Just copy (or symlink) the files to `~/.kube/plugins` to test. **Which issue this PR fixes**: Related to the discussions in the proposal document: #30086 and kubernetes/community#122. **Release note**: ```release-note Introduces the ability to extend kubectl by adding third-party plugins. Developer preview, please refer to the documentation for instructions about how to use it. ```
Proposal: kubectl extension
From: kubernetes/kubernetes#30086