SSH 操作晋级:自动化脚本集成技巧,备份与部署一键完成
SSH 操作晋级:自动化脚本集成技巧,备份与部署一键完成
前言:为什么需要 SSH 自动化脚本?运维的 “重复痛点”
你是否每天在重复这些低效操作?
远程备份数据库:手动 SSH 登录服务器→执行mysqldump→用scp把备份文件拉到本地→删除服务器 7 天前的旧备份,每天耗时 10 分钟;代码部署:本地git pull→scp传代码到远程服务器→SSH 登录重启服务→查看日志确认是否启动成功,每次部署步骤多易遗漏;多服务器操作:需登录 5 台服务器执行相同命令(如清理日志),重复输入 SSH 指令,耗时且易出错。
手动操作的核心问题是 “重复、低效、易出错”,而SSH 自动化脚本(结合 bash 脚本 + SSH 工具链)能完美解决这些问题 —— 通过 “一次编写、多次复用” 的脚本,实现 “一键触发备份 / 部署,自动处理 SSH 交互、错误判断、日志记录”,大幅降低运维成本,尤其适合高频重复的 SSH 操作场景。
本文从 “基础准备→核心场景实战→进阶优化” 全流程讲解,带你掌握 SSH 自动化脚本的集成技巧,覆盖数据库备份、代码部署两大高频运维需求。
一、基础准备:自动化脚本的 “前提条件”
在编写脚本前,需先完成两项核心准备(确保脚本能无交互执行):
1. 配置 SSH 免密登录(自动化的核心)
脚本无法手动输入密码,必须通过 “SSH 密钥登录” 实现无交互认证,步骤如下:
步骤 1:本地生成 SSH 密钥(仅首次执行)
|
# 生成 ED25519 密钥(比 RSA 更安全,生成速度快) ssh-keygen -t ed25519 -a 200 -f ~/.ssh/auto_ssh_key -C “ssh-automation-script” # 参数说明: # -a 200:增加 KDF 迭代次数,抗暴力破解; # -f ~/.ssh/auto_ssh_key:指定密钥保存路径(避免与默认密钥冲突); # 执行后按提示回车(无需设置 Passphrase,否则脚本仍需输入密码)。 |
步骤 2:将公钥上传到远程服务器(目标服务器)
|
# 格式:ssh-copy-id -i 本地公钥路径 远程用户@远程IP -p 远程SSH端口 ssh-copy-id -i ~/.ssh/auto_ssh_key.pub ops@47.100.xxx.xxx -p 22 # 首次执行需输入远程服务器密码,后续登录无需密码。 |
步骤 3:验证免密登录
|
# 格式:ssh -i 本地私钥路径 远程用户@远程IP -p 远程SSH端口 “echo '免密登录成功'” ssh -i ~/.ssh/auto_ssh_key ops@47.100.xxx.xxx -p 22 “echo '免密登录成功'” # 输出“免密登录成功”即配置完成,脚本可无交互执行SSH命令。 |
2. 脚本运行环境准备
本地环境:Linux/macOS(自带 bash)、Windows(需安装 Git Bash 或 WSL,避免 cmd/powershell 语法兼容问题);脚本权限:编写的.sh脚本需赋予执行权限(chmod +x script.sh);依赖工具:确保本地和远程服务器安装必要工具(如mysqldump、git、tar,脚本中可添加检查逻辑)。
二、实战场景 1:SSH 自动化远程数据库备份(一键完成)
场景需求
远程服务器(IP:47.100.xxx.xxx)运行 MySQL 数据库,需每天自动备份指定库(app_db);备份流程:远程执行mysqldump→压缩备份文件→通过 SSH 将备份文件拉到本地→删除远程服务器 7 天前的旧备份→记录备份日志(成功 / 失败)。
完整自动化脚本(auto_db_backup.sh)
|
#!/bin/bash # 脚本名称:auto_db_backup.sh # 功能:SSH远程MySQL备份,自动拉取备份文件并清理旧备份 # 配置参数(根据实际情况修改) LOCAL_BACKUP_DIR=”/data/backups/db” # 本地备份文件存放目录 REMOTE_SSH_KEY=”$HOME/.ssh/auto_ssh_key” # 本地SSH私钥路径 REMOTE_USER=”ops” # 远程服务器用户名 REMOTE_IP=”47.100.xxx.xxx” # 远程服务器IP REMOTE_SSH_PORT=”22″ # 远程SSH端口 REMOTE_MYSQL_USER=”root” # 远程MySQL用户名 REMOTE_MYSQL_PASS=”DB@Pass123″ # 远程MySQL密码(建议用环境变量,下文优化) REMOTE_DB_NAME=”app_db” # 需备份的MySQL数据库名 REMOTE_BACKUP_DIR=”/tmp/db_backups” # 远程服务器临时备份目录 RETENTION_DAYS=7 # 远程旧备份保留天数(超过则删除) LOG_FILE=”$LOCAL_BACKUP_DIR/db_backup.log” # 备份日志文件 # ————————– 脚本核心逻辑 ————————– # 1. 初始化本地目录和日志 mkdir -p $LOCAL_BACKUP_DIR # 创建本地备份目录(不存在则创建) echo -e ” # 2. 远程执行MySQL备份并压缩(通过SSH远程命令) BACKUP_FILENAME=”${REMOTE_DB_NAME}_$(date “+%Y%m%d_%H%M%S”).sql.gz” # 备份文件名(含时间戳) echo “正在远程执行MySQL备份:$BACKUP_FILENAME” >> $LOG_FILE # SSH远程执行备份命令(mysqldump+gzip压缩) ssh -i $REMOTE_SSH_KEY -p $REMOTE_SSH_PORT $REMOTE_USER@$REMOTE_IP “ mkdir -p $REMOTE_BACKUP_DIR; # 远程创建临时备份目录 export MYSQL_PWD=$REMOTE_MYSQL_PASS; # 避免MySQL密码明文显示在进程列表 mysqldump -u $REMOTE_MYSQL_USER $REMOTE_DB_NAME | gzip > $REMOTE_BACKUP_DIR/$BACKUP_FILENAME; echo $? # 返回备份命令执行结果(0=成功,非0=失败) ” > $LOCAL_BACKUP_DIR/backup_result.tmp # 保存远程执行结果 # 3. 检查远程备份是否成功 BACKUP_RESULT=$(tail -n 1 $LOCAL_BACKUP_DIR/backup_result.tmp) if [ $BACKUP_RESULT -ne 0 ]; then echo “远程备份失败!” >> $LOG_FILE rm -f $LOCAL_BACKUP_DIR/backup_result.tmp exit 1 # 脚本退出,返回错误码1 fi echo “远程备份成功,开始拉取备份文件” >> $LOG_FILE # 4. 通过SCP拉取远程备份文件到本地 scp -i $REMOTE_SSH_KEY -P $REMOTE_SSH_PORT $REMOTE_USER@$REMOTE_IP:$REMOTE_BACKUP_DIR/$BACKUP_FILENAME $LOCAL_BACKUP_DIR/ # 检查SCP拉取是否成功 if [ $? -eq 0 ]; then echo “备份文件拉取成功:$LOCAL_BACKUP_DIR/$BACKUP_FILENAME” >> $LOG_FILE else echo “备份文件拉取失败!” >> $LOG_FILE rm -f $LOCAL_BACKUP_DIR/backup_result.tmp exit 1 fi # 5. 远程清理旧备份(保留指定天数内的文件) echo “正在清理远程$RETENTION_DAYS天前的旧备份” >> $LOG_FILE ssh -i $REMOTE_SSH_KEY -p $REMOTE_SSH_PORT $REMOTE_USER@$REMOTE_IP “ find $REMOTE_BACKUP_DIR -name '${REMOTE_DB_NAME}_*.sql.gz' -mtime +$RETENTION_DAYS -delete “ # 6. 备份完成,记录日志 echo “===== $(date “+%Y-%m-%d %H:%M:%S”) 数据库备份完成 =====” >> $LOG_FILE rm -f $LOCAL_BACKUP_DIR/backup_result.tmp # 删除临时文件 exit 0 |
脚本使用与验证
修改配置参数:打开脚本,将配置参数部分的 IP、用户名、密码等改为实际环境信息;赋予执行权限:
|
chmod +x auto_db_backup.sh |
执行脚本:
|
./auto_db_backup.sh |
验证结果:
查看本地备份目录(/data/backups/db)是否有.sql.gz备份文件;查看日志文件(/data/backups/db/db_backup.log),确认无错误信息;登录远程服务器,检查/tmp/db_backups目录是否仅保留 7 天内的备份。
三、实战场景 2:SSH 一键代码部署(拉取 + 编译 + 重启)
场景需求
本地开发完成后,需将代码部署到远程服务器(47.100.xxx.xxx)的/opt/app目录;部署流程:本地git pull更新代码→通过 SSH 同步代码到远程服务器→远程编译项目(如 Java Maven 项目)→停止旧服务→启动新服务→验证服务是否启动成功。
完整自动化脚本(auto_code_deploy.sh)
|
#!/bin/bash # 脚本名称:auto_code_deploy.sh # 功能:SSH一键部署代码(拉取+同步+编译+重启服务) # 配置参数(根据实际情况修改) LOCAL_CODE_DIR=”$HOME/projects/app” # 本地代码目录 REMOTE_SSH_KEY=”$HOME/.ssh/auto_ssh_key” # 本地SSH私钥路径 REMOTE_USER=”ops” # 远程服务器用户名 REMOTE_IP=”47.100.xxx.xxx” # 远程服务器IP REMOTE_SSH_PORT=”22″ # 远程SSH端口 REMOTE_APP_DIR=”/opt/app” # 远程服务器应用目录 SERVICE_NAME=”app-service” # 远程服务名(systemd服务) LOG_FILE=”$LOCAL_CODE_DIR/deploy.log” # 部署日志文件 # ————————– 脚本核心逻辑 ————————– # 1. 初始化日志 echo -e ” # 2. 本地拉取最新代码(Git) echo “正在本地拉取最新代码…” >> $LOG_FILE cd $LOCAL_CODE_DIR || { echo “本地代码目录不存在!” >> $LOG_FILE; exit 1; } git pull origin main # 拉取main分支(根据实际分支修改) if [ $? -ne 0 ]; then echo “本地Git拉取代码失败!” >> $LOG_FILE exit 1 fi echo “本地代码拉取成功” >> $LOG_FILE # 3. 通过SCP同步本地代码到远程服务器(排除.git、node_modules等无用目录) echo “正在同步代码到远程服务器…” >> $LOG_FILE scp -i $REMOTE_SSH_KEY -P $REMOTE_SSH_PORT -r –exclude=”.git” –exclude=”node_modules” –exclude=”logs” $LOCAL_CODE_DIR/* $REMOTE_USER@$REMOTE_IP:$REMOTE_APP_DIR/ if [ $? -ne 0 ]; then echo “代码同步到远程失败!” >> $LOG_FILE exit 1 fi echo “代码同步到远程成功” >> $LOG_FILE # 4. SSH远程编译项目(以Maven项目为例,需远程安装Maven) echo “正在远程编译项目…” >> $LOG_FILE ssh -i $REMOTE_SSH_KEY -p $REMOTE_SSH_PORT $REMOTE_USER@$REMOTE_IP “ cd $REMOTE_APP_DIR; mvn clean package -Dmaven.test.skip=true; # 编译并跳过测试 echo $? # 返回编译结果 ” > $LOCAL_CODE_DIR/build_result.tmp # 检查编译是否成功 BUILD_RESULT=$(tail -n 1 $LOCAL_CODE_DIR/build_result.tmp) if [ $BUILD_RESULT -ne 0 ]; then echo “远程项目编译失败!” >> $LOG_FILE rm -f $LOCAL_CODE_DIR/build_result.tmp exit 1 fi echo “远程项目编译成功” >> $LOG_FILE # 5. SSH远程重启服务(systemd管理服务) echo “正在远程重启服务…” >> $LOG_FILE ssh -i $REMOTE_SSH_KEY -p $REMOTE_SSH_PORT $REMOTE_USER@$REMOTE_IP “ sudo systemctl stop $SERVICE_NAME; # 停止旧服务 sleep 3; # 等待3秒,确保服务完全停止 sudo systemctl start $SERVICE_NAME; # 启动新服务 sudo systemctl status $SERVICE_NAME | grep 'active (running)' # 检查服务状态 ” > $LOCAL_CODE_DIR/service_status.tmp # 检查服务是否启动成功 if grep -q “active (running)” $LOCAL_CODE_DIR/service_status.tmp; then echo “服务重启成功,状态:运行中” >> $LOG_FILE else echo “服务重启失败!请查看远程日志:sudo journalctl -u $SERVICE_NAME” >> $LOG_FILE rm -f $LOCAL_CODE_DIR/build_result.tmp $LOCAL_CODE_DIR/service_status.tmp exit 1 fi # 6. 部署完成,记录日志 echo “===== $(date “+%Y-%m-%d %H:%M:%S”) 代码部署完成 =====” >> $LOG_FILE rm -f $LOCAL_CODE_DIR/build_result.tmp $LOCAL_CODE_DIR/service_status.tmp exit 0 |
脚本使用与验证
前提条件:远程服务器已安装maven(编译用),且ops用户有sudo systemctl操作权限(可在/etc/sudoers中配置免密 sudo);修改配置参数:更新脚本中的本地代码目录、远程服务名等参数;执行部署:
|
./auto_code_deploy.sh |
验证结果:
查看部署日志($LOCAL_CODE_DIR/deploy.log)确认无错误;远程执行sudo systemctl status app-service,确认服务处于active (running)状态;访问应用接口(如http://47.100.xxx.xxx:8080/health),验证服务正常。
四、进阶技巧:让自动化脚本更健壮、更灵活
1. 敏感信息处理(避免硬编码密码)
脚本中硬编码 MySQL 密码、API 密钥等敏感信息存在安全风险,推荐用 “环境变量” 或 “配置文件” 存储:
方法 1:使用环境变量
|
# 1. 本地设置环境变量(临时生效,重启终端需重新设置) export REMOTE_MYSQL_PASS=”DB@Pass123″ # 2. 脚本中引用环境变量(替换原硬编码密码) REMOTE_MYSQL_PASS=”$REMOTE_MYSQL_PASS” # 直接引用环境变量 |
方法 2:使用配置文件(推荐,持久化)
|
# 1. 创建配置文件(.env,权限设为600,仅自己可读写) vim $HOME/.ssh/auto_ssh_config.env # 添加内容: REMOTE_MYSQL_PASS=”DB@Pass123″ REMOTE_API_KEY=”xxx” # 2. 脚本中加载配置文件 source $HOME/.ssh/auto_ssh_config.env # 加载配置 REMOTE_MYSQL_PASS=”$REMOTE_MYSQL_PASS” # 引用配置中的变量 # 3. 设置配置文件权限(关键,避免他人读取) chmod 600 $HOME/.ssh/auto_ssh_config.env |
2. 错误处理与陷阱(脚本崩溃时自动清理)
通过set -e和trap命令,让脚本在出错时自动退出并清理临时文件,避免残留垃圾:
|
#!/bin/bash set -e # 脚本中任何命令执行失败,立即退出脚本(避免继续执行错误操作) trap 'cleanup' EXIT # 脚本退出时(无论成功/失败),执行cleanup函数 # 临时文件目录 TMP_DIR=”/tmp/ssh_auto_tmp” # 清理函数(删除临时文件) cleanup() { echo “正在清理临时文件…” rm -rf $TMP_DIR echo “清理完成” } # 初始化临时目录 mkdir -p $TMP_DIR |
3. 定时自动执行(无需手动触发)
结合crontab(Linux/macOS)实现脚本定时执行(如每天凌晨 2 点备份、每小时部署一次测试环境):
步骤 1:编辑 crontab 任务
|
# 打开crontab编辑界面 crontab -e |
步骤 2:添加定时任务(示例)
|
# 1. 每天凌晨2点执行数据库备份脚本(日志输出到指定文件) 0 2 * * * /home/ops/scripts/auto_db_backup.sh >> /home/ops/scripts/auto_backup_cron.log 2>&1 # 2. 每小时执行一次测试环境部署(工作时间8:00-20:00) 0 8-20 * * * /home/ops/scripts/auto_code_deploy_test.sh >> /home/ops/scripts/auto_deploy_cron.log 2>&1 |
说明:
0 2 * * *:定时规则(分 时 日 月 周),表示每天凌晨 2 点;2>&1:将脚本错误输出(stderr)重定向到日志文件,便于排查问题;查看 crontab 日志:tail -f /var/log/cron(CentOS)或grep CRON /var/log/syslog(Ubuntu)。
4. 多服务器批量操作(循环遍历服务器列表)
若需对多台服务器执行相同操作(如批量备份、批量部署),可通过循环遍历服务器列表实现:
|
#!/bin/bash # 多服务器列表(数组,存储IP或主机名) REMOTE_SERVERS=(“47.100.xxx.101” “47.100.xxx.102” “47.100.xxx.103”) REMOTE_USER=”ops” REMOTE_SSH_KEY=”$HOME/.ssh/auto_ssh_key” # 循环遍历服务器,执行SSH命令 for SERVER_IP in “${REMOTE_SERVERS[@]}”; do echo “===== 开始操作服务器:$SERVER_IP =====” # 示例:批量清理远程服务器日志 ssh -i $REMOTE_SSH_KEY $REMOTE_USER@$SERVER_IP “ sudo rm -rf /var/log/app/*.log.1; # 删除旧日志 echo '服务器$SERVER_IP 日志清理完成' “ echo “===== 服务器$SERVER_IP 操作完成 =====” done |
五、常见问题排查(脚本运行踩坑指南)
1. 脚本执行报错:“Permission denied (publickey)”
原因:
SSH 私钥权限过宽(如 755,SSH 为安全拒绝使用);远程服务器~/.ssh/authorized_keys未添加本地公钥;
解决:
|
# 1. 重置私钥权限(必须为600) chmod 600 ~/.ssh/auto_ssh_key # 2. 重新上传公钥到远程服务器 ssh-copy-id -i ~/.ssh/auto_ssh_key.pub ops@47.100.xxx.xxx -p 22 |
2. 远程命令执行失败:“command not found”(如 mysqldump、mvn)
原因:远程服务器PATH环境变量未包含命令所在目录(如mysqldump在/usr/local/mysql/bin,未在 PATH 中);解决:脚本中使用命令绝对路径,或远程执行时指定 PATH:
|
# 方法1:使用绝对路径(推荐,准确) ssh -i $REMOTE_SSH_KEY ops@47.100.xxx.xxx “/usr/local/mysql/bin/mysqldump -u root app_db” # 方法2:远程设置PATH ssh -i $REMOTE_SSH_KEY ops@47.100.xxx.xxx “ export PATH=$PATH:/usr/local/mysql/bin; # 添加命令路径 mysqldump -u root app_db; # 此时可直接用命令名 “ |
3. crontab 定时任务不执行
常见原因:
crontab 环境变量与终端不同(如PATH未包含脚本依赖命令);脚本路径用相对路径(crontab 执行目录为/home/用户,相对路径易出错);
解决:
脚本中使用绝对路径(如/home/ops/scripts/auto_db_backup.sh,而非./auto_db_backup.sh);crontab 任务中指定 PATH:
|
# crontab 任务中添加PATH(示例) 0 2 * * * export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin; /home/ops/scripts/auto_db_backup.sh >> /home/ops/scripts/auto_backup_cron.log 2>&1 |
五、安全注意事项(必看!)
私钥安全:SSH 私钥(auto_ssh_key)权限必须设为 600(chmod 600 ~/.ssh/auto_ssh_key),避免其他用户读取;脚本权限:自动化脚本权限设为 700(chmod 700 script.sh),仅自己可执行,防止他人篡改脚本;最小权限原则:远程服务器的ops用户仅授予必要权限(如备份仅需mysqldump权限,部署仅需systemctl启停权限),避免授予 root 权限;日志审计:定期查看备份 / 部署日志,检查是否有异常执行记录(如未授权的备份失败、部署失败)。
六、总结:自动化脚本的核心价值与适用场景
1. 核心价值
|
手动操作 |
SSH 自动化脚本 |
效率提升幅度 |
|
数据库备份(10 分钟 / 次) |
一键执行(30 秒 / 次,含日志) |
20 倍 |
|
代码部署(5 分钟 / 次) |
一键部署(1 分钟 / 次,自动验证) |
5 倍 |
|
多服务器操作(N 分钟 / N 台) |
批量执行(N 分钟 / 所有台,循环遍历) |
N 倍 |
2. 适用场景
高频重复操作:每日备份、定时部署、日志清理;多服务器批量操作:批量安装软件、批量执行命令;标准化流程:确保每次操作步骤一致(避免手动遗漏步骤)。
通过本文的实战脚本与进阶技巧,你可轻松实现 SSH 操作的自动化,告别重复手动操作,将更多时间投入到更有价值的运维工作中。若在脚本编写中遇到问题,欢迎在评论区留言讨论!
附:SSH 自动化脚本常用命令速查表
|
操作需求 |
命令示例 |
说明 |
|
SSH 远程执行命令 |
ssh -i 私钥 user@ip -p 端口 “命令” |
无交互执行远程命令,返回结果 |
|
SCP 同步文件(本地→远程) |
scp -i 私钥 -P 端口 本地文件 user@ip:远程路径 |
加密传输文件,支持-r递归同步目录 |
|
SCP 同步文件(远程→本地) |
scp -i 私钥 -P 端口 user@ip:远程文件 本地路径 |
拉取远程文件到本地 |
|
加载配置文件 |
source 配置文件路径 |
加载外部配置,避免硬编码敏感信息 |
|
定时任务(crontab) |
0 2 * * * 脚本路径 >> 日志路径 2>&1 |
每天凌晨 2 点执行脚本,日志重定向 |
|
脚本错误处理 |
set -e; trap 'cleanup' EXIT |
命令失败立即退出,退出时清理临时文件 |

