Linux 实操———— Shell 远程执行命令

引言

目前,开发人员的部署方式是,将项目打包(Maven 打包) 然后将 生成的 jar 包等文件,通过Xshell 等终端工具手动传输到远程服务器上,然后再通过在终端执行远程服务器上的 shell 脚本来启动服务。

本篇博客聚焦这样一种解决方案,通过在本地(Windows或Mac 系统等)运行 Shell 脚本,使用 scp 命令传输,并通过 ssh 命令执行远程服务器上的指令或脚本,来完成这一系列各种软件切换、复制粘贴、启动运行的操作,达到 “一键部署” 的效果。这在前期频繁更新部署 jar 包到远程服务器有很大的效率提升。

一、准备条件

如果本机是 Windows 系统,那么如果希望执行 shell 脚本,至少需要安装一个类似 Xshell 的终端工具,普通的 dos 命令行肯定是不行的。

不过如果有装过 git ,那么通过Git Bash 来执行 Shell 脚本是个不错的选择。

另外,文件上传和远程执行 Shell 脚本需要对 scp 命令、 Shell 命令 、ssh 等命令有一定的了解。

二、文件上传

一般在主机之间传输文件除了使用 SFTP 等协议外,还会使用 scp 命令,这些协议都基于 ssh 安全登录协议。scp 命令在之前的文章中有简单介绍过,详情参考我的《Linux进阶之路————scp指令介绍与演示

于是,我们可以像下面这样将打包好的 jar 文件通过 scp 命令传输到 远程主机上:

#!/bin/bash
## 通过 scp 命令上传
scp ../target/demo-0.0.1-SNAPSHOT.jar [email protected]:~/myapp/

这个格式非常简单,首先 scp 命令先行,其次是源文件,再然后就是远程主机的 ip 地址以及存放的位置,其中 ~ 代表用户的 HOME 目录,比如 root 用户的 HOME 目录就是 /root,tom用户的 HOME 目录就是 /home/tom/ 。如果希望传输多个文件,可以直接用空格隔开(多个空格没有关系),类似这样:

scp  文件1  文件2  文件3...    user@IP:目标路径

其实,完全可以在项目的 classpath 下建立一个专门管理 shell 文件的文件夹,类似这样:

这样的话,shell 和 target 下打包出来的 jar 包始终保持相对路径,就不会因为在不同开发者主机上的项目位置不同而频繁修改 shell 中的 jar 包路径。

三、远程执行 Shell 项目启动脚本

当执行完文件上传命令之后,接下来就是启动远程主机的 Shell 脚本,让服务启动。

通常,我们会在远程服务器上放置一个配置好固定参数的启动脚本,类似这样:

但每次都需要登录远程主机,切换到目标位置,再执行启动脚本有些麻烦,于是,我们可以在保留远程脚本的同时将调用执行的操作放在本地 Windows 主机上。

于是,我们可以在上面的 scp 命令之后,添加 ssh 命令用于执行远程脚本:

#!/bin/bash
## 通过 scp 命令上传
scp ../target/demo-0.0.1-SNAPSHOT.jar [email protected]:~/myapp/

## 上传后执行启动脚本
ssh [email protected] << bash
source /etc/profile
cd ~/myapp
./app.sh restart demo-0.0.1-SNAPSHOT.jar
bash

我们可以使用 ssh 命令在本地执行远程主机上的命令,包括执行 shell 脚本。

其中,"<<" 代表输入重定向,它的功能可以这样来描述:

格式:cmd << text

从命令行读取输入,直到一个与text 相同的行结束。text 是自定义的文本,可以是任何字符串,那么 text 与 text 之间的全部内容,都会被当做输入的参数,并被输入到 << 左边的指令中。

于是,红框内的部分就是我们要执行的 Shell 调用的具体命令(由于我的Eclipse安装了 shell编辑插件,<< 的部分会被灰色处理):

值得一提的是,在真正执行远程 app.sh 脚本之前,需要执行 source /etc/profile  命令,这在我的《Linux 实操———CentOS 6 安装配置 Oracle JDK 1.8》和《Linux进阶之路———Shell 编程入门》中都有说明,意思就是刷新环境变量。这是因为远程连接的情况下不会自动加载环境变量,因此,如果你调用的远程脚本中存在类似 java 的环境变量的命令,就会报 command not found 错误。因此只要在执行脚本之前刷新环境变量就可以了。

另外,远程的输出会被传回到本地的 Git Bash 窗口,如果希望将输出保存到远程的 nohup.out 文件中,需要添加 >> 重定向:

当加入输出重定向后,服务端的输出就会保留在nohup.out 中,而 Git Bash 也不会有任何输出内容,从而安静的执行完脚本并返回。下面第四节采用了非重定向的方式,可以根据实际情况酌情考虑。

本博客暂未做.log 日志文件的输出检查,如果对是否会影响每天日志保存的情况,还有待进一步验证。未来验证后会追加这个问题。 

四、远程传输并启动项目

到此为止,通过本地的 deploy.sh ,我们就有足够的能力传输 jar 包并启动远程服务(deploy.sh—>app.sh—>启动服务),接下来我们实际演示一下,看看能否成功。

当然,Eclipse 貌似也有执行 bash 的插件。这里由于操作比较简单,我们可以通过 Eclipse 编辑完 Shell 后在系统盘中打开,然后通过 Git Bash 来执行,方法是选中文件,右键——>Show In——>System Explorer:

然后在打开的资源管理器中右键空白,选择 Git Bash:

最后执行脚本:

我们可以看到远程服务的日志输出(如果是重定向到远程文件,例如 ">> nohup.out",就会在远程服务器上保留输出),这更加方便了我们判断是否启动成功,当看到启动成功后,将Git Bash 关闭即可。这并不会影响远程服务。

我们来检查一下,服务的访问,以及远程服务器上的资源情况,应该是都没有问题的:

值得一提的是,在scp 和 ssh 执行部署工作的时候,需要两次交互式的输入密码(scp 一次,ssh 一次),密码是不可见的,如果你的密码非常长,建议复制粘贴。

虽然脚本已经足够简化文件上传和启动的操作,但是依然不能避免输入密码的痛苦。

还有一种方式是使用 rsa 公私钥来解决免密操作的方式,但是如果是多开发者的话,就需要为每台开发者机器配置公私钥,这就极大地增加了前期的部署工作和操作难度,但如果大家每次都复制粘贴密码的话好像也会使密码渐渐变得不那么安全,容易泄露。另外有一种支持非交互式免密的方式是 sshpass ,它可以在ssh 之前通过 -P "password" 指定登录密码, 不过这东西貌似在 Git Bash 上不支持,甚至在 CentOS 6 上也找不到yum 安装,比较难搞。

总之,目前我还没有找到比较好的权宜之计,所以,暂且就复制粘贴吧,其实已经足够简单了。

参考与鸣谢

Linux Shell远程执行命令(命令行与脚本方式)

linux shell 远程执行命令

linux:shell脚本中一些特殊符号

linux几种文件传输方式

ssh登录时在参数中加入密码的解决方案

发布了191 篇原创文章 · 获赞 280 · 访问量 52万+

猜你喜欢

转载自blog.csdn.net/u014745069/article/details/102532934