CI/CD A 服务器(构建机)免密登录 B 服务器(目标部署机)完整操作
原理:A 生成 ssh 密钥对,把公钥 放到 B 服务器
~/.ssh/authorized_keys,A 用私钥登录 B,CI/CD 工具(Jenkins/GitLab CI 等)使用 A 上的私钥远程发布。 说明:A = 发起端,B = 目标服务器;操作全部在A 服务器执行,少量 B 端权限检查。
1. A 服务器:生成 SSH 密钥对(不要设置密码!CI/CD 自动化不能输密码)
# 一路回车,不设置passphrase,直接生成密钥
ssh-keygen -t ed25519 -C "cicd-auto-deploy"
# 旧系统不支持ed25519就用rsa
# ssh-keygen -t rsa -b 4096 -C "cicd-auto-deploy"
生成文件默认路径:
- 私钥:
~/.ssh/id_ed25519(A 服务器保留,不能泄露,CI/CD 用这个) - 公钥:
~/.ssh/id_ed25519.pub(复制这个内容到 B)
⚠️ 重点:密钥不要加密码,如果生成时输入了密码,CI 流水线执行 ssh/scp 会卡住等待手动输入密码。
2. A 服务器把公钥推送到 B 服务器(两种方式)
方式 1:ssh-copy-id(最简单,推荐)
# B服务器用户名@B的IP
ssh-copy-id root@B服务器IP
# 非root用户示例:ssh-copy-id deploy@192.168.1.101
输入 B 服务器的登录密码,执行完成,公钥自动写入 B 的~/.ssh/authorized_keys。
方式 2:手动复制(服务器没有 ssh-copy-id 命令时用)
-
在 A 查看公钥内容:
cat ~/.ssh/id_ed25519.pub
-
登录 B 服务器,创建 / 修改 ssh 目录:
B服务器执行
mkdir -p ~/.ssh
chmod 700 ~/.ssh把上面A的公钥字符串追加到文件
echo "粘贴A公钥全部内容" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
权限非常关键:
.ssh目录 700,authorized_keys 必须 600,权限过大 ssh 会拒绝免密登录。
3. 验证免密(A 服务器执行)
ssh root@B服务器IP
✅ 成功:直接登录,不需要输入密码。 ❌ 失败:排查下面常见问题。
4. CI/CD 使用方案(两种常用)
方案 A:Jenkins Agent/CI 进程直接跑在 A 服务器
A 服务器上的 CI 进程使用当前用户下的私钥 ~/.ssh/id_ed25519,流水线脚本直接 ssh:
# 流水线示例
ssh root@BIP "cd /data/app && git pull && restart app"
方案 B:CI 工具单独管理私钥(推荐,安全最佳实践)
不要把私钥明文放服务器文件,在 Jenkins/GitLab CI/ArgoCD 的密钥凭证 里,填入 A 服务器私钥(id_ed25519完整内容),流水线运行时动态加载私钥。
生产环境优先这种,避免私钥文件留在机器磁盘。
5. 常见失败排查清单
-
B 服务器
~/.ssh目录权限 >700 /authorized_keys 权限 > 600 → ssh 拒绝免密 -
公钥粘贴错误,有换行、空格多余字符
-
B 服务器 sshd 配置禁止公钥登录: 登录 B,检查 sshd 配置
/etc/ssh/sshd_configPubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
修改后重启 sshd:
# centos
systemctl restart sshd
# ubuntu
systemctl restart ssh
-
防火墙:B 服务器 22 端口是否放行 A 服务器 IP
-
SELinux 开启(CentOS/RHEL),会导致读取 authorized_keys 失败:
临时关闭测试
setenforce 0