Write to stdin of running docker container
Asked Answered
S

2

11

Say I run a docker container as a daemon:

docker run -d foo

is there a way to write to the stdin of that container? Something like:

docker exec -i foo echo 'hi'

last time I checked the -i and -d flags were mutually exclusive when used with the docker run command.

Snorter answered 21/1, 2020 at 2:8 Comment(2)
The canonical answer is to use socat. Please look at the following question on serverfault for details: serverfault.com/questions/885765Erkan
can you add an answer here? I will upvote just tag me, thxSnorter
L
6

In principle you can docker attach to it. CTRL+C will stop the container (by sending SIGINT to the process); CTRL+P, CTRL+Q will detach from it and leave it running (if you started the container with docker run -it).

The one trick here is that docker attach expects to be running in a terminal of some sort; you can do something like run it under script to meet this requirement. Here's an example:

# Create a new empty directory
mkdir x

# Run a container, in the background, that copies its stdin
# to a file in that directory
docker run -itd -v $PWD/x:/x --name cat busybox sh -c 'cat >/x/y'

# Send a string in
echo foo | script -q /dev/null docker attach cat
# Note, EOF here stops the container, probably because /bin/cat
# exits normally

# Clean up
docker rm cat

# See what we got out
cat x/y

In practice, if the main way a program communicates is via text on its standard input and standard output, Docker isn't a great packaging mechanism for it. In higher-level environments like Docker Compose or Kubernetes, it becomes progressively harder to send content this way, and there's frequently an assumption that a container can run completely autonomously. Just invoking the program gets complicated quickly (as this question hints at). If you have something like, say, the create-react-app setup tool that asks a bunch of interactive questions then writes things to the host filesystem, it will be vastly easier to run it directly on the host and not in Docker.

Lawton answered 21/1, 2020 at 10:44 Comment(3)
so like echo 'david left this part out' | docker attach c or ? I am talking more of a script and less of an interactive shell.Snorter
I’ve seen examples of people doing echo foo | docker run --rm -it ... | grep ... before and I sort of expect ... | docker attach will work, but I don’t have an example off hand.Lawton
i will give you a big green checkmark and 20 USD if you can find a docker attach example, I already upvoted soSnorter
E
11

According to another answer on ServerFault, you can use socat to pipe input to a docker container like this:

echo 'hi' | socat EXEC:"docker attach container0",pty STDIN

Note that the echo command includes a newline at the end of the output, so the line above actually sends hi\n. Use echo -n if you don't want a newline.


Let's see how this looks like with the example script from David's answer:

# Create a new empty directory
mkdir x

# Run a container, in the background, that copies its stdin
# to a file in that directory
docker run -itd --rm -v $PWD/x:/x --name cattainer busybox sh -c 'cat >/x/y'

# Send some strings in
echo 'hi' | socat EXEC:"docker attach cattainer",pty STDIN
echo 'still there?' | socat EXEC:"docker attach cattainer",pty STDIN

# Stop container (cleans up itself because of --rm)
docker stop cattainer

# See what we got out
cat x/y

# should output:
# hi
# still there?

You could also wrap it in a shell function:

docker_send() {
    container="$1"; shift
    echo "$@" | socat EXEC:"docker attach $container",pty STDIN
}

docker_send cattainer "Hello cat!"
docker_send cattainer -n "No newline here:"    # flag -n is passed to echo

Trivia: I'm actually using this approach to control a Terraria server running in a docker container, because TerrariaServer.exe only accepts server commands (like save or exit) on stdin.

Erkan answered 1/6, 2020 at 22:33 Comment(2)
Does this method wait for the docker container to finish doing its thing before continuing on to the next line, or does it just run through those steps asynchronously?Middleaged
@Logan: It just sends the text to the stdin of the container. The function docker_send returns as soon as the echo | socat pipeline terminates. In order to wait, you would first have to specify exactly what you mean by the container "doing its thing". For example, waiting for some output on the stdout of the running process.Erkan
L
6

In principle you can docker attach to it. CTRL+C will stop the container (by sending SIGINT to the process); CTRL+P, CTRL+Q will detach from it and leave it running (if you started the container with docker run -it).

The one trick here is that docker attach expects to be running in a terminal of some sort; you can do something like run it under script to meet this requirement. Here's an example:

# Create a new empty directory
mkdir x

# Run a container, in the background, that copies its stdin
# to a file in that directory
docker run -itd -v $PWD/x:/x --name cat busybox sh -c 'cat >/x/y'

# Send a string in
echo foo | script -q /dev/null docker attach cat
# Note, EOF here stops the container, probably because /bin/cat
# exits normally

# Clean up
docker rm cat

# See what we got out
cat x/y

In practice, if the main way a program communicates is via text on its standard input and standard output, Docker isn't a great packaging mechanism for it. In higher-level environments like Docker Compose or Kubernetes, it becomes progressively harder to send content this way, and there's frequently an assumption that a container can run completely autonomously. Just invoking the program gets complicated quickly (as this question hints at). If you have something like, say, the create-react-app setup tool that asks a bunch of interactive questions then writes things to the host filesystem, it will be vastly easier to run it directly on the host and not in Docker.

Lawton answered 21/1, 2020 at 10:44 Comment(3)
so like echo 'david left this part out' | docker attach c or ? I am talking more of a script and less of an interactive shell.Snorter
I’ve seen examples of people doing echo foo | docker run --rm -it ... | grep ... before and I sort of expect ... | docker attach will work, but I don’t have an example off hand.Lawton
i will give you a big green checkmark and 20 USD if you can find a docker attach example, I already upvoted soSnorter

© 2022 - 2024 — McMap. All rights reserved.