如何从Docker容器内执行SCP命令向外部服务器传输文件?
问题根源与解决方案
出现Host key verification failed错误,核心原因是Docker容器是全新的隔离环境,和本地IDE环境存在三个关键差异:
1. 容器无目标服务器的主机密钥记录
本地环境首次连接外部服务器时,已经确认过主机密钥并存在~/.ssh/known_hosts中,但容器是全新环境,非交互式下无法手动确认密钥,导致scp连接失败。
解决办法:
方案一(推荐生产环境):提前生成包含目标主机密钥的文件
在本地执行命令生成known_hosts文件:ssh-keyscan external_ip >> known_hosts然后在
docker-compose.yaml中挂载该文件到容器的对应目录:version: '3.9' services: python-scp: container_name: python-scp image: python-scp:latest volumes: - ./known_hosts:/root/.ssh/known_hosts # 若容器用非root用户,替换为对应用户的.ssh路径 networks: - my-bridge networks: my-bridge: external: true name: my-bridge方案二(仅测试用):临时跳过主机密钥验证
修改Python脚本中的scp命令,添加参数关闭验证:success = os.system("scp -o StrictHostKeyChecking=no -i id_rsa my_file username@external_ip:/tmp/")
2. 容器内无法访问私钥和待传输文件
本地IDE能直接读取id_rsa和my_file,但容器是隔离环境,这些文件默认不会自动进入容器。
解决办法:
在docker-compose.yaml中添加volume挂载,把本地文件映射到容器内的对应路径:
version: '3.9' services: python-scp: container_name: python-scp image: python-scp:latest volumes: - ./id_rsa:/app/id_rsa # 替换为容器内脚本实际读取的路径 - ./my_file:/app/my_file # 同上,和脚本中的路径保持一致 networks: - my-bridge networks: my-bridge: external: true name: my-bridge
同时修改Python脚本中的路径,确保和容器内挂载路径匹配:
success = os.system("scp -i /app/id_rsa /app/my_file username@external_ip:/tmp/")
3. 私钥权限不符合scp要求
scp强制要求私钥文件权限为600(仅所有者可读可写),否则会拒绝使用。容器内挂载的文件可能继承了本地的宽松权限,导致报错。
解决办法:
方式一:Dockerfile中设置权限
在构建镜像的Dockerfile中添加命令:FROM python:3.11 COPY id_rsa /app/id_rsa RUN chmod 600 /app/id_rsa # 其他构建步骤方式二:启动时动态修改
在Python脚本执行scp命令前,先修改权限:os.system("chmod 600 /app/id_rsa") success = os.system("scp -i /app/id_rsa /app/my_file username@external_ip:/tmp/")
额外检查项
- 确认容器所在的
my-bridge网络能访问外部服务器的22端口,可进入容器执行telnet external_ip 22测试连通性; - 若容器使用非root用户运行,需确保该用户的
~/.ssh目录权限为700,避免ssh/scp权限报错。
内容的提问来源于stack exchange,提问作者MrPallaBall
相关产品推荐
相关产品推荐

