mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 20:24:09 +00:00
Merge pull request #12220 from brendandburns/stdin
Add interactive run that combines run and attach.
This commit is contained in:
commit
7a875a1ac0
@ -616,6 +616,7 @@ _kubectl_run()
|
||||
flags_with_completion=()
|
||||
flags_completion=()
|
||||
|
||||
flags+=("--attach")
|
||||
flags+=("--dry-run")
|
||||
flags+=("--generator=")
|
||||
flags+=("--help")
|
||||
@ -632,8 +633,11 @@ _kubectl_run()
|
||||
flags+=("--port=")
|
||||
flags+=("--replicas=")
|
||||
two_word_flags+=("-r")
|
||||
flags+=("--stdin")
|
||||
flags+=("-i")
|
||||
flags+=("--template=")
|
||||
two_word_flags+=("-t")
|
||||
flags+=("--tty")
|
||||
|
||||
must_have_one_flag=()
|
||||
must_have_one_flag+=("--image=")
|
||||
|
@ -18,6 +18,10 @@ Creates a replication controller to manage the created container(s).
|
||||
|
||||
|
||||
.SH OPTIONS
|
||||
.PP
|
||||
\fB\-\-attach\fP=false
|
||||
If true, wait for the Pod to start running, and then attach to the Pod as if 'kubectl attach ...' were called. Default false, unless '\-i/\-\-interactive' is set, in which case the default is true.
|
||||
|
||||
.PP
|
||||
\fB\-\-dry\-run\fP=false
|
||||
If true, only print the object that would be sent, without sending it.
|
||||
@ -66,11 +70,19 @@ Creates a replication controller to manage the created container(s).
|
||||
\fB\-r\fP, \fB\-\-replicas\fP=1
|
||||
Number of replicas to create for this container. Default is 1.
|
||||
|
||||
.PP
|
||||
\fB\-i\fP, \fB\-\-stdin\fP=false
|
||||
Keep stdin open on the container(s) in the pod, even if nothing is attached.
|
||||
|
||||
.PP
|
||||
\fB\-t\fP, \fB\-\-template\fP=""
|
||||
Template string or path to template file to use when \-o=template or \-o=templatefile. The template format is golang templates [
|
||||
\[la]http://golang.org/pkg/text/template/#pkg-overview\[ra]]
|
||||
|
||||
.PP
|
||||
\fB\-\-tty\fP=false
|
||||
Allocated a TTY for each container in the pod. Because \-t is currently shorthand for \-\-template, \-t is not supported for \-\-tty. This shorthand is deprecated and we expect to adopt \-t for \-\-tty soon.
|
||||
|
||||
|
||||
.SH OPTIONS INHERITED FROM PARENT COMMANDS
|
||||
.PP
|
||||
|
@ -80,6 +80,17 @@ nginx-http run=nginx-app run=nginx-app 80/TCP
|
||||
|
||||
With kubectl, we create a [replication controller](replication-controller.md) which will make sure that N pods are running nginx (where N is the number of replicas stated in the spec, which defaults to 1). We also create a [service](services.md) with a selector that matches the replication controller's selector. See the [Quick start](quick-start.md) for more information.
|
||||
|
||||
By default images are run in the background, similar to `docker run -d ...`, if you want to run things in the foreground, use:
|
||||
|
||||
```console
|
||||
kubectl run [-i] [--tty] --attach <name> --image=<image>
|
||||
```
|
||||
|
||||
Unlike `docker run ...`, if `--attach` is specified, we attach to `stdin`, `stdout` and `stderr`, there is no ability to control which streams are attached (`docker -a ...`).
|
||||
|
||||
Because we start a replication controller for your container, it will be restarted if you terminate the attached process (e.g. `ctrl-c`), this is different than `docker run -it`.
|
||||
To destroy the replication controller (and it's pods) you need to run `kubectl delete rc <name>`
|
||||
|
||||
#### docker ps
|
||||
|
||||
How do I list what is currently running? Checkout [kubectl get](kubectl/kubectl_get.md).
|
||||
|
@ -121,7 +121,7 @@ $ kubectl annotate pods foo description-
|
||||
|
||||
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
|
||||
|
||||
###### Auto generated by spf13/cobra at 2015-08-05 14:22:30.875870257 +0000 UTC
|
||||
###### Auto generated by spf13/cobra at 2015-08-07 03:15:49.183633333 +0000 UTC
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
[]()
|
||||
|
@ -103,7 +103,7 @@ $ kubectl config view -o template --template='{{range .users}}{{ if eq .name "e2
|
||||
|
||||
* [kubectl config](kubectl_config.md) - config modifies kubeconfig files
|
||||
|
||||
###### Auto generated by spf13/cobra at 2015-08-05 14:22:30.876088386 +0000 UTC
|
||||
###### Auto generated by spf13/cobra at 2015-08-07 03:15:49.184001914 +0000 UTC
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
[]()
|
||||
|
@ -118,7 +118,7 @@ $ kubectl expose rc streamer --port=4100 --protocol=udp --name=video-stream
|
||||
|
||||
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
|
||||
|
||||
###### Auto generated by spf13/cobra at 2015-08-05 23:27:50.888628432 +0000 UTC
|
||||
###### Auto generated by spf13/cobra at 2015-08-07 03:15:49.182748201 +0000 UTC
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
[]()
|
||||
|
@ -125,7 +125,7 @@ $ kubectl get rc/web service/frontend pods/web-pod-13je7
|
||||
|
||||
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
|
||||
|
||||
###### Auto generated by spf13/cobra at 2015-08-05 23:27:50.884869862 +0000 UTC
|
||||
###### Auto generated by spf13/cobra at 2015-08-07 03:15:49.175798628 +0000 UTC
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
[]()
|
||||
|
@ -115,7 +115,7 @@ $ kubectl label pods foo bar-
|
||||
|
||||
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
|
||||
|
||||
###### Auto generated by spf13/cobra at 2015-08-05 23:27:50.888803859 +0000 UTC
|
||||
###### Auto generated by spf13/cobra at 2015-08-07 03:15:49.183216488 +0000 UTC
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
[]()
|
||||
|
@ -117,7 +117,7 @@ $ kubectl rolling-update frontend --image=image:v2
|
||||
|
||||
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
|
||||
|
||||
###### Auto generated by spf13/cobra at 2015-08-05 23:28:32.886715844 +0000 UTC
|
||||
###### Auto generated by spf13/cobra at 2015-08-07 03:15:49.179537741 +0000 UTC
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
[]()
|
||||
|
@ -64,6 +64,7 @@ $ kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { .
|
||||
### Options
|
||||
|
||||
```
|
||||
--attach[=false]: If true, wait for the Pod to start running, and then attach to the Pod as if 'kubectl attach ...' were called. Default false, unless '-i/--interactive' is set, in which case the default is true.
|
||||
--dry-run[=false]: If true, only print the object that would be sent, without sending it.
|
||||
--generator="run/v1": The name of the API generator to use. Default is 'run-controller/v1'.
|
||||
-h, --help[=false]: help for run
|
||||
@ -76,7 +77,9 @@ $ kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { .
|
||||
--overrides="": An inline JSON override for the generated object. If this is non-empty, it is used to override the generated object. Requires that the object supply a valid apiVersion field.
|
||||
--port=-1: The port that this container exposes.
|
||||
-r, --replicas=1: Number of replicas to create for this container. Default is 1.
|
||||
-i, --stdin[=false]: Keep stdin open on the container(s) in the pod, even if nothing is attached.
|
||||
-t, --template="": Template string or path to template file to use when -o=template or -o=templatefile. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview]
|
||||
--tty[=false]: Allocated a TTY for each container in the pod. Because -t is currently shorthand for --template, -t is not supported for --tty. This shorthand is deprecated and we expect to adopt -t for --tty soon.
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
@ -112,7 +115,7 @@ $ kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { .
|
||||
|
||||
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
|
||||
|
||||
###### Auto generated by spf13/cobra at 2015-08-05 14:22:30.874977162 +0000 UTC
|
||||
###### Auto generated by spf13/cobra at 2015-08-07 03:15:49.181215106 +0000 UTC
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
[]()
|
||||
|
@ -141,7 +141,7 @@ Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`,
|
||||
cmds.AddCommand(NewCmdPortForward(f))
|
||||
cmds.AddCommand(NewCmdProxy(f, out))
|
||||
|
||||
cmds.AddCommand(NewCmdRun(f, out))
|
||||
cmds.AddCommand(NewCmdRun(f, in, out, err))
|
||||
cmds.AddCommand(NewCmdStop(f, out))
|
||||
cmds.AddCommand(NewCmdExposeService(f, out))
|
||||
|
||||
|
@ -261,7 +261,7 @@ func ExamplePrintReplicationControllerWithNamespace() {
|
||||
Codec: codec,
|
||||
Client: nil,
|
||||
}
|
||||
cmd := NewCmdRun(f, os.Stdout)
|
||||
cmd := NewCmdRun(f, os.Stdin, os.Stdout, os.Stderr)
|
||||
ctrl := &api.ReplicationController{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo",
|
||||
@ -303,7 +303,7 @@ func ExamplePrintPodWithWideFormat() {
|
||||
Client: nil,
|
||||
}
|
||||
nodeName := "kubernetes-minion-abcd"
|
||||
cmd := NewCmdRun(f, os.Stdout)
|
||||
cmd := NewCmdRun(f, os.Stdin, os.Stdout, os.Stderr)
|
||||
pod := &api.Pod{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "test1",
|
||||
@ -337,7 +337,7 @@ func ExamplePrintServiceWithNamespacesAndLabels() {
|
||||
Codec: codec,
|
||||
Client: nil,
|
||||
}
|
||||
cmd := NewCmdRun(f, os.Stdout)
|
||||
cmd := NewCmdRun(f, os.Stdin, os.Stdout, os.Stderr)
|
||||
svc := &api.ServiceList{
|
||||
Items: []api.Service{
|
||||
{
|
||||
|
@ -20,11 +20,15 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/client"
|
||||
"k8s.io/kubernetes/pkg/fields"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -43,7 +47,7 @@ $ kubectl run nginx --image=nginx --dry-run
|
||||
$ kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { ... } }'`
|
||||
)
|
||||
|
||||
func NewCmdRun(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
func NewCmdRun(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "run NAME --image=image [--port=port] [--replicas=replicas] [--dry-run=bool] [--overrides=inline-json]",
|
||||
// run-container is deprecated
|
||||
@ -52,7 +56,7 @@ func NewCmdRun(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
Long: run_long,
|
||||
Example: run_example,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := Run(f, out, cmd, args)
|
||||
err := Run(f, cmdIn, cmdOut, cmdErr, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
},
|
||||
}
|
||||
@ -66,10 +70,13 @@ func NewCmdRun(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
cmd.Flags().Int("port", -1, "The port that this container exposes.")
|
||||
cmd.Flags().Int("hostport", -1, "The host port mapping for the container port. To demonstrate a single-machine container.")
|
||||
cmd.Flags().StringP("labels", "l", "", "Labels to apply to the pod(s).")
|
||||
cmd.Flags().BoolP("stdin", "i", false, "Keep stdin open on the container(s) in the pod, even if nothing is attached.")
|
||||
cmd.Flags().Bool("tty", false, "Allocated a TTY for each container in the pod. Because -t is currently shorthand for --template, -t is not supported for --tty. This shorthand is deprecated and we expect to adopt -t for --tty soon.")
|
||||
cmd.Flags().Bool("attach", false, "If true, wait for the Pod to start running, and then attach to the Pod as if 'kubectl attach ...' were called. Default false, unless '-i/--interactive' is set, in which case the default is true.")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func Run(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cobra.Command, args []string) error {
|
||||
if len(os.Args) > 1 && os.Args[1] == "run-container" {
|
||||
printDeprecationWarning("run", "run-container")
|
||||
}
|
||||
@ -78,6 +85,16 @@ func Run(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) e
|
||||
return cmdutil.UsageError(cmd, "NAME is required for run")
|
||||
}
|
||||
|
||||
interactive := cmdutil.GetFlagBool(cmd, "stdin")
|
||||
tty := cmdutil.GetFlagBool(cmd, "tty")
|
||||
if tty && !interactive {
|
||||
return cmdutil.UsageError(cmd, "-i/--stdin is required for containers with --tty=true")
|
||||
}
|
||||
replicas := cmdutil.GetFlagInt(cmd, "replicas")
|
||||
if interactive && replicas != 1 {
|
||||
return cmdutil.UsageError(cmd, fmt.Sprintf("-i/--stdin requires that replicas is 1, found %d", replicas))
|
||||
}
|
||||
|
||||
namespace, _, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -123,5 +140,82 @@ func Run(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) e
|
||||
}
|
||||
}
|
||||
|
||||
return f.PrintObject(cmd, controller, out)
|
||||
attachFlag := cmd.Flags().Lookup("attach")
|
||||
attach := cmdutil.GetFlagBool(cmd, "attach")
|
||||
|
||||
if !attachFlag.Changed && interactive {
|
||||
attach = true
|
||||
}
|
||||
|
||||
if attach {
|
||||
opts := &AttachOptions{
|
||||
In: cmdIn,
|
||||
Out: cmdOut,
|
||||
Err: cmdErr,
|
||||
Stdin: interactive,
|
||||
TTY: tty,
|
||||
|
||||
Attach: &DefaultRemoteAttach{},
|
||||
}
|
||||
config, err := f.ClientConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opts.Config = config
|
||||
|
||||
client, err := f.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opts.Client = client
|
||||
return handleAttach(client, controller.(*api.ReplicationController), opts)
|
||||
}
|
||||
return f.PrintObject(cmd, controller, cmdOut)
|
||||
}
|
||||
|
||||
func waitForPodRunning(c *client.Client, pod *api.Pod, out io.Writer) error {
|
||||
for {
|
||||
pod, err := c.Pods(pod.Namespace).Get(pod.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pod.Status.Phase == api.PodRunning {
|
||||
ready := true
|
||||
for _, status := range pod.Status.ContainerStatuses {
|
||||
if !status.Ready {
|
||||
ready = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if ready {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(out, "Waiting for pod %s/%s to be running\n", pod.Namespace, pod.Name)
|
||||
time.Sleep(2 * time.Second)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
func handleAttach(c *client.Client, controller *api.ReplicationController, opts *AttachOptions) error {
|
||||
var pods *api.PodList
|
||||
for pods == nil || len(pods.Items) == 0 {
|
||||
var err error
|
||||
if pods, err = c.Pods(controller.Namespace).List(labels.SelectorFromSet(controller.Spec.Selector), fields.Everything()); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(pods.Items) == 0 {
|
||||
fmt.Fprint(opts.Out, "Waiting for pod to be scheduled\n")
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
pod := &pods.Items[0]
|
||||
|
||||
if err := waitForPodRunning(c, pod, opts.Out); err != nil {
|
||||
return err
|
||||
}
|
||||
opts.Client = c
|
||||
opts.PodName = pod.Name
|
||||
opts.Namespace = pod.Namespace
|
||||
return opts.Run()
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ package kubectl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
@ -88,3 +89,11 @@ func ParseLabels(labelString string) (map[string]string, error) {
|
||||
}
|
||||
return labels, nil
|
||||
}
|
||||
|
||||
func GetBool(params map[string]string, key string, defValue bool) (bool, error) {
|
||||
if val, found := params[key]; !found {
|
||||
return defValue, nil
|
||||
} else {
|
||||
return strconv.ParseBool(val)
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,8 @@ func (BasicReplicationController) ParamNames() []GeneratorParam {
|
||||
{"image", true},
|
||||
{"port", false},
|
||||
{"hostport", false},
|
||||
{"stdin", false},
|
||||
{"tty", false},
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,6 +66,16 @@ func (BasicReplicationController) Generate(params map[string]string) (runtime.Ob
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stdin, err := GetBool(params, "stdin", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tty, err := GetBool(params, "tty", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
controller := api.ReplicationController{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: name,
|
||||
@ -81,6 +93,8 @@ func (BasicReplicationController) Generate(params map[string]string) (runtime.Ob
|
||||
{
|
||||
Name: name,
|
||||
Image: params["image"],
|
||||
Stdin: stdin,
|
||||
TTY: tty,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user