AI Infra 训练营
总览
  • 总览
  • 完整安装
  • 核心 K8s
  • Cilium 网络
  • Longhorn 存储
  • 监控日志
  • CI / GitOps
  • 安全准入
  • CI/CD 实战(MySQL+Go+Vue)
  • HPA/Ingress/Hubble 实战
  • 面试速查 + 真实踩坑
  • Day 0 · 新手接管 Runbook
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
命令手册
HiHuo 主站
GitHub
总览
  • 总览
  • 完整安装
  • 核心 K8s
  • Cilium 网络
  • Longhorn 存储
  • 监控日志
  • CI / GitOps
  • 安全准入
  • CI/CD 实战(MySQL+Go+Vue)
  • HPA/Ingress/Hubble 实战
  • 面试速查 + 真实踩坑
  • Day 0 · 新手接管 Runbook
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
命令手册
HiHuo 主站
GitHub
  • 命令手册总览
  • SSH 与远程执行

    • ssh —— 远程登录与远程执行
    • ssh-config —— ~/.ssh/config 客户端配置文件
    • ssh-keygen —— 密钥对生成与 known_hosts 维护
    • sshd —— SSH 服务端守护进程与硬化
    • sshpass —— 密码登录自动化(仅限"首次推 key"场景)
    • scp / rsync —— 远程文件拷贝
    • nsenter —— 进入 Linux namespace 的"传送门"
  • 系统状态与诊断

    • systemd-detect-virt —— 探测当前运行环境的虚拟化类型
    • systemctl —— systemd 服务管理的总入口
    • journalctl —— systemd 日志查询
    • hostnamectl / timedatectl —— 改主机名与时区
    • ss —— socket statistics(替代 netstat)
    • lsblk / df / du —— 三个被混淆的"看磁盘"命令
  • 进程与资源

    • ps —— 看进程
    • top / htop —— 实时进程资源监控
    • lsof —— 列出打开的文件(list open files)
    • strace —— 系统调用追踪
    • dmesg —— 看内核环形缓冲日志
    • iostat —— 磁盘 I/O 性能分析
    • iotop —— 进程级 I/O 实时监控
  • 文本与文件批处理

    • grep —— 文本搜索
    • sed —— 流编辑器
    • awk —— 按字段处理文本
    • jq —— JSON 命令行处理器
    • find —— 按各种条件找文件
    • xargs —— 把 stdin 喂给下一个命令
    • tee —— 一边输出、一边写文件
  • 磁盘与存储

    • mount / umount —— 挂载文件系统
    • mkfs —— 格式化文件系统
    • /etc/fstab —— 持久化挂载配置
    • parted / fdisk —— 分区表管理
    • LVM —— pvcreate / vgcreate / lvcreate 三件套
    • findmnt —— 现代化的"看挂载"命令
    • nfsstat / showmount —— NFS 状态与性能
    • smartctl —— 盘健康检查与坏盘预警
  • 网络诊断

    • curl —— HTTP 客户端的瑞士军刀
    • ip —— 现代 Linux 网络配置工具(替代 ifconfig / route)
    • iptables —— Linux 内核包过滤 / NAT 规则
    • tcpdump —— 命令行抓包
    • dig —— DNS 查询工具
    • mtr —— traceroute + ping 合体
    • iperf3 —— 网络带宽测试
    • nc (netcat) —— 网络瑞士军刀
    • ethtool —— 物理网卡参数 / 速率 / offload
  • 内核 / 包管理 / 时间

    • modprobe / lsmod —— 内核模块加载
    • sysctl —— 内核运行时参数
    • apt / apt-get / dpkg —— Debian / Ubuntu 包管理
    • chrony / chronyc —— NTP 时间同步
  • K8s / 容器工具链

    • kubectl —— K8s 的瑞士军刀
    • kubeadm —— K8s 集群引导工具
    • helm —— K8s 应用包管理器
    • crictl —— 容器运行时命令行(CRI 层)
    • etcdctl —— 直连 K8s 元数据存储
    • docker —— 单机容器(构建和本地开发)
  • 监控 / GitOps / 备份

    • argocd —— GitOps CLI
    • velero —— K8s 集群备份恢复
    • prometheus / promtool —— 监控数据查询和工具
    • cilium / cilium-cli / hubble —— eBPF CNI 排错
    • grafana / grafana-cli —— 可视化平台运维
    • alertmanager / amtool —— 告警分组、抑制、路由
  • 开发 / 构建 / 终端

    • git —— 版本控制 + GitOps 的底座
    • make / Makefile —— 任务编排
    • openssl —— 证书 / 密钥 / TLS 调试工具箱
    • tmux —— 终端复用 / 长跑任务防掉线
    • vim —— 远程编辑必备最小集
    • cron / crontab —— 定时任务

sshpass —— 密码登录自动化(仅限"首次推 key"场景)

一句话定义

sshpass 是个非常小的工具,作用只有一个:在脚本里把密码喂给 ssh,跳过那个交互式的密码提示。

OpenSSH 客户端本身故意不接受 -p <password> 这种参数(安全设计 —— 防止密码出现在 ps 输出和 shell history 里)。sshpass 是个绕过这个限制的小hack。

典型场景

90% 的合理使用就一个:拿到一批全新机器,第一次推公钥时,没法用 key 登(因为 key 还没推过去),只能用密码。这时用 sshpass 在脚本里自动化推 key,推完立刻关密码登录。

Day0 §2.1:

PUBKEY=$(cat ~/.ssh/id_rsa.pub)
for ip in 10.0.24.28 10.0.24.29 10.0.24.30 10.0.24.31 10.0.24.32; do
  sshpass -p "$IP_PWD" ssh -o StrictHostKeyChecking=accept-new root@$ip "
    mkdir -p /root/.ssh && chmod 700 /root/.ssh
    grep -qxF '$PUBKEY' /root/.ssh/authorized_keys 2>/dev/null \
      || echo '$PUBKEY' >> /root/.ssh/authorized_keys
    chmod 600 /root/.ssh/authorized_keys
  "
done

绝对不应该用 sshpass 的场景:

  • 日常运维(key + ssh-agent 完全够)
  • 生产部署(必须用 key 或更严的认证)
  • 把密码写在 git 仓库的脚本里(密码泄漏 = 机器沦陷)

安装

# Ubuntu / Debian
apt-get install -y sshpass

# macOS(Homebrew 默认不收,因为它"不安全")
brew install hudochenkov/sshpass/sshpass

# CentOS / RHEL(需要 EPEL)
yum install -y epel-release
yum install -y sshpass

brew 官方不收的原因:维护者觉得 sshpass 鼓励了不好的做法(把密码写脚本里)。要装得走第三方 tap,或者别用 macOS 跑这种脚本(拉个 Linux VM)。


三种"喂密码"方式

按安全性排序,越往后越安全。

1. -p <password> —— 命令行参数(最不安全)

sshpass -p 'MyPassw0rd' ssh root@host

问题:

  • ps aux | grep sshpass 会看到密码(任何能登录这台机器的人都能 sniff)
  • 写进 shell history(.bash_history、.zsh_history)
  • 容易被 git commit 进代码库

只用于一次性、纯本机、马上要删 history 的场景。

2. -f <file> —— 从文件读

echo 'MyPassw0rd' > /tmp/pw
chmod 600 /tmp/pw
sshpass -f /tmp/pw ssh root@host
rm /tmp/pw

比 -p 好:不出现在 ps 输出。但密码以明文落盘,依然不理想。

3. -e —— 从环境变量 SSHPASS 读(推荐)

export SSHPASS='MyPassw0rd'
sshpass -e ssh root@host
unset SSHPASS

# 或者一次性,密码只在子进程里
SSHPASS='MyPassw0rd' sshpass -e ssh root@host

环境变量不出现在 ps、不写文件。配合 read -s 输入更安全:

read -s -p "Password: " SSHPASS
export SSHPASS
for ip in ...; do
  sshpass -e ssh root@$ip 'echo OK'
done
unset SSHPASS

read -s 不回显密码到屏幕。Day0 推 key 脚本应该这么写。


完整推 key 工作流(建议这么干)

#!/bin/bash
set -euo pipefail

read -s -p "IDC machine password: " SSHPASS
export SSHPASS
echo

PUBKEY=$(cat ~/.ssh/id_ed25519.pub)
IPS=(10.0.24.28 10.0.24.29 10.0.24.30 10.0.24.31 10.0.24.32)

for ip in "${IPS[@]}"; do
  echo "=== $ip ==="
  sshpass -e ssh \
    -o StrictHostKeyChecking=accept-new \
    -o ConnectTimeout=10 \
    root@"$ip" "
      mkdir -p /root/.ssh && chmod 700 /root/.ssh
      grep -qxF '$PUBKEY' /root/.ssh/authorized_keys 2>/dev/null \
        || echo '$PUBKEY' >> /root/.ssh/authorized_keys
      chmod 600 /root/.ssh/authorized_keys
    " && echo "  ✅ key pushed" || echo "  ❌ failed"
done

unset SSHPASS

# 验证:每台机器用 key 都能登
for ip in "${IPS[@]}"; do
  ssh -o BatchMode=yes -o ConnectTimeout=5 root@"$ip" 'echo OK' \
    && echo "$ip: ✅ key works" \
    || echo "$ip: ❌ key broken"
done

关键点:

  • read -s 输入密码不回显
  • set -euo pipefail 让脚本一遇到错就退出(避免某台失败但继续推后面的)
  • StrictHostKeyChecking=accept-new:首次自动信任并写 known_hosts
  • ConnectTimeout=10:默认 TCP 重试好几分钟,加超时让脚本快速失败
  • grep -qxF ... || 实现幂等(详见 ssh-keygen.md)
  • 推完立刻验证 key 工作(BatchMode=yes 禁交互),确认 OK 之后再关密码

常见踩坑

坑 1:推 key 成功了,但马上 PasswordAuthentication no,结果 key 不工作

顺序不能反。正确顺序:

  1. 推 key
  2. 用 ssh -o BatchMode=yes 验证 key 能登
  3. 确认验证通过后,再去关 PasswordAuthentication(见 sshd.md)

如果 key 没工作就关了密码 → 你既不能用密码登、也不能用 key 登 → 锁外面。

坑 2:密码里有特殊字符($, !, `)

sshpass -p 'My$ecret!' ssh root@host        # 单引号是必须的
sshpass -p "My$ecret!" ssh root@host        # ❌ $ecret 被 shell 当变量展开(多半为空)

含 $ 或 ` 的密码:用单引号。

坑 3:sshpass 报 "command not found"

-bash: sshpass: command not found

很多发行版默认不装。apt-get install -y sshpass。

坑 4:sshpass 报 "Permission denied",密码明明对

可能是远端禁用了 keyboard-interactive、或者只允许公钥。先用普通 ssh root@host 手动试一次,看远端到底允许什么认证方式:

ssh -v -o PreferredAuthentications=password root@host
# Authentications that can continue: publickey
# 说明远端禁了密码

这种机器你根本不需要 sshpass —— 它已经强制 key 了。

坑 5:first connection 的 host key 提示卡住

sshpass -e ssh root@host         # ❌ 卡在 "Are you sure you want to continue?"

sshpass 喂的是登录密码,不是这个提示的"yes"回答。加 StrictHostKeyChecking=accept-new 让 ssh 自动信任首次:

sshpass -e ssh -o StrictHostKeyChecking=accept-new root@host

坑 6:CI 环境里把密码 commit 进了 .env 或脚本

经典事故。CI 跑得好好的,过了一年某个新员工把 repo 设成 public 或者 fork 出去 → 密码泄漏。

防御:

  • 用 CI 平台的 secret 机制(GitHub Actions secrets、GitLab CI variables)
  • 任何脚本里都用 ${SSHPASS} 读环境变量,不在文件里写明文
  • 不要 commit .env:.gitignore 加 .env、*.password、secrets/*

更彻底的:根本不要用 sshpass 进 CI。CI 部署用 SSH key(CI 提供的 deploy key 机制),key 不会泄漏的同时还能精确撤销。


替代方案

Ansible(首选)

ansible all -i hosts -m authorized_key \
  -a "user=root state=present key='$(cat ~/.ssh/id_ed25519.pub)'" \
  -k                    # -k 提示输入密码

-k 一次性输密码,Ansible 帮你处理所有节点。无需 sshpass。

ssh-copy-id

for ip in ...; do
  ssh-copy-id -i ~/.ssh/id_ed25519.pub root@$ip
done

每台机器交互式问一次密码。机器多就累,机器少(≤5)足够。

直接走 cloud-init / IDC console 注入 key

很多 IDC 创建机器时可以选"注入 SSH 公钥"。这是最佳做法 —— 机器开出来就有 key,根本不需要密码登录这一步。


关联命令

  • ssh —— sshpass 只是 ssh 前面的一个 wrapper
  • ssh-keygen —— 先生成 key 才有可推的公钥
  • sshd —— 推完 key 之后关密码登录的服务端配置
  • ansible / ssh-copy-id —— 生产环境的更好替代
在 GitHub 上编辑此页
Prev
sshd —— SSH 服务端守护进程与硬化
Next
scp / rsync —— 远程文件拷贝