简体   繁体   中英

Using pipes with docker-py

In the example at https://github.com/docker/docker-py , they return the results of a command to a docker image as so:

>>> client.containers.run("ubuntu:latest", "echo hello world")
'hello world\n'

What I want is to use a pipe - for instance, it would be great if I could do this:

>>> client.containers.run("ubuntu:latest", "echo hello world | wc")
'       1       2      12\n'

However, instead I get this:

 >>> client.containers.run("ubuntu:latest", "echo hello world | wc")
    b'hello world | wc\n'

What is the easiest way to run two commands, the second piped from the first, in docker?

Whenever you use a shell construct such as $ENV_VAR , | , etc, make sure you actually have a shell to interpret them or they'll have their literal values, To see why your invocation lacks a shell, you have to understand docker ENTRYPOINT and CMD .

If you look at the dockerfile for ubuntu:latest ,you'll see that it is

FROM scratch

And the file doesn't set an ENTRYPOINT , only a CMD . Read What is the difference between CMD and ENTRYPOINT in a Dockerfile? for some good looking info about the difference. Suffice it to say that in your case everything after the image name replaces the cmd .

The doc for containers.run() says command can be a str or list . From that, and from observed behavior, we can infer the command string will be split on whitespace to create a list of arguments for the docker exec.

So, the answer, in short, is because | is a shell construct but you're executing no shell. There's a few ways to add a shell into the equation. The most obvious is to run the shell directly:

>>> client.containers.run("ubuntu:latest", "bash -c 'echo hello world | wc'",)
'      1       2      12\n'

But you could also set the entrypoint to a shell, which is commonly done in general purpose containers (though notice you still have to make sure that -c is provided, and the entire shell command must be enquoted as before. The entrypoint only provides the executable, not any arguments).

>>> client.containers.run("ubuntu:latest", "-c 'echo hello world | wc'", entrypoint="bash")
'      1       2      12\n'

The command line does the same thing with the standard input field separator:

$ docker run --rm -it ubuntu:latest echo hello world \| wc
hello world | wc

If we enquote the whole thing we defeat the automatic splitting around the input field separator:

$ docker run --rm -it ubuntu:latest "echo hello world \| wc"
docker: Error response from daemon: OCI runtime create failed: container_linux.go:345: starting container process caused "exec: \"echo hello world \\\\| wc\": executable file not found in $PATH": unknown.

The python equivalent is:

>>> client.containers.run("ubuntu:latest",["echo hello world \\|"])
Traceback (most recent call last):
  [... traceback omitted for brevity ...]
docker.errors.APIError: 500 Server Error: Internal Server Error ("OCI runtime create failed: container_linux.go:345: starting container process caused "exec: \"echo hello world \\\\|\": executable file not found in $PATH": unknown")

It is simply:

client.containers.run("ubuntu:latest", "sh -c 'echo hello world | wc'")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM