I have a python code for testing my docker images.
import docker
client = docker.from_env()
container = client.containers.run("my_image", ["python --version"], auto_remove = True)
print("done!")
I get the following error:
Traceback (most recent call last):
File "/home/user1/miniconda3/envs/py_test/lib/python3.10/site-packages/docker/api/client.py", line 268, in _raise_for_status
response.raise_for_status()
File "/home/user1/miniconda3/envs/py_test/lib/python3.10/site-packages/requests/models.py", line 960, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: http docker://localhost/v1.41/containers/19b94bfbebc0dbaaf2864b8cc72d1c597fe108a3ddd9bf45b58b8d3c825cb3e6/start
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/user1/tmp_python/test.py", line 5, in <module>
container = client.containers.run("my_image", ["python --version"], auto_remove = True)
File "/home/user1/miniconda3/envs/py_test/lib/python3.10/site-packages/docker/models/containers.py", line 826, in run
container.start()
File "/home/user1/miniconda3/envs/py_test/lib/python3.10/site-packages/docker/models/containers.py", line 404, in start
return self.client.api.start(self.id, **kwargs)
File "/home/user1/miniconda3/envs/py_test/lib/python3.10/site-packages/docker/utils/decorators.py", line 19, in wrapped
return f(self, resource_id, *args, **kwargs)
File "/home/user1/miniconda3/envs/py_test/lib/python3.10/site-packages/docker/api/container.py", line 1109, in start
self._raise_for_status(res)
File "/home/user1/miniconda3/envs/py_test/lib/python3.10/site-packages/docker/api/client.py", line 270, in _raise_for_status
raise create_api_error_from_http_exception(e)
File "/home/user1/miniconda3/envs/py_test/lib/python3.10/site-packages/docker/errors.py", line 31, in create_api_error_from_http_exception
raise cls(e, response=response, explanation=explanation)
docker.errors.APIError: 400 Client Error for http docker://localhost/v1.41/containers/19b94bfbebc0dbaaf2864b8cc72d1c597fe108a3ddd9bf45b58b8d3c825cb3e6/start: Bad Request ("failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "python --version": executable file not found in $PATH: unknown")
however, when I run manually my image, I can get the python version:
docker run -it my_image
(base) root@6f9d163cc547:/# python --version
Python 3.9.12
(base) root@6f9d163cc547:/# exit
exit
CodePudding user response:
This error:
unable to start container process: exec: "python --version": executable file not found in $PATH: unknown")
Means you should be passing a list of arguments:
client.containers.run('myimage', ['python', '--version'])
Or a single string:
client.containers.run('myimage', 'python --version')
With your current code, Docker is trying to find an executable file named literally python --version
. This is exactly what you see with RUN
and CMD
statements in a Dockerfile
: a single string is executed using /bin/sh -c
, while a list argument is executed directly (e.g., passed as arguments to execve()
).
This works just fine:
import docker
client = docker.from_env()
container = client.containers.run('docker.io/python:3', ['python', '--version'])
print("done!")
I find that in my setup, using auto_remove=True
results in a different error, but that's unrelated to what you show in your question. @KrerkkiatChusap has some suggestions for that issue in their answer.
CodePudding user response:
You code seems to be
container = client.containers.run("my_image", ["python --version"], auto_remove = True)
container.start()
The docker run
command will create and start the container, so there is no need for container.start()
.
The next problem is then when auto_remove=True
, the container will be destroyed after it finished the execution, and the library have a hard time obtaining the output from destroyed container. Also, without detach=True
, the output (byte) will be returned instead of a container object (so calling .start()
on it will not make sense).
Instead, you can obtain the handle with detach=True
and manually remove the container after you get the output with container.logs()
.
import docker
client = docker.from_env()
# The command here is implicitly fixed by larsks' answer.
container = client.containers.run("my_image", ["python", "--version"], detach=True)
output_bytes = container.logs()
# Since the container is already exited, you can skip the `.stop()`.
container.remove()