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 ”
===== $(date “+%Y-%m-%d %H:%M:%S”) 开始数据库备份 =====” >> $LOG_FILE

# 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 ”
===== $(date “+%Y-%m-%d %H:%M:%S”) 开始代码部署 =====” >> $LOG_FILE

# 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

命令失败立即退出,退出时清理临时文件

© 版权声明

相关文章

暂无评论

none
暂无评论...