该方法适用于maven构建的项目,自动部署需要用到maven插件wagon-maven-plugin

当配置插件后,部署流程如下:

  1. 客户端通过maven打包项目(package)
  2. 插件会自动将包上传到配置的服务器
  3. 插件调用wagon-ssh库执行部署脚本

上述流程中每次都需要手动操作的就只有第1条,其他都可以自动完成,这种方案很适用于开发过程中的测试部署,具体配置方法如下(想直接查看所有配置的代码见文末配置代码)。

配置wagon-maven-plugin

配置wagon-maven-plugin分为4个部分:

  1. 配置服务器认证
  2. 配置插件执行阶段(阶段简单说就是插件的执行时机,比如package之后,可以搜索maven生命周期关键词了解)。
  3. 配置上传包的目标(目标简单说就是要插件做的事情,一个插件可以做很多事情,一件事情就是一个目标)
  4. 配置执行部署脚本目标

1. 配置服务器认证

在maven的配置文件settings.xml(一般在用户目录下的.m2文件夹下)中配置服务器认证信息,即用户和密码,找到文件的大概121行可以看到配置server信息的注释,在注释后面添加如下代码。

<server>
    <id>127.0.0.1</id>
    <username>root</username>
    <password>root</password>
</server>

其中,

  • 标签<id>是该配置的唯一编号,后面配置插件连接服务器会用到,建议配置为服务器ip
  • 标签<username>是服务器登录用户名
  • 标签<password>是服务器登录密码

2. 配置插件执行阶段

执行打包命令完成打包后,就要执行插件了,那么插件的执行时机就是package。pom.xml中新增如下代码。

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>wagon-maven-plugin</artifactId>
    <version>2.0.0</version>
    <!-- 定义执行 -->
    <executions>
        <execution>
            <id>upload-and-deploy</id>
            <!-- 插件在maven的package阶段执行,即打包后执行 -->
            <phase>package</phase>
        </execution>
    </executions>
</plugin>

其中,

  • 标签<execution>表示定义执行,具体为后面要配置的上传包和执行部署脚本。
  • 标签<id>表示这个执行的id,取一个有意义的名称即可。
  • 标签<phase>表示这个插件在package阶段执行,即打包完成后执行。

简单描述下阶段以及如何配置插件在阶段中执行。比如命令mvn clean package,这个命令中有2个阶段,即cleanpackage,如果想要pluginA插件在package之后执行,就可以执行命令mvn clean package pluginA。如果希望命令简单一些,可以将插件的phase标签配置为package,这时候执行命令mvn clean package就可以达到命令mvn clean package pluginA同样的效果了。更多信息可以搜索maven生命周期关键词了解,不再赘述。

3. 配置上传包的目标

上传目标就是要插件将打好的包上传到服务器,需要配置:

  1. 服务器地址
  2. 上传到的路径
  3. 要上传的包的路径

配置服务器相关信息的代码如下,在<execution>中加入<goals><configuration>标签。

<plugin>
    ...
    <executions>
        <execution>
            ...
            <goals>
                <!-- 上传一次 -->
                <goal>upload-single</goal>
            </goals>
            <configuration>
                <serverId>127.0.0.1</serverId>
                <!-- 本地包位置 -->
                <fromFile>target/my-war-package.war</fromFile>
                <!-- 服务器用户、地址、存放路径 -->
                <url>scp://root@127.0.0.1/root</url>
            </configuration>
        </execution>
    </executions>
</plugin>

其中,

  • 标签<goals>表示目标,有多个目标时按照顺序执行,上传包使用upload-single即可,即上传一次。
  • 标签<configuration>表示服务器和上传路径配置

服务器和上传路径配置中,

  • 标签<serverId>即上面配置的服务器认证的id。
  • 标签<fromFile>表示打包后包的位置,一般都是target下的某个war包。
  • 标签<url>表示使用scp将包拷贝到指定的路径,root 是服务器用户名,@ 后面是服务器地址和存放路径(类似scp命令)。

4. 配置执行部署脚本目标

执行部署脚本目标是当包上传完成后,用于在服务器执行部署脚本的。具体配置如下,在<goals>中加入<goal>,即加入新的目标,多个目标按顺序执行。以及在<configuration>标签中添加<commands><displayCommandOutputs>标签。

<execution>
    ...
    <goals>
        ...
        <!-- 加入执行脚本目标 -->
        <goal>sshexec</goal>
    </goals>
    <configuration>
        ...
        <!-- 执行命令行 -->
        <commands>
            <command>cd /root;./run.sh</command>
        </commands>
        <!-- 客户端打印命令和结果 -->
        <displayCommandOutputs>true</displayCommandOutputs>
    </configuration>
</execution>

其中,

  • 标签<goal> 表示执行ssh命令。
  • 标签<commands> 是要执行的命令行,具体命令在标签<command>中。案列中是进入war包所在目录,然后执行run.sh脚本。
  • 标签<displayCommandOutputs> 表示在客户端打印出执行的命令和命令返回结果。

需要注意的是,commond标签中的命令涉及到目录或文件需要使用全路径,如果不想使用全路径,可以像案列中那样,多条命令用分号隔开合并为一条语句,后面的命令就可以使用相对路径了。

编写部署脚本

这个步骤就是自定义部署的命令了,比如解压war包到目录,重启docker等,当然也可以不通过sh文件执行,也可以在commond标签中直接写命令,但是每一行命令都要使用完整路径,否则就使用案列中的一条语句,多条命令用分号隔开。下面是一个sh脚本示例。

date >> log.txt
ls my-war-package.war >> log.txt
echo deployed successfully >> log.txt

其他说明

wagon-maven-plugin版本说明

案列中采用的插件版本为2.0.0,如果使用1.0,还需要配置wagon-ssh,否则无法正常执行命令,会报错Cannot find wagon which supports the requested protocol: sftp: java.util.NoSuchElementException

<build>
    ...
    <extensions>
        <extension>
            <groupId>org.apache.maven.wagon</groupId>
            <artifactId>wagon-ssh</artifactId>
            <version>3.3.3</version>
        </extension>
    </extensions>
</build>

多个阶段执行命令

案列中将插件配置在package阶段执行,即打包后执行上传和部署,如果在打包之前还要做一些准备工作,比如清理之前的包,关闭容器等,那么可以再配置一个执行(execution)并在clean阶段执行即可,具体代码如下,在id为upload-and-deploy这个执行之前再添加一个id为prepare的执行,就可以在clean之后,package之前执行了。

<plugin>
    ...
    <executions>
        <!-- 新增一个执行 -->
        <execution>
            <id>prepare</id>
            <phase>clean</phase>
            <goals>
                <goal>sshexec</goal>
            </goals>
            <configuration>
                <commands>
                    <!-- 执行准备工作的命令 -->
                    <command>cd /root;echo prepare > log.txt</command>
                </commands>
                <displayCommandOutputs>true</displayCommandOutputs>
            </configuration>
        </execution>

        <!-- 和上面的案例一样 -->
        <execution>
            <id>upload-and-deploy</id>
            ...
        </execution>
    </executions>
</plugin>

FAQ

  • 报错Cannot connect. Reason: invalid privatekey

    错误原因是服务器认证没有配置或者配置不正确,配置方法见上述配置服务器认证

  • 报错Cannot find wagon which supports the requested protocol: sftp: java.util.NoSuchElementException

    错误原因是wagon-maven-plugin插件使用的1.0版本,并且没有配置wagon-ssh库,配置方法见上述wagon-maven-plugin版本说明

附件:配置代码

  • 服务器认证配置

    配置到maven的settints.xml中。

    <server>
        <id>127.0.0.1</id>
        <username>root</username>
        <password>root</password>
    </server>
    
  • pom.xml配置

    配置到pom.xml的plugins标签中。

    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>wagon-maven-plugin</artifactId>
        <version>2.0.0</version>
        <executions>
            <execution>
                <id>upload-and-deploy</id>
                <phase>package</phase>
                <goals>
                    <goal>upload-single</goal>
                    <goal>sshexec</goal>
                </goals>
                <configuration>
                    <serverId>127.0.0.1</serverId>
                    <fromFile>target/my-war-package.war</fromFile>
                    <url>scp://root@127.0.0.1/root</url>
                    <commands>
                        <command>cd /root;./run.sh</command>
                    </commands>
                    <displayCommandOutputs>true</displayCommandOutputs>
                </configuration>
            </execution>
        </executions>
    </plugin>