GitLab CI/CD中SSH连接建立后立即断开的解决求助
GitLab CI/CD 保持SSH连接复用及rsync权限问题解决
问题根源
每个GitLab CI脚本中的命令都是独立的Shell进程,单独执行ssh user@host "command"只会在当前进程中建立临时SSH会话,命令执行完毕后会话立即关闭,后续命令自然回到gitlab-runner环境。而rsync出现权限拒绝,本质是rsync发起的新SSH连接未正确配置认证信息,并非之前的连接没有保持。
解决方案
1. 配置SSH连接复用(控制套接字)
通过SSH的ControlMaster特性创建持久连接,让后续的ssh/rsync命令复用同一个会话:
script: # 创建控制套接字存储目录 - mkdir -p ~/.ssh/controlmasters # 建立持久控制连接,保持10分钟 - ssh -o ControlMaster=yes -o ControlPath=~/.ssh/controlmasters/%r@%h:%p -o ControlPersist=10m myssh_user@$SSH_KNOWN_HOSTS_DEPLOY "whoami && ls" # rsync复用已建立的连接 - rsync -avz -e "ssh -o ControlPath=~/.ssh/controlmasters/%r@%h:%p" $CI_PROJECT_DIR/app_root myssh_user@$SSH_KNOWN_HOSTS_DEPLOY:/directory/to/copy/the/files # 主动关闭控制连接 - ssh -o ControlPath=~/.ssh/controlmasters/%r@%h:%p -O exit myssh_user@$SSH_KNOWN_HOSTS_DEPLOY
参数说明:
ControlMaster=yes:开启主连接模式ControlPath:指定连接套接字的存储路径,%r@%h:%p自动替换为用户名、主机、端口ControlPersist=10m:让主连接在最后一次使用后保持10分钟
2. 确保SSH认证信息正确配置
rsync权限拒绝的核心原因是CI环境中未正确加载SSH私钥,需在before_script中完成密钥初始化:
before_script: # 启动ssh-agent - eval $(ssh-agent -s) # 添加私钥(需在GitLab CI/CD变量中配置SSH_PRIVATE_KEY) - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - # 配置known_hosts(需在GitLab CI/CD变量中配置SSH_KNOWN_HOSTS) - mkdir -p ~/.ssh - chmod 700 ~/.ssh - echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts - chmod 644 ~/.ssh/known_hosts
配置步骤:
- 在GitLab项目的「Settings → CI/CD → Variables」中添加
SSH_PRIVATE_KEY变量,值为你的SSH私钥内容 - 添加
SSH_KNOWN_HOSTS变量,值为远程服务器的SSH主机指纹(可通过ssh-keyscan $SSH_KNOWN_HOSTS_DEPLOY获取)
3. 合并远程命令到同一会话(按需使用)
如果需要在远程服务器执行多条命令,可将所有命令通过单条ssh语句执行,避免多次建立连接:
script: - ssh myssh_user@$SSH_KNOWN_HOSTS_DEPLOY "whoami && ls && mkdir -p /directory/to/copy/the/files" - rsync -avz $CI_PROJECT_DIR/app_root myssh_user@$SSH_KNOWN_HOSTS_DEPLOY:/directory/to/copy/the/files
关键说明
- 不要误以为「保持SSH连接」就能让后续命令在远程执行,CI的每个脚本行都是独立进程,只有在ssh命令的引号内的代码才会在远程运行
- rsync本身基于SSH协议,只要CI环境正确配置了密钥,无需依赖之前的ssh会话也能直接成功执行
内容的提问来源于stack exchange,提问作者DevMan
相关产品推荐
相关产品推荐

