mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Support setting env vars in kubectl run
This commit is contained in:
		@@ -681,6 +681,7 @@ _kubectl_run()
 | 
			
		||||
    flags+=("--attach")
 | 
			
		||||
    flags+=("--command")
 | 
			
		||||
    flags+=("--dry-run")
 | 
			
		||||
    flags+=("--env=")
 | 
			
		||||
    flags+=("--generator=")
 | 
			
		||||
    flags+=("--hostport=")
 | 
			
		||||
    flags+=("--image=")
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,10 @@ Creates a replication controller to manage the created container(s).
 | 
			
		||||
\fB\-\-dry\-run\fP=false
 | 
			
		||||
    If true, only print the object that would be sent, without sending it.
 | 
			
		||||
 | 
			
		||||
.PP
 | 
			
		||||
\fB\-\-env\fP=[]
 | 
			
		||||
    Environment variables to set in the container
 | 
			
		||||
 | 
			
		||||
.PP
 | 
			
		||||
\fB\-\-generator\fP=""
 | 
			
		||||
    The name of the API generator to use.  Default is 'run/v1' if \-\-restart=Always, otherwise the default is 'run\-pod/v1'.
 | 
			
		||||
@@ -200,6 +204,12 @@ Creates a replication controller to manage the created container(s).
 | 
			
		||||
# Start a single instance of nginx.
 | 
			
		||||
$ kubectl run nginx \-\-image=nginx
 | 
			
		||||
 | 
			
		||||
# Start a single instance of hazelcast and let the container expose port 5701 .
 | 
			
		||||
$ kubectl run hazelcast \-\-image=hazelcast \-\-port=5701
 | 
			
		||||
 | 
			
		||||
# Start a single instance of hazelcast and set environment variables "DNS\_DOMAIN=cluster" and "POD\_NAMESPACE=default" in the container.
 | 
			
		||||
$ kubectl run hazelcast \-\-image=hazelcast \-\-env="DNS\_DOMAIN=local" \-\-env="POD\_NAMESPACE=default"
 | 
			
		||||
 | 
			
		||||
# Start a replicated instance of nginx.
 | 
			
		||||
$ kubectl run nginx \-\-image=nginx \-\-replicas=5
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -58,7 +58,7 @@ How do I run an nginx container and expose it to the world? Checkout [kubectl ru
 | 
			
		||||
With docker:
 | 
			
		||||
 | 
			
		||||
```console
 | 
			
		||||
$ docker run -d --restart=always --name nginx-app -p 80:80 nginx
 | 
			
		||||
$ docker run -d --restart=always -e DOMAIN=cluster --name nginx-app -p 80:80 nginx
 | 
			
		||||
a9ec34d9878748d2f33dc20cb25c714ff21da8d40558b45bfaec9955859075d0
 | 
			
		||||
$ docker ps
 | 
			
		||||
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                         NAMES
 | 
			
		||||
@@ -69,7 +69,7 @@ With kubectl:
 | 
			
		||||
 | 
			
		||||
```console
 | 
			
		||||
# start the pod running nginx
 | 
			
		||||
$ kubectl run --image=nginx nginx-app
 | 
			
		||||
$ kubectl run --image=nginx nginx-app --port=80 --env="DOMAIN=local"
 | 
			
		||||
CONTROLLER   CONTAINER(S)   IMAGE(S)   SELECTOR        REPLICAS
 | 
			
		||||
nginx-app    nginx-app      nginx      run=nginx-app   1
 | 
			
		||||
# expose a port through with a service
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,7 @@ Create and run a particular image, possibly replicated.
 | 
			
		||||
Creates a replication controller to manage the created container(s).
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
kubectl run NAME --image=image [--port=port] [--replicas=replicas] [--dry-run=bool] [--overrides=inline-json]
 | 
			
		||||
kubectl run NAME --image=image [--env="key=value"] [--port=port] [--replicas=replicas] [--dry-run=bool] [--overrides=inline-json]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Examples
 | 
			
		||||
@@ -51,6 +51,12 @@ kubectl run NAME --image=image [--port=port] [--replicas=replicas] [--dry-run=bo
 | 
			
		||||
# Start a single instance of nginx.
 | 
			
		||||
$ kubectl run nginx --image=nginx
 | 
			
		||||
 | 
			
		||||
# Start a single instance of hazelcast and let the container expose port 5701 .
 | 
			
		||||
$ kubectl run hazelcast --image=hazelcast --port=5701
 | 
			
		||||
 | 
			
		||||
# Start a single instance of hazelcast and set environment variables "DNS_DOMAIN=cluster" and "POD_NAMESPACE=default" in the container.
 | 
			
		||||
$ kubectl run hazelcast --image=hazelcast --env="DNS_DOMAIN=local" --env="POD_NAMESPACE=default"
 | 
			
		||||
 | 
			
		||||
# Start a replicated instance of nginx.
 | 
			
		||||
$ kubectl run nginx --image=nginx --replicas=5
 | 
			
		||||
 | 
			
		||||
@@ -76,6 +82,7 @@ $ kubectl run nginx --image=nginx --command -- <cmd> <arg1> ... <argN>
 | 
			
		||||
      --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.
 | 
			
		||||
      --command[=false]: If true and extra arguments are present, use them as the 'command' field in the container, rather than the 'args' field which is the default.
 | 
			
		||||
      --dry-run[=false]: If true, only print the object that would be sent, without sending it.
 | 
			
		||||
      --env=[]: Environment variables to set in the container
 | 
			
		||||
      --generator="": The name of the API generator to use.  Default is 'run/v1' if --restart=Always, otherwise the default is 'run-pod/v1'.
 | 
			
		||||
      --hostport=-1: The host port mapping for the container port. To demonstrate a single-machine container.
 | 
			
		||||
      --image="": The image for the container to run.
 | 
			
		||||
@@ -126,7 +133,7 @@ $ kubectl run nginx --image=nginx --command -- <cmd> <arg1> ... <argN>
 | 
			
		||||
 | 
			
		||||
* [kubectl](kubectl.md)	 - kubectl controls the Kubernetes cluster manager
 | 
			
		||||
 | 
			
		||||
###### Auto generated by spf13/cobra at 2015-08-29 13:01:26.772003236 +0000 UTC
 | 
			
		||||
###### Auto generated by spf13/cobra at 2015-09-07 06:40:12.142439604 +0000 UTC
 | 
			
		||||
 | 
			
		||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
 | 
			
		||||
[]()
 | 
			
		||||
 
 | 
			
		||||
@@ -38,6 +38,12 @@ Creates a replication controller to manage the created container(s).`
 | 
			
		||||
	run_example = `# Start a single instance of nginx.
 | 
			
		||||
$ kubectl run nginx --image=nginx
 | 
			
		||||
 | 
			
		||||
# Start a single instance of hazelcast and let the container expose port 5701 .
 | 
			
		||||
$ kubectl run hazelcast --image=hazelcast --port=5701
 | 
			
		||||
 | 
			
		||||
# Start a single instance of hazelcast and set environment variables "DNS_DOMAIN=cluster" and "POD_NAMESPACE=default" in the container.
 | 
			
		||||
$ kubectl run hazelcast --image=hazelcast --env="DNS_DOMAIN=local" --env="POD_NAMESPACE=default"
 | 
			
		||||
 | 
			
		||||
# Start a replicated instance of nginx.
 | 
			
		||||
$ kubectl run nginx --image=nginx --replicas=5
 | 
			
		||||
 | 
			
		||||
@@ -59,7 +65,7 @@ $ kubectl run nginx --image=nginx --command -- <cmd> <arg1> ... <argN>`
 | 
			
		||||
 | 
			
		||||
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]",
 | 
			
		||||
		Use: "run NAME --image=image [--env=\"key=value\"] [--port=port] [--replicas=replicas] [--dry-run=bool] [--overrides=inline-json]",
 | 
			
		||||
		// run-container is deprecated
 | 
			
		||||
		Aliases: []string{"run-container"},
 | 
			
		||||
		Short:   "Run a particular image on the cluster.",
 | 
			
		||||
@@ -77,6 +83,7 @@ func NewCmdRun(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *c
 | 
			
		||||
	cmd.Flags().IntP("replicas", "r", 1, "Number of replicas to create for this container. Default is 1.")
 | 
			
		||||
	cmd.Flags().Bool("dry-run", false, "If true, only print the object that would be sent, without sending it.")
 | 
			
		||||
	cmd.Flags().String("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.")
 | 
			
		||||
	cmd.Flags().StringSlice("env", []string{}, "Environment variables to set in the container")
 | 
			
		||||
	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).")
 | 
			
		||||
@@ -137,6 +144,9 @@ func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cob
 | 
			
		||||
	if len(args) > 1 {
 | 
			
		||||
		params["args"] = args[1:]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	params["env"] = cmdutil.GetFlagStringSlice(cmd, "env")
 | 
			
		||||
 | 
			
		||||
	err = kubectl.ValidateParams(names, params)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
 
 | 
			
		||||
@@ -17,10 +17,12 @@ limitations under the License.
 | 
			
		||||
package cmd
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/api"
 | 
			
		||||
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestGetRestartPolicy(t *testing.T) {
 | 
			
		||||
@@ -78,3 +80,20 @@ func TestGetRestartPolicy(t *testing.T) {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetEnv(t *testing.T) {
 | 
			
		||||
	test := struct {
 | 
			
		||||
		input    []string
 | 
			
		||||
		expected []string
 | 
			
		||||
	}{
 | 
			
		||||
		input:    []string{"a=b", "c=d"},
 | 
			
		||||
		expected: []string{"a=b", "c=d"},
 | 
			
		||||
	}
 | 
			
		||||
	cmd := &cobra.Command{}
 | 
			
		||||
	cmd.Flags().StringSlice("env", test.input, "")
 | 
			
		||||
 | 
			
		||||
	envStrings := cmdutil.GetFlagStringSlice(cmd, "env")
 | 
			
		||||
	if len(envStrings) != 2 || !reflect.DeepEqual(envStrings, test.expected) {
 | 
			
		||||
		t.Errorf("expected: %s, saw: %s", test.expected, envStrings)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,9 +19,11 @@ package kubectl
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/kubernetes/pkg/api"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/util"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type BasicReplicationController struct{}
 | 
			
		||||
@@ -39,6 +41,7 @@ func (BasicReplicationController) ParamNames() []GeneratorParam {
 | 
			
		||||
		{"tty", false},
 | 
			
		||||
		{"command", false},
 | 
			
		||||
		{"args", false},
 | 
			
		||||
		{"env", false},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -77,6 +80,23 @@ func (BasicReplicationController) Generate(genericParams map[string]interface{})
 | 
			
		||||
		}
 | 
			
		||||
		delete(genericParams, "args")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: abstract this logic so that multiple generators can handle env in the same way. Same for parse envs.
 | 
			
		||||
	var envs []api.EnvVar
 | 
			
		||||
	envStrings, found := genericParams["env"]
 | 
			
		||||
	if found {
 | 
			
		||||
		if envStringArray, isArray := envStrings.([]string); isArray {
 | 
			
		||||
			var err error
 | 
			
		||||
			envs, err = parseEnvs(envStringArray)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			delete(genericParams, "env")
 | 
			
		||||
		} else {
 | 
			
		||||
			return nil, fmt.Errorf("expected []string, found: %v", envStrings)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	params := map[string]string{}
 | 
			
		||||
	for key, value := range genericParams {
 | 
			
		||||
		strVal, isString := value.(string)
 | 
			
		||||
@@ -127,6 +147,10 @@ func (BasicReplicationController) Generate(genericParams map[string]interface{})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(envs) > 0 {
 | 
			
		||||
		podSpec.Containers[0].Env = envs
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	controller := api.ReplicationController{
 | 
			
		||||
		ObjectMeta: api.ObjectMeta{
 | 
			
		||||
			Name:   name,
 | 
			
		||||
@@ -198,6 +222,7 @@ func (BasicPod) ParamNames() []GeneratorParam {
 | 
			
		||||
		{"restart", false},
 | 
			
		||||
		{"command", false},
 | 
			
		||||
		{"args", false},
 | 
			
		||||
		{"env", false},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -212,6 +237,22 @@ func (BasicPod) Generate(genericParams map[string]interface{}) (runtime.Object,
 | 
			
		||||
		}
 | 
			
		||||
		delete(genericParams, "args")
 | 
			
		||||
	}
 | 
			
		||||
	// TODO: abstract this logic so that multiple generators can handle env in the same way. Same for parse envs.
 | 
			
		||||
	var envs []api.EnvVar
 | 
			
		||||
	envStrings, found := genericParams["env"]
 | 
			
		||||
	if found {
 | 
			
		||||
		if envStringArray, isArray := envStrings.([]string); isArray {
 | 
			
		||||
			var err error
 | 
			
		||||
			envs, err = parseEnvs(envStringArray)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			delete(genericParams, "env")
 | 
			
		||||
		} else {
 | 
			
		||||
			return nil, fmt.Errorf("expected []string, found: %v", envStrings)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	params := map[string]string{}
 | 
			
		||||
	for key, value := range genericParams {
 | 
			
		||||
		strVal, isString := value.(string)
 | 
			
		||||
@@ -281,8 +322,26 @@ func (BasicPod) Generate(genericParams map[string]interface{}) (runtime.Object,
 | 
			
		||||
			pod.Spec.Containers[0].Args = args
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(envs) > 0 {
 | 
			
		||||
		pod.Spec.Containers[0].Env = envs
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := updatePodPorts(params, &pod.Spec); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return &pod, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseEnvs(envArray []string) ([]api.EnvVar, error) {
 | 
			
		||||
	envs := []api.EnvVar{}
 | 
			
		||||
	for _, env := range envArray {
 | 
			
		||||
		parts := strings.Split(env, "=")
 | 
			
		||||
		if len(parts) != 2 || !util.IsCIdentifier(parts[0]) || len(parts[1]) == 0 {
 | 
			
		||||
			return nil, fmt.Errorf("invalid env: %v", env)
 | 
			
		||||
		}
 | 
			
		||||
		envVar := api.EnvVar{Name: parts[0], Value: parts[1]}
 | 
			
		||||
		envs = append(envs, envVar)
 | 
			
		||||
	}
 | 
			
		||||
	return envs, nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -60,6 +60,50 @@ func TestGenerate(t *testing.T) {
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		{
 | 
			
		||||
			params: map[string]interface{}{
 | 
			
		||||
				"name":     "foo",
 | 
			
		||||
				"image":    "someimage",
 | 
			
		||||
				"replicas": "1",
 | 
			
		||||
				"port":     "-1",
 | 
			
		||||
				"env":      []string{"a=b", "c=d"},
 | 
			
		||||
			},
 | 
			
		||||
			expected: &api.ReplicationController{
 | 
			
		||||
				ObjectMeta: api.ObjectMeta{
 | 
			
		||||
					Name:   "foo",
 | 
			
		||||
					Labels: map[string]string{"run": "foo"},
 | 
			
		||||
				},
 | 
			
		||||
				Spec: api.ReplicationControllerSpec{
 | 
			
		||||
					Replicas: 1,
 | 
			
		||||
					Selector: map[string]string{"run": "foo"},
 | 
			
		||||
					Template: &api.PodTemplateSpec{
 | 
			
		||||
						ObjectMeta: api.ObjectMeta{
 | 
			
		||||
							Labels: map[string]string{"run": "foo"},
 | 
			
		||||
						},
 | 
			
		||||
						Spec: api.PodSpec{
 | 
			
		||||
							Containers: []api.Container{
 | 
			
		||||
								{
 | 
			
		||||
									Name:  "foo",
 | 
			
		||||
									Image: "someimage",
 | 
			
		||||
									Env: []api.EnvVar{
 | 
			
		||||
										{
 | 
			
		||||
											Name:  "a",
 | 
			
		||||
											Value: "b",
 | 
			
		||||
										},
 | 
			
		||||
										{
 | 
			
		||||
											Name:  "c",
 | 
			
		||||
											Value: "d",
 | 
			
		||||
										},
 | 
			
		||||
									},
 | 
			
		||||
								},
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		{
 | 
			
		||||
			params: map[string]interface{}{
 | 
			
		||||
				"name":     "foo",
 | 
			
		||||
@@ -287,6 +331,49 @@ func TestGeneratePod(t *testing.T) {
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			params: map[string]interface{}{
 | 
			
		||||
				"name":  "foo",
 | 
			
		||||
				"image": "someimage",
 | 
			
		||||
				"env":   []string{"a", "c"},
 | 
			
		||||
			},
 | 
			
		||||
 | 
			
		||||
			expected:  nil,
 | 
			
		||||
			expectErr: true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			params: map[string]interface{}{
 | 
			
		||||
				"name":  "foo",
 | 
			
		||||
				"image": "someimage",
 | 
			
		||||
				"env":   []string{"a=b", "c=d"},
 | 
			
		||||
			},
 | 
			
		||||
			expected: &api.Pod{
 | 
			
		||||
				ObjectMeta: api.ObjectMeta{
 | 
			
		||||
					Name: "foo",
 | 
			
		||||
				},
 | 
			
		||||
				Spec: api.PodSpec{
 | 
			
		||||
					Containers: []api.Container{
 | 
			
		||||
						{
 | 
			
		||||
							Name:            "foo",
 | 
			
		||||
							Image:           "someimage",
 | 
			
		||||
							ImagePullPolicy: api.PullIfNotPresent,
 | 
			
		||||
							Env: []api.EnvVar{
 | 
			
		||||
								{
 | 
			
		||||
									Name:  "a",
 | 
			
		||||
									Value: "b",
 | 
			
		||||
								},
 | 
			
		||||
								{
 | 
			
		||||
									Name:  "c",
 | 
			
		||||
									Value: "d",
 | 
			
		||||
								},
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
					DNSPolicy:     api.DNSClusterFirst,
 | 
			
		||||
					RestartPolicy: api.RestartPolicyAlways,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			params: map[string]interface{}{
 | 
			
		||||
				"name":  "foo",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user