Merge pull request #4174 from vbatts/vbatts-env_file

support for `docker run` environment variables file
This commit is contained in:
Michael Crosby 2014-03-31 12:01:14 -07:00
commit b45c1061bf
3 changed files with 120 additions and 1 deletions

View file

@ -1152,6 +1152,7 @@ image is removed.
--cidfile="": Write the container ID to the file
-d, --detach=false: Detached mode: Run container in the background, print new container id
-e, --env=[]: Set environment variables
--env-file="": Read in a line delimited file of ENV variables
-h, --hostname="": Container host name
-i, --interactive=false: Keep stdin open even if not attached
--privileged=false: Give extended privileges to this container
@ -1284,6 +1285,54 @@ This exposes port ``80`` of the container for use within a link without
publishing the port to the host system's interfaces. :ref:`port_redirection`
explains in detail how to manipulate ports in Docker.
.. code-block:: bash
$ sudo docker run -e MYVAR1 --env MYVAR2=foo --env-file ./env.list ubuntu bash
This sets environmental variables in the container. For illustration all three
flags are shown here. Where ``-e``, ``--env`` take an environment variable and
value, or if no "=" is provided, then that variable's current value is passed
through (i.e. $MYVAR1 from the host is set to $MYVAR1 in the container). All
three flags, ``-e``, ``--env`` and ``--env-file`` can be repeated.
Regardless of the order of these three flags, the ``--env-file`` are processed
first, and then ``-e``/``--env`` flags. This way, the ``-e`` or ``--env`` will
override variables as needed.
.. code-block:: bash
$ cat ./env.list
TEST_FOO=BAR
$ sudo docker run --env TEST_FOO="This is a test" --env-file ./env.list busybox env | grep TEST_FOO
TEST_FOO=This is a test
The ``--env-file`` flag takes a filename as an argument and expects each line
to be in the VAR=VAL format, mimicking the argument passed to ``--env``.
Comment lines need only be prefixed with ``#``
An example of a file passed with ``--env-file``
.. code-block:: bash
$ cat ./env.list
TEST_FOO=BAR
# this is a comment
TEST_APP_DEST_HOST=10.10.0.127
TEST_APP_DEST_PORT=8888
# pass through this variable from the caller
TEST_PASSTHROUGH
$ sudo TEST_PASSTHROUGH=howdy docker run --env-file ./env.list busybox env
HOME=/
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=5198e0745561
TEST_FOO=BAR
TEST_APP_DEST_HOST=10.10.0.127
TEST_APP_DEST_PORT=8888
TEST_PASSTHROUGH=howdy
.. code-block:: bash
$ sudo docker run --name console -t -i ubuntu bash

54
opts/envfile.go Normal file
View file

@ -0,0 +1,54 @@
package opts
import (
"bufio"
"fmt"
"os"
"strings"
)
/*
Read in a line delimited file with environment variables enumerated
*/
func ParseEnvFile(filename string) ([]string, error) {
fh, err := os.Open(filename)
if err != nil {
return []string{}, err
}
defer fh.Close()
lines := []string{}
scanner := bufio.NewScanner(fh)
for scanner.Scan() {
line := scanner.Text()
// line is not empty, and not starting with '#'
if len(line) > 0 && !strings.HasPrefix(line, "#") {
if strings.Contains(line, "=") {
data := strings.SplitN(line, "=", 2)
// trim the front of a variable, but nothing else
variable := strings.TrimLeft(data[0], whiteSpaces)
if strings.ContainsAny(variable, whiteSpaces) {
return []string{}, ErrBadEnvVariable{fmt.Sprintf("variable '%s' has white spaces", variable)}
}
// pass the value through, no trimming
lines = append(lines, fmt.Sprintf("%s=%s", variable, data[1]))
} else {
// if only a pass-through variable is given, clean it up.
lines = append(lines, fmt.Sprintf("%s=%s", strings.TrimSpace(line), os.Getenv(line)))
}
}
}
return lines, nil
}
var whiteSpaces = " \t"
type ErrBadEnvVariable struct {
msg string
}
func (e ErrBadEnvVariable) Error() string {
return fmt.Sprintf("poorly formatted environment: %s", e.msg)
}

View file

@ -52,6 +52,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
flVolumesFrom opts.ListOpts
flLxcOpts opts.ListOpts
flDriverOpts opts.ListOpts
flEnvFile opts.ListOpts
flAutoRemove = cmd.Bool([]string{"#rm", "-rm"}, false, "Automatically remove the container when it exits (incompatible with -d)")
flDetach = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: Run container in the background, print new container id")
@ -78,6 +79,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
cmd.Var(&flVolumes, []string{"v", "-volume"}, "Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)")
cmd.Var(&flLinks, []string{"#link", "-link"}, "Add link to another container (name:alias)")
cmd.Var(&flEnv, []string{"e", "-env"}, "Set environment variables")
cmd.Var(&flEnvFile, []string{"-env-file"}, "Read in a line delimited file of ENV variables")
cmd.Var(&flPublish, []string{"p", "-publish"}, fmt.Sprintf("Publish a container's port to the host (format: %s) (use 'docker port' to see the actual mapping)", nat.PortSpecTemplateFormat))
cmd.Var(&flExpose, []string{"#expose", "-expose"}, "Expose a port from the container without publishing it to your host")
@ -199,6 +201,20 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
}
}
// collect all the environment variables for the container
envVariables := []string{}
for _, ef := range flEnvFile.GetAll() {
parsedVars, err := opts.ParseEnvFile(ef)
if err != nil {
return nil, nil, cmd, err
}
envVariables = append(envVariables, parsedVars...)
}
// parse the '-e' and '--env' after, to allow override
envVariables = append(envVariables, flEnv.GetAll()...)
// boo, there's no debug output for docker run
//utils.Debugf("Environment variables for the container: %#v", envVariables)
config := &Config{
Hostname: hostname,
Domainname: domainname,
@ -213,7 +229,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
AttachStdin: flAttach.Get("stdin"),
AttachStdout: flAttach.Get("stdout"),
AttachStderr: flAttach.Get("stderr"),
Env: flEnv.GetAll(),
Env: envVariables,
Cmd: runCmd,
Dns: flDns.GetAll(),
DnsSearch: flDnsSearch.GetAll(),