Docker Python SDK中container.start()启动后立即退出问题求助
问题描述
我想用Docker Python SDK创建Docker容器,对应的可正常运行的CLI命令如下(镜像入口为/bin/bash):
docker container create --name <container_name> -i --mount source=<src>,target=/project_data <image_name> docker container start -i <container_name>
但通过Python SDK创建并启动容器后,容器会立即退出,导致执行container.exec_run()时出现容器未运行的错误。我尝试过以下代码:
container = client.containers.run("<image_name>", name="<container_name>", detach=True, volumes=volumes)
无法以分离模式保持容器运行,我的目标是在同一容器实例中执行多条命令,例如:
result = container.exec_run('ls') result = container.exec_run('./run_scripts > out.txt') result = container.exec_run('./run_scripts_2 > out.txt') # 一些数据处理 ... <省略> ... # 执行更多脚本 result = container.exec_run('./run_scripts_3 > out.txt')
调用container.start()时,容器启动后很快退出,执行exec_run时出现如下错误:
--------------------------------------------------------------------------- HTTPError Traceback (most recent call last) File ~/miniconda3/envs/foldynamics/lib/python3.8/site-packages/docker/api/client.py:268, in APIClient._raise_for_status(self, response) 267 try: --> 268 response.raise_for_status() 269 except requests.exceptions.HTTPError as e: File ~/miniconda3/envs/foldynamics/lib/python3.8/site-packages/requests/models.py:1021, in Response.raise_for_status(self) 1020 if http_error_msg: --> 1021 raise HTTPError(http_error_msg, response=self) HTTPError: 409 Client Error: Conflict for url: http+docker://localhost/v1.41/containers/43cb7fd5549053bf426ed3d39c1d4f5a982d329f7483e890604d0d5b2a38f7b1/exec The above exception was the direct cause of the following exception: APIError Traceback (most recent call last) Cell In[87], line 1 ----> 1 result = container.exec_run("echo pwd", tty=True, detach=True) File ~/miniconda3/envs/foldynamics/lib/python3.8/site-packages/docker/models/containers.py:193, in Container.exec_run(self, cmd, stdout, stderr, stdin, tty, privileged, user, detach, stream, socket, environment, workdir, demux) 152 def exec_run(self, cmd, stdout=True, stderr=True, stdin=False, tty=False, 153 privileged=False, user='', detach=False, stream=False, 154 socket=False, environment=None, workdir=None, demux=False): 155 """ 156 Run a command inside this container. Similar to 157 ``docker exec``. (...) 191 If the server returns an error. 192 """ --> 193 resp = self.client.api.exec_create( 194 self.id, cmd, stdout=stdout, stderr=stderr, stdin=stdin, tty=tty, 195 privileged=privileged, user=user, environment=environment, 196 workdir=workdir, 197 ) 198 exec_output = self.client.api.exec_start( 199 resp['Id'], detach=detach, tty=tty, stream=stream, socket=socket, 200 demux=demux 201 ) 202 if socket or stream: File ~/miniconda3/envs/foldynamics/lib/python3.8/site-packages/docker/utils/decorators.py:19, in check_resource.<locals>.decorator.<locals>.wrapped(self, resource_id, *args, **kwargs) 15 if not resource_id: 16 raise errors.NullResource( 17 'Resource ID was not provided' 18 ) --> 19 return f(self, resource_id, *args, **kwargs) File ~/miniconda3/envs/foldynamics/lib/python3.8/site-packages/docker/api/exec_api.py:78, in ExecApiMixin.exec_create(self, container, cmd, stdout, stderr, stdin, tty, privileged, user, environment, workdir, detach_keys) 76 url = self._url('/containers/{0}/exec', container) 77 res = self._post_json(url, data=data) --> 78 return self._result(res, True) File ~/miniconda3/envs/foldynamics/lib/python3.8/site-packages/docker/api/client.py:274, in APIClient._result(self, response, json, binary) 272 def _result(self, response, json=False, binary=False): 273 assert not (json and binary) --> 274 self._raise_for_status(response) 276 if json: 277 return response.json() File ~/miniconda3/envs/foldynamics/lib/python3.8/site-packages/docker/api/client.py:270, in APIClient._raise_for_status(self, response) 268 response.raise_for_status() 269 except requests.exceptions.HTTPError as e: --> 270 raise create_api_error_from_http_exception(e) from e File ~/miniconda3/envs/foldynamics/lib/python3.8/site-packages/docker/errors.py:39, in create_api_error_from_http_exception(e) 37 else: 38 cls = NotFound --> 39 raise cls(e, response=response, explanation=explanation) from e APIError: 409 Client Error for http+docker://localhost/v1.41/containers/43cb7fd5549053bf426ed3d39c1d4f5a982d329f7483e890604d0d5b2a38f7b1/exec: Conflict ("Container 43cb7fd5549053bf426ed3d39c1d4f5a982d329f7483e890604d0d5b2a38f7b1 is not running")
解决方案
容器启动后立即退出的核心原因是没有持续运行的前台进程。CLI中-i参数会保持标准输入打开,让bash维持前台运行;但SDK默认不会自动配置这些参数,需要显式指定。
方法一:模拟CLI的create+start流程
先创建容器并配置终端和标准输入,再启动:
# 定义卷映射,替换为你的实际路径 volumes = { '<src>': {'bind': '/project_data', 'mode': 'rw'} } # 创建容器,对应CLI的create命令 container = client.containers.create( image="<image_name>", name="<container_name>", volumes=volumes, tty=True, # 分配伪终端,对应CLI的-t参数 stdin_open=True, # 保持标准输入打开,对应CLI的-i参数 command="/bin/bash" # 显式指定bash作为运行命令 ) # 启动容器 container.start()
方法二:用run命令直接创建并保持运行
如果偏好使用containers.run,需同时配置tty、stdin_open和detach=True:
container = client.containers.run( "<image_name>", name="<container_name>", volumes=volumes, detach=True, tty=True, stdin_open=True, command="/bin/bash" )
容器保持运行后,即可正常执行多条exec_run命令:
# 执行目录查看命令 result = container.exec_run('ls') print(result.output.decode()) # 执行脚本并重定向输出 container.exec_run('./run_scripts > out.txt') # 数据处理完成后执行后续脚本 container.exec_run('./run_scripts_3 > out.txt')
额外提示
- 替换代码中的
<image_name>、<container_name>和<src>为你的实际值 - 若不需要交互,也可使用
tail -f /dev/null作为容器启动命令,但后续exec_run可能需要显式指定工作目录 - 操作完成后记得清理容器:
container.stop() container.remove()
内容的提问来源于stack exchange,提问作者Ido
相关产品推荐
相关产品推荐

