起因:

    因项目使用spring boot 服务以jar方式运行,每次更新都需要对不同模块、不同目录进行文件上传、服务重启等操作,同时文件上传必须使用SFTP,这就导致了需要开多个客户端工具,需要在不同文件目录中来回切换。

    这种操作方式效率低、浪费时间,于是想着找开源运维工具,能远端一键部署,奈何网上找了一圈,不是学习成本高就是有使用限制。最后在知乎的一篇文章中看到了一个无需远端服务的Java运维工具,仅需配置好XML即可实现上传文件、执行命令的操作,于是试用一波,无奈要License才能用。想想算了,既然你能用Java搞出来,那我自己整一个出来,高度符合自己使用需求,岂不更妙!

    Go! Go! Go! 动起来!

过程:

    Google一把,使用Java进行SSH连接,找到不少的博客资料,大多都是使用 JSch 来实现远端链接进行操纵的,那就来了解下它吧,如果满足最基础的几点要求(1、远端链接;2、SFTP上传文件;3、远端执行命令)就可以开始动手Code了。

    JSch 官网:http://www.jcraft.com/jsch/, 嗯,老旧的版面风格,还大绿色的,比OSC的的绿色还亮眼啊!不过好东西还挺多的,各种纯JAVA实现的工具,不过暂时我不关心它们,我就了解下JSch。嗯,很好,支持SSH2链接远端,支持文件上传操作,支持远端执行命令。OK,可以动手Code了,容我找找它的MAVEN地址。Oh, shit! 最后更新时间16年9月,看样子不是发展到头了,就是没人维护了。再搜罗一下,应该还有同类开源包,若不其然,Apache有在维护一个项目:SSHD,这次先看看它的MAVNE更新情况再说。嗯,不错,18年还有更新,那继续吧!

    SSHD 官网:http://mina.apache.org/sshd-project/,同样了解下它是否满足我的基础要求。ok,同样满足,那不多说咯,了解Api,开始上手了。

    0、MAVEN配置

<dependency>
    <groupId>org.apache.sshd</groupId>
    <artifactId>sshd-core</artifactId>
    <version>1.7.0</version>
</dependency>

    1、远端链接

SshClient client = SshClient.setUpDefaultClient();
client.start();

ConnectFuture connectFuture = client.connect("user", "ip", port);   // 建立连接
connectFuture.await();

ClientSession session = connectFuture.getSession();
session.addPasswordIdentity(remoteLink.getPassword());
AuthFuture authFuture = session.auth(); // 验证身份
authFuture.await();

if(!authFuture.isSuccess()) {
    System.out.println("远端连接失败!");
}

SftpClient sftpClient = session.createSftpClient(); // 建立sftp连接

    2、SFTP上传文件

OutputStream outputStream = sftpClient.write("remoteFile");
Files.copy(Paths.get("localFile"), outputStream);
outputStream.close();

    3、远端执行命令

session.executeRemoteCommand("cmd", System.out, StandardCharsets.UTF_8);

    SSHD的使用异常简单,就上面的几行代码就达到了我的目的。

    使用SSHD构建一个完整的项目,实现远端一键部署的需求,代码参见:https://github.com/clyy/remote-deploy

-----------------------------------------------------------------------------------------------------------------------------------------------

    注意:远端执行命令,是non-interactive + non-login模式,在执行命令时不会加载环境变量配置,这就会引起一些意外,比如乱码。对于这种情况,建议手动强制进行环境变量加载,相关内容可以参考: