如何使用Python Docker SDK的exec_run向容器传递文件?
解决Python Docker SDK通过exec_run传递备份文件到PostgreSQL容器的问题
你的问题核心在于误解了docker exec -i的工作逻辑,以及如何用Docker SDK复现它。让我一步步拆解:
为什么你的代码会报错?
你原来的代码:
containers[0].exec_run("/bin/bash -c 'pg_restore -C -d postgres <'" + filename, ...)
这里的问题有两个:
- 你让PostgreSQL容器内的bash尝试读取
filename路径,但这个文件只存在于运行Python的容器里,PostgreSQL容器根本访问不到这个路径,所以会报No such file or directory。 - 原
docker exec -i命令里的< 文件名是把宿主机(或你的Python容器)的文件内容作为标准输入传给容器内的pg_restore,而不是让容器去读取某个文件路径。
正确的实现方式:通过stdin传递文件内容
要复现docker exec -i ... < 文件名的效果,你需要在Python容器里先读取备份文件的内容,然后通过exec_run的stdin参数把内容直接传给PostgreSQL容器内的pg_restore进程。这样就不需要把文件复制到PostgreSQL容器里,也不需要解压操作。
示例代码:
# 1. 先在当前Python容器内读取备份文件的二进制内容 backup_file_path = "./2019-04-29-postgres_db.dump" with open(backup_file_path, 'rb') as backup_file: backup_content = backup_file.read() # 2. 调用exec_run,直接执行pg_restore并传入stdin内容 exec_result = containers[0].exec_run( # 直接指定pg_restore命令和参数,不需要bash转义 ["pg_restore", "-C", "-d", "postgres"], user="postgres", stdin=backup_content, # 把文件内容作为标准输入传递 stdout=True, stderr=True ) # 3. 处理执行结果 stdout_output = exec_result[0].decode("utf-8") stderr_output = exec_result[1].decode("utf-8") print("执行输出:") print(stdout_output) if stderr_output: print("错误信息:") print(stderr_output)
为什么这个方法可行?
这个实现和你原来的docker exec命令逻辑完全一致:
- 原命令
docker exec -i -u postgres <容器ID> pg_restore -C -d postgres < 文件名中,< 文件名是将宿主机文件的内容通过标准输入流发送给容器内的pg_restore。 - 上面的Python代码则是在Python容器里读取文件内容,再通过Docker SDK的
stdin参数把这个内容传递给PostgreSQL容器内的pg_restore进程,完全模拟了原命令的输入逻辑。
关于put_archive的补充
如果用put_archive,确实需要把文件打包成tar包传到容器里再解压,步骤更繁琐。而通过stdin传递内容的方式更直接,完全匹配你想要复现的docker exec命令的行为,是更简便的方案。
内容的提问来源于stack exchange,提问作者el323




