Running a longer command from docker

2019-06-19 08:16发布

问题:

I am using Docker to write a file on the fly and run it. The command looks like this so far (just to test the idea first):

docker run dockerfile/python cat <<EOF >hi.txt && tail hi.txt
> hi there
> EOF

For some reason this does not echo anything.

If I run this command without a HEREDOC then it does output the result. For example the following works:

docker run dockerfile/python cat > hi.txt && ls
hi.txt

How do I output the result of a multi line run command/HEREDOC.

回答1:

I'm curious, what shell are you using so that the second command works? Because in bash the hi.txt is created on the host and so is the ls.

bash-3.2$ docker run --rm dockerfile/python cat > hi.txt && ls
Applications    Desktop     Documents   Downloads   Dropbox     Library     Movies      Music       Pictures    Public      VirtualBox VMs  hi.txt      projects

To achieve that, I'd have to use:

docker run --rm dockerfile/python bash -c 'cat > hi.txt && ls'

IMO, the simplest way to test stuff is to just use a container as a sandbox:

docker run -it dockerfile/python bash

And then just do stuff in that container's shell. Once I got things running well, I backport what I've done in a Dockerfile.



回答2:

I was fiddling with crossbuild* and was wondering about how to use here documents to pipe commands to a Docker container. Here's the solution.

$ docker run --rm --interactive --volume $(pwd):/workdir --env CROSS_TRIPLE=x86_64-apple-darwin multiarch/crossbuild /bin/bash -s <<EOF
mkdir build && cd build
cmake ..
make
EOF

Quick rundown of what's happening.

  • --rm tells Docker to remove the container when it finished execution, otherwise it would show up in the output docker ps -a (not mandatory to use of course)
  • --interactive, -i is needed, otherwise /bin/bash would not run in an interactive environment and would not accept the here document from stdin as its input
  • about the -s flag passed to /bin/bash

    If the -s option is present, or if no arguments remain after option processing, then commands are read from the standard input.

  • --volume $(pwd):/workdir, just -v will mount the current working directory on the host to /workdir in the container
  • --env CROSS_TRIPLE=x86_64-apple-darwin, or simple -e tells the crossbuild container about the target platform and architecture (the container's entry point is /usr/bin/crossbuild, which is a shell script and based on the environment variable it's symlink the right toolchain components to the right places for the cross compilation to work)
  • multiarch/crossbuild the name of the Docker container to run (available in Docker Hub)

The commands can be fed to Docker like this as well.

$ cat a.sh
mkdir build && cd build
cmake ..
make
$ docker run --rm -i -v $(pwd):/workdir -e CROSS_TRIPLE=x86_64-apple-darwin multiarch/crossbuild /bin/bash -s < a.sh

Hoped this helps.

Update

Actually it seems you don't even need to use /bin/bash -s, it can be ommited, at least for the crossbuild container, YMMV.

*Linux based container used to produce multi-arch binaries: Linux, Windows and OS X, very cool.