从Docker镜像执行Capistrano部署时forward_agent密钥认证失败问题
问题:容器化Ruby环境下Capistrano部署时,部署目标服务器无法连接Bitbucket
我用Capistrano部署静态网站(静态页面由Ruby工具生成),目前正切换到容器化Ruby环境替代本地Ruby安装。
我的容器配置如下:
- Dockerfile创建了用户
dockerguy,UID/GID和本地用户一致,同时将本地用户的.ssh目录映射到容器内dockerguy的主目录,理论上可共用SSH密钥
docker-compose.yml
services: app: container_name: <project>-ruby build: context: . dockerfile: Dockerfile no_cache: true shm_size: 128mb ports: - 4567:4567 volumes: - .:/app - ~/.ssh:/home/dockerguy/.ssh tty: true
Dockerfile
FROM ruby:3.4 # 这两个值和我的本地用户一致(后续会改成非硬编码) ARG UID=501 ARG GID=20 WORKDIR /app RUN apt update RUN apt --assume-yes install nodejs RUN adduser --uid $UID --gid $GID --disabled-password --gecos "" dockerguy \ && echo 'nonroot ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers USER dockerguy
执行bundle exec cap production deploy时,能正常连接部署目标服务器,但部署目标服务器与Bitbucket仓库的连接失败,报错信息如下:
INFO [2f3b6a35] Running /usr/bin/env git ls-remote git@bitbucket.org:<user>/<reponame>.git HEAD on <deploy-target> DEBUG [2f3b6a35] Command: ( export GIT_ASKPASS="/bin/echo" GIT_SSH="/tmp/git-ssh-0056b902611677dcfbca.sh" ; /usr/bin/env git ls-remote git@bitbucket.org:<user>/<reponame>.git HEAD ) DEBUG [2f3b6a35] Error reading response length from authentication socket. DEBUG [2f3b6a35] Permission denied (publickey). DEBUG [2f3b6a35] fatal: The remote end hung up unexpectedly
我的Capistrano配置已启用forward_agent:
# config/deploy/production.rb [...] server '<deploy-target>', roles: %w{web db app}, ssh_options: { user: <username-on-deploy-target>, forward_agent: true, auth_methods: %w(publickey) }
请问部署目标与Bitbucket的连接为何失败?
问题分析与解决思路
这是SSH代理转发未正确穿透容器层导致的问题,具体原因和修复步骤如下:
1. 核心原因
虽然你挂载了本地.ssh目录到容器,但Capistrano的代理转发依赖容器能访问本地主机的SSH代理套接字,而非仅共享密钥文件。当前容器内的dockerguy用户无法连接本地ssh-agent,导致部署目标服务器无法通过代理获取你的本地密钥访问Bitbucket。
2. 验证步骤
进入容器内部,检查SSH代理环境变量:
# 进入容器 docker-compose exec app bash # 查看代理套接字路径 echo $SSH_AUTH_SOCK
若输出为空,说明容器未继承本地SSH_AUTH_SOCK环境变量,代理转发无法工作。
3. 修复方案
方案一:挂载SSH代理套接字到容器
修改docker-compose.yml,添加代理套接字挂载与环境变量配置:
services: app: # 保留原有配置 volumes: - .:/app - ~/.ssh:/home/dockerguy/.ssh # 挂载本地SSH代理套接字 - ${SSH_AUTH_SOCK}:/ssh-agent # 告诉容器代理套接字位置 environment: - SSH_AUTH_SOCK=/ssh-agent
方案二:修复容器内SSH权限
检查容器内.ssh目录及密钥文件权限:
docker-compose exec app ls -l /home/dockerguy/.ssh/
确保.ssh目录权限为700,密钥文件(如id_rsa)权限为600,若权限错误,在容器内执行:
chmod 700 /home/dockerguy/.ssh chmod 600 /home/dockerguy/.ssh/id_rsa
方案三:确认本地SSH代理状态
本地主机需确保ssh-agent已启动且密钥已加载:
# 启动代理 eval "$(ssh-agent -s)" # 添加密钥 ssh-add ~/.ssh/id_rsa # 验证密钥是否加载 ssh-add -l
4. 额外优化建议
- macOS用户需注意:Docker Desktop默认允许容器访问本地代理,但需确保
SSH_AUTH_SOCK路径正确(通常为/private/tmp/com.apple.launchd.xxxx/Listeners) - 避免硬编码UID/GID,后续可通过
docker-compose.yml动态传递:build: args: UID: ${UID} GID: ${GID}
内容的提问来源于stack exchange,提问作者Grant Birchmeier
相关产品推荐
相关产品推荐

