Reword “Extend kubectl with plugins” (#17005)

* Tweak kubectl plugins page

- drop text about kubectl plugin beta status etc
- fix output formatted as shell
- address the reader as “you”
- other tweaks

* Update links & details for Krew

* Update kubectl-plugins.md
This commit is contained in:
Tim Bannister
2019-11-26 06:23:10 +00:00
committed by Kubernetes Prow Robot
parent 8d15eaa3b6
commit 1a45e5cc4d
@@ -9,8 +9,6 @@ content_template: templates/task
{{% capture overview %}} {{% capture overview %}}
{{< feature-state state="stable" >}}
This guide demonstrates how to install and write extensions for [kubectl](/docs/reference/kubectl/kubectl/). By thinking of core `kubectl` commands as essential building blocks for interacting with a Kubernetes cluster, a cluster administrator can think This guide demonstrates how to install and write extensions for [kubectl](/docs/reference/kubectl/kubectl/). By thinking of core `kubectl` commands as essential building blocks for interacting with a Kubernetes cluster, a cluster administrator can think
of plugins as a means of utilizing these building blocks to create more complex behavior. Plugins extend `kubectl` with new sub-commands, allowing for new and custom features not included in the main distribution of `kubectl`. of plugins as a means of utilizing these building blocks to create more complex behavior. Plugins extend `kubectl` with new sub-commands, allowing for new and custom features not included in the main distribution of `kubectl`.
@@ -20,55 +18,54 @@ of plugins as a means of utilizing these building blocks to create more complex
You need to have a working `kubectl` binary installed. You need to have a working `kubectl` binary installed.
{{< note >}}
Plugins were officially introduced as an alpha feature in the v1.8.0 release. They have been re-worked in the v1.12.0 release to support a wider range of use-cases. So, while some parts of the plugins feature were already available in previous versions, a `kubectl` version of 1.12.0 or later is recommended if you are following these docs.
{{< /note >}}
{{% /capture %}} {{% /capture %}}
{{% capture steps %}} {{% capture steps %}}
## Installing kubectl plugins ## Installing kubectl plugins
A plugin is nothing more than a standalone executable file, whose name begins with `kubectl-`. To install a plugin, simply move its executable file to anywhere on your PATH. A plugin is nothing more than a standalone executable file, whose name begins with `kubectl-`. To install a plugin, simply move its executable file to anywhere on your `PATH`.
You can also discover and install kubectl plugins available in the open source You can also discover and install kubectl plugins available in the open source
using [Krew](https://sigs.k8s.io/krew). Krew is a plugin manager maintained by using [Krew](https://krew.dev/). Krew is a plugin manager maintained by
the Kubernetes SIG CLI community. the Kubernetes SIG CLI community.
{{< caution >}} {{< caution >}}
Kubectl plugins installed via the Krew [centralized Kubectl plugins available via the Krew [plugin index](https://index.krew.dev/)
index](https://github.com/kubernetes-sigs/krew-index) are not audited for are not audited for security. You should install and run third-party plugins at your
security. You should install and run third-party plugins at your own risk, since own risk, since they are arbitrary programs running on your machine.
they are arbitrary programs running on your machine. {{< /caution >}}
{{< /note >}}
### Discovering plugins ### Discovering plugins
`kubectl` provides a command `kubectl plugin list` that searches your PATH for valid plugin executables. `kubectl` provides a command `kubectl plugin list` that searches your `PATH` for valid plugin executables.
Executing this command causes a traversal of all files in your PATH. Any files that are executable, and begin with `kubectl-` will show up *in the order in which they are present in your PATH* in this command's output. Executing this command causes a traversal of all files in your `PATH`. Any files that are executable, and begin with `kubectl-` will show up *in the order in which they are present in your `PATH`* in this command's output.
A warning will be included for any files beginning with `kubectl-` that are *not* executable. A warning will be included for any files beginning with `kubectl-` that are *not* executable.
A warning will also be included for any valid plugin files that overlap each other's name. A warning will also be included for any valid plugin files that overlap each other's name.
You can use [Krew](https://sigs.k8s.io/krew) to discover and install `kubectl` You can use [Krew](https://krew.dev/) to discover and install `kubectl`
plugins from a community-curated plugins from a community-curated
[plugin index](https://github.com/kubernetes-sigs/krew-index). [plugin index](https://index.krew.dev/).
#### Limitations #### Limitations
It is currently not possible to create plugins that overwrite existing `kubectl` commands. For example, creating a plugin `kubectl-version` will cause that plugin to never be executed, as the existing `kubectl version` command will always take precedence over it. Due to this limitation, it is also *not* possible to use plugins to add new subcommands to existing `kubectl` commands. For example, adding a subcommand `kubectl create foo` by naming your plugin `kubectl-create-foo` will cause that plugin to be ignored. Warnings will appear under the output of `kubectl plugin list` for any valid plugins that attempt to do this. It is currently not possible to create plugins that overwrite existing `kubectl` commands. For example, creating a plugin `kubectl-version` will cause that plugin to never be executed, as the existing `kubectl version` command will always take precedence over it. Due to this limitation, it is also *not* possible to use plugins to add new subcommands to existing `kubectl` commands. For example, adding a subcommand `kubectl create foo` by naming your plugin `kubectl-create-foo` will cause that plugin to be ignored.
`kubectl plugin list` shows warnings for any valid plugins that attempt to do this.
## Writing kubectl plugins ## Writing kubectl plugins
You can write a plugin in any programming language or script that allows you to write command-line commands. You can write a plugin in any programming language or script that allows you to write command-line commands.
There is no plugin installation or pre-loading required. Plugin executables receive the inherited environment from the `kubectl` binary. There is no plugin installation or pre-loading required. Plugin executables receive
A plugin determines which command path it wishes to implement based on its name. For example, a plugin wanting to provide a new command the inherited environment from the `kubectl` binary.
`kubectl foo`, would simply be named `kubectl-foo`, and live somewhere in the user's PATH. A plugin determines which command path it wishes to implement based on its name. For
example, a plugin wanting to provide a new command `kubectl foo`, would simply be named
`kubectl-foo`, and live somewhere in your `PATH`.
### Example plugin ### Example plugin
``` ```bash
#!/bin/bash #!/bin/bash
# optional argument handling # optional argument handling
@@ -96,7 +93,7 @@ To use the above plugin, simply make it executable:
sudo chmod +x ./kubectl-foo sudo chmod +x ./kubectl-foo
``` ```
and place it anywhere in your PATH: and place it anywhere in your `PATH`:
``` ```
sudo mv ./kubectl-foo /usr/local/bin sudo mv ./kubectl-foo /usr/local/bin
@@ -137,7 +134,7 @@ KUBECONFIG=/etc/kube/config kubectl foo config
/etc/kube/config /etc/kube/config
``` ```
Additionally, the first argument that is passed to a plugin will always be the full path to the location where it was invoked (`$0` would equal `/usr/local/bin/kubectl-foo` in our example above). Additionally, the first argument that is passed to a plugin will always be the full path to the location where it was invoked (`$0` would equal `/usr/local/bin/kubectl-foo` in the example above).
### Naming a plugin ### Naming a plugin
@@ -147,15 +144,19 @@ For example, a plugin that wishes to be invoked whenever the command `kubectl fo
#### Flags and argument handling #### Flags and argument handling
{{< note >}} {{< note >}}
Unlike previous versions of `kubectl`, the plugin mechanism will _not_ create any custom, plugin-specific values or environment variables to a plugin process. The plugin mechanism does _not_ create any custom, plugin-specific values or environment variables for a plugin process.
This means that environment variables such as `KUBECTL_PLUGINS_CURRENT_NAMESPACE` are no longer provided to a plugin. Plugins must parse all of the arguments passed to them by a user,
and handle flag validation as part of their own implementation. For plugins written in Go, a set of utilities has been provided under [k8s.io/cli-runtime](https://github.com/kubernetes/cli-runtime) to assist with this. An older kubectl plugin mechanism provided environment variables such as `KUBECTL_PLUGINS_CURRENT_NAMESPACE`; that no longer happens.
{{< /note >}} {{< /note >}}
Taking our `kubectl-foo-bar-baz` plugin from the above scenario, we further explore additional cases where users invoke our plugin while providing additional flags and arguments. kubectl plugins must parse and validate all of the arguments passed to them.
For example, in a situation where a user invokes the command `kubectl foo bar baz arg1 --flag=value arg2`, the plugin mechanism will first try to find the plugin with the longest possible name, which in this case See [using the command line runtime package](#using-the-command-line-runtime-package) for details of a Go library aimed at plugin authors.
would be `kubectl-foo-bar-baz-arg1`. Upon not finding that plugin, it then treats the last dash-separated value as an argument (`arg1` in this case), and attempts to find the next longest possible name, `kubectl-foo-bar-baz`.
Upon finding a plugin with this name, it then invokes that plugin, passing all args and flags after its name to the plugin executable. Here are some additional cases where users invoke your plugin while providing additional flags and arguments. This builds upon the the `kubectl-foo-bar-baz` plugin from the scenario above.
If you run `kubectl foo bar baz arg1 --flag=value arg2`, kubectl's plugin mechanism will first try to find the plugin with the longest possible name, which in this case
would be `kubectl-foo-bar-baz-arg1`. Upon not finding that plugin, kubectl then treats the last dash-separated value as an argument (`arg1` in this case), and attempts to find the next longest possible name, `kubectl-foo-bar-baz`.
Upon having found a plugin with this name, kubectl then invokes that plugin, passing all args and flags after the plugin's name as arguments to the plugin process.
Example: Example:
@@ -164,28 +165,31 @@ Example:
echo -e '#!/bin/bash\n\necho "My first command-line argument was $1"' > kubectl-foo-bar-baz echo -e '#!/bin/bash\n\necho "My first command-line argument was $1"' > kubectl-foo-bar-baz
sudo chmod +x ./kubectl-foo-bar-baz sudo chmod +x ./kubectl-foo-bar-baz
# "install" our plugin by placing it on our PATH # "install" your plugin by moving it to a directory in your $PATH
sudo mv ./kubectl-foo-bar-baz /usr/local/bin sudo mv ./kubectl-foo-bar-baz /usr/local/bin
# ensure our plugin is recognized by kubectl # chck that kubectl recognizes your plugin
kubectl plugin list kubectl plugin list
``` ```
``` ```
The following kubectl-compatible plugins are available: The following kubectl-compatible plugins are available:
/usr/local/bin/kubectl-foo-bar-baz /usr/local/bin/kubectl-foo-bar-baz
``` ```
``` ```
# test that calling our plugin via a "kubectl" command works # test that calling your plugin via a "kubectl" command works
# even when additional arguments and flags are passed to our # even when additional arguments and flags are passed to your
# plugin executable by the user. # plugin executable by the user.
kubectl foo bar baz arg1 --meaningless-flag=true kubectl foo bar baz arg1 --meaningless-flag=true
``` ```
``` ```
My first command-line argument was arg1 My first command-line argument was arg1
``` ```
As you can see, our plugin was found based on the `kubectl` command specified by a user, and all extra arguments and flags were passed as-is to the plugin executable once it was found. As you can see, your plugin was found based on the `kubectl` command specified by a user, and all extra arguments and flags were passed as-is to the plugin executable once it was found.
#### Names with dashes and underscores #### Names with dashes and underscores
@@ -199,45 +203,49 @@ Example:
echo -e '#!/bin/bash\n\necho "I am a plugin with a dash in my name"' > ./kubectl-foo_bar echo -e '#!/bin/bash\n\necho "I am a plugin with a dash in my name"' > ./kubectl-foo_bar
sudo chmod +x ./kubectl-foo_bar sudo chmod +x ./kubectl-foo_bar
# move the plugin into your PATH # move the plugin into your $PATH
sudo mv ./kubectl-foo_bar /usr/local/bin sudo mv ./kubectl-foo_bar /usr/local/bin
# our plugin can now be invoked from `kubectl` like so: # You can now invoke your plugin via kubectl:
kubectl foo-bar kubectl foo-bar
``` ```
``` ```
I am a plugin with a dash in my name I am a plugin with a dash in my name
``` ```
Note that the introduction of underscores to a plugin filename does not prevent us from having commands such as `kubectl foo_bar`. Note that the introduction of underscores to a plugin filename does not prevent you from having commands such as `kubectl foo_bar`.
The command from the above example, can be invoked using either a dash (`-`) or an underscore (`_`): The command from the above example, can be invoked using either a dash (`-`) or an underscore (`_`):
```bash ```bash
# our plugin can be invoked with a dash # You can invoke your custom command with a dash
kubectl foo-bar kubectl foo-bar
``` ```
``` ```
I am a plugin with a dash in my name I am a plugin with a dash in my name
``` ```
```bash ```bash
# it can also be invoked using an underscore # You can also invoke your custom command with an underscore
kubectl foo_bar kubectl foo_bar
``` ```
``` ```
I am a plugin with a dash in my name I am a plugin with a dash in my name
``` ```
#### Name conflicts and overshadowing #### Name conflicts and overshadowing
It is possible to have multiple plugins with the same filename in different locations throughout your PATH. It is possible to have multiple plugins with the same filename in different locations throughout your `PATH`.
For example, given a PATH with the following value: `PATH=/usr/local/bin/plugins:/usr/local/bin/moreplugins`, a copy of plugin `kubectl-foo` could exist in `/usr/local/bin/plugins` and `/usr/local/bin/moreplugins`, For example, given a `PATH` with the following value: `PATH=/usr/local/bin/plugins:/usr/local/bin/moreplugins`, a copy of plugin `kubectl-foo` could exist in `/usr/local/bin/plugins` and `/usr/local/bin/moreplugins`,
such that the output of the `kubectl plugin list` command is: such that the output of the `kubectl plugin list` command is:
```bash ```bash
PATH=/usr/local/bin/plugins:/usr/local/bin/moreplugins kubectl plugin list PATH=/usr/local/bin/plugins:/usr/local/bin/moreplugins kubectl plugin list
``` ```
```bash
```
The following kubectl-compatible plugins are available: The following kubectl-compatible plugins are available:
/usr/local/bin/plugins/kubectl-foo /usr/local/bin/plugins/kubectl-foo
@@ -247,18 +255,19 @@ The following kubectl-compatible plugins are available:
error: one plugin warning was found error: one plugin warning was found
``` ```
In the above scenario, the warning under `/usr/local/bin/moreplugins/kubectl-foo` tells us that this plugin will never be executed. Instead, the executable that appears first in our PATH, `/usr/local/bin/plugins/kubectl-foo`, will always be found and executed first by the `kubectl` plugin mechanism. In the above scenario, the warning under `/usr/local/bin/moreplugins/kubectl-foo` tells you that this plugin will never be executed. Instead, the executable that appears first in your `PATH`, `/usr/local/bin/plugins/kubectl-foo`, will always be found and executed first by the `kubectl` plugin mechanism.
A way to resolve this issue is to ensure that the location of the plugin that you wish to use with `kubectl` always comes first in your PATH. For example, if we wanted to always use `/usr/local/bin/moreplugins/kubectl-foo` anytime that the `kubectl` command `kubectl foo` was invoked, we would simply change the value of our PATH to be `PATH=/usr/local/bin/moreplugins:/usr/local/bin/plugins`. A way to resolve this issue is to ensure that the location of the plugin that you wish to use with `kubectl` always comes first in your `PATH`. For example, if you want to always use `/usr/local/bin/moreplugins/kubectl-foo` anytime that the `kubectl` command `kubectl foo` was invoked, change the value of your `PATH` to be `/usr/local/bin/moreplugins:/usr/local/bin/plugins`.
#### Invocation of the longest executable filename #### Invocation of the longest executable filename
There is another kind of overshadowing that can occur with plugin filenames. Given two plugins present in a user's PATH `kubectl-foo-bar` and `kubectl-foo-bar-baz`, the `kubectl` plugin mechanism will always choose the longest possible plugin name for a given user command. Some examples below, clarify this further: There is another kind of overshadowing that can occur with plugin filenames. Given two plugins present in a user's `PATH`: `kubectl-foo-bar` and `kubectl-foo-bar-baz`, the `kubectl` plugin mechanism will always choose the longest possible plugin name for a given user command. Some examples below, clarify this further:
```bash ```bash
# for a given kubectl command, the plugin with the longest possible filename will always be preferred # for a given kubectl command, the plugin with the longest possible filename will always be preferred
kubectl foo bar baz kubectl foo bar baz
``` ```
``` ```
Plugin kubectl-foo-bar-baz is executed Plugin kubectl-foo-bar-baz is executed
``` ```
@@ -266,6 +275,7 @@ Plugin kubectl-foo-bar-baz is executed
```bash ```bash
kubectl foo bar kubectl foo bar
``` ```
``` ```
Plugin kubectl-foo-bar is executed Plugin kubectl-foo-bar is executed
``` ```
@@ -273,6 +283,7 @@ Plugin kubectl-foo-bar is executed
```bash ```bash
kubectl foo bar baz buz kubectl foo bar baz buz
``` ```
``` ```
Plugin kubectl-foo-bar-baz is executed, with "buz" as its first argument Plugin kubectl-foo-bar-baz is executed, with "buz" as its first argument
``` ```
@@ -280,6 +291,7 @@ Plugin kubectl-foo-bar-baz is executed, with "buz" as its first argument
```bash ```bash
kubectl foo bar buz kubectl foo bar buz
``` ```
``` ```
Plugin kubectl-foo-bar is executed, with "buz" as its first argument Plugin kubectl-foo-bar is executed, with "buz" as its first argument
``` ```
@@ -289,6 +301,7 @@ This design choice ensures that plugin sub-commands can be implemented across mu
```bash ```bash
ls ./plugin_command_tree ls ./plugin_command_tree
``` ```
``` ```
kubectl-parent kubectl-parent
kubectl-parent-subcommand kubectl-parent-subcommand
@@ -302,6 +315,7 @@ You can use the aforementioned `kubectl plugin list` command to ensure that your
```bash ```bash
kubectl plugin list kubectl plugin list
``` ```
``` ```
The following kubectl-compatible plugins are available: The following kubectl-compatible plugins are available:
@@ -316,41 +330,60 @@ error: 2 plugin warnings were found
### Using the command line runtime package ### Using the command line runtime package
As part of the plugin mechanism update in the v1.12.0 release, an additional set of utilities have been made available to plugin authors. These utilities If you're writing a plugin for kubectl and you're using Go, you can make use
exist under the [k8s.io/cli-runtime](https://github.com/kubernetes/cli-runtime) repository, and can be used by plugins written in Go to parse and update of the
a user's KUBECONFIG file, obtain REST clients to talk to the API server, and automatically bind flags associated with configuration and printing. [cli-runtime](https://github.com/kubernetes/cli-runtime) utility libraries.
Plugins *do not* have to be written in Go in order to be recognized as valid plugins by `kubectl`, but they do have to use Go in order to take advantage of These libraries provide helpers for parsing or updating a user's
the tools and utilities in the CLI Runtime repository. [kubeconfig](/docs/concepts/configuration/organize-cluster-access-kubeconfig/)
file, for making REST-style requests to the API server, or to bind flags
associated with configuration and printing.
See the [Sample CLI Plugin](https://github.com/kubernetes/sample-cli-plugin) for an example usage of the tools provided in the CLI Runtime repo. See the [Sample CLI Plugin](https://github.com/kubernetes/sample-cli-plugin) for
an example usage of the tools provided in the CLI Runtime repo.
## Distributing kubectl plugins ## Distributing kubectl plugins
If you have developed a plugin for others to use, you should consider how you If you have developed a plugin for others to use, you should consider how you
package it, distribute it and deliver updates to your users. package it, distribute it and deliver updates to your users.
[Krew](https://sigs.k8s.io/krew) project offers a cross-platform way to package ### Krew {#distributing-krew}
and distribute your plugins. This way, you use a single packaging format for all
[Krew](https://krew.dev/) offers a cross-platform way to package and
distribute your plugins. This way, you use a single packaging format for all
target platforms (Linux, Windows, macOS etc) and deliver updates to your users. target platforms (Linux, Windows, macOS etc) and deliver updates to your users.
Since Krew also maintains a [plugin Krew also maintains a [plugin
index](https://github.com/kubernetes-sigs/krew-index), others can discover your index](https://index.krew.dev/) so that other people can
plugin and install it. Read the [Krew developer discover your plugin and install it.
guide](https://github.com/kubernetes-sigs/krew/blob/master/docs/DEVELOPER_GUIDE.md)
to learn how to package kubectl plugins for Krew.
### Native / platform specific package management {#distributing-native}
Alternatively, you can use traditional package managers such as, `apt` or `yum` Alternatively, you can use traditional package managers such as, `apt` or `yum`
on Linux, Chocolatey on Windows, Homebrew on macOS, since kubectl plugins are on Linux, Chocolatey on Windows, and Homebrew on macOS. Any package
just executables placed somewhere in client's PATH. This comes with the burden manager will be suitable if it can place new executables placed somewhere
of updating your kubectl plugins distribution package in multiple platforms in the user's `PATH`.
when you release a newer version. As a plugin author, if you pick this option then you also have the burden
of updating your kubectl plugins distribution package across multiple
platforms for each release.
### Source code {#distributing-source-code}
You can publish the source code; for example, as a Git repository. If you
choose this option, someone who wants to use that plugin must fetch the code,
set up a build environment (if it needs compiling), and deploy the plugin.
If you also make compiled packages available, or use Krew, that will make
installs easier.
{{% /capture %}} {{% /capture %}}
{{% capture whatsnext %}} {{% capture whatsnext %}}
* Install [Krew kubectl plugin manager](https://sigs.k8s.io/krew) to discover and install plugins. * Check the Sample CLI Plugin repository for a
* Check the Sample CLI Plugin repository for [a detailed example](https://github.com/kubernetes/sample-cli-plugin) of a plugin written in Go. [detailed example](https://github.com/kubernetes/sample-cli-plugin) of a
* In case of any questions, feel free to reach out to the [CLI SIG team](https://github.com/kubernetes/community/tree/master/sig-cli). plugin written in Go.
In case of any questions, feel free to reach out to the
[SIG CLI team](https://github.com/kubernetes/community/tree/master/sig-cli).
* Read about [Krew](https://krew.dev/), a package manager for kubectl plugins.
{{% /capture %}} {{% /capture %}}