Maven打包成RPM RPM全称是 Red Hat Package Manager(Red Hat包管理器)。几乎所有的 Linux 发行版本都使用这种形式的软件包管理安装、更新和卸载软件。
在devops链条上,常见的部署方式是通过持续集成工具如jenkins/CI 构建和发布jar包到服务端制定目录。不过随着越来越多的应用趋向于paas 平台,本地化自动部署的需求越来越多,在软件包的安装过程中各种自动控制命令的集成也越来越复杂,jenkins等部署方式已经无法满足需求,这时候将软件包和集成脚本一起打包成rpm包的形式,也是一种另外的思路。对于最终用户来说,使用 RPM所提供的功能来维护系统是比较容易和轻松的。安装、卸载和升级RPM软件包只需一条命令就能搞定。 后续还可以构建yum本地源,通过ambari等其他集成工具,进行对软件包的安装、管理、监控、卸载、升级全生命周期的管控
利用rpm-maven-plugin插件实现rpm构建,以便于RPM软件仓库管理。 包含四个部分:
基本单项目 打包成rpm
多module 项目打包成rpm
纯前端项目 打包成rpm
rpm script 应用-通过自动创建软连接实现rpm包自动升级
备注:
rpm-maven-plugin 需要在linux 机器上才能正常运行,运行机器需要
一、基础项目打包 pom文件配置
工程信息,声明rpm包要用到的相关信息,例如project.version、rpm.release、rpm.basedir等等
pom.xml 1 2 3 4 5 6 7 8 9 10 11 <modelVersion > 4.0.0</modelVersion > <groupId > io.github.ifengkou</groupId > <artifactId > web-api</artifactId > <version > 0.0.1-SNAPSHOT</version > <properties > ...... <rpm.release > 0.3.0</rpm.release > <rpm.owner > isuhadoop</rpm.owner > <rpm.basedir > /data/micro-services/9090-web-api-jar</rpm.basedir > </properties >
pom文件中加入plugin,执行 maven clean package 可以直接打包
pom.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 <plugin > <groupId > org.codehaus.mojo</groupId > <artifactId > rpm-maven-plugin</artifactId > <version > 2.1.5</version > <extensions > true</extensions > <executions > <execution > <goals > <goal > rpm</goal > </goals > </execution > </executions > <configuration > <prefix > {install_dir}</prefix > <copyright > GPL (c) 2005, SWWDC</copyright > <distribution > loganshen</distribution > <group > ifengkou.github.io</group > <packager > loganshen</packager > <prefix > ${rpm.basedir}</prefix > <name > web-api</name > <version > ${project.version}</version > <autoProvides > false</autoProvides > <autoRequires > false</autoRequires > <needarch > noarch</needarch > <targetOS > linux</targetOS > <release > ${rpm.release}</release > <requires > <require > java-1.7.0 >= 1.7</require > </requires > <mappings > <mapping > <directory > ${install_dir}/jars</directory > <username > tomcat</username > <groupname > tomcat</groupname > <sources > <source > <location > target/${project.artifactId}-${project.version}</location > </source > </sources > </mapping > <mapping > <directory > ${install_dir}/bin</directory > <filemode > 755</filemode > <username > tomcat</username > <groupname > tomcat</groupname > <sources > <source > <location > ${basedir}/scripts</location > </source > </sources > </mapping > </mappings > </configuration > </plugin >
二、多module 打rpm包 加了rpm包插件后,为了在构建时,不影响日常研发测试,所以在打包的rpm插件配置中,不能将其放入maven 的lifecycle
日常构建,打jar包:
发布rpm包:
1 mvn clean package rpm:attached-rpm -U
父项目(配置空rpm) – controller -打最终的rpm 包 – service(配置空rpm) – dao(配置空rpm) – model(配置空rpm)
父项目需要配置 空的rpm配置,其他所有子module 都需要配置,否则就会报错。
其中<phase>none</phase>
表示:unbinds rpm creation from maven lifecycle。这样在构建时,只有在显示指定 rpm:attached-rpm
时,才会主动构建rpm包,否则不会触发。
其中 <directory>/tmp</directory>
并不存在,所以不会打包任何东西到rpm中
pom.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <plugin > <groupId > org.codehaus.mojo</groupId > <artifactId > rpm-maven-plugin</artifactId > <version > 2.1.5</version > <inherited > false</inherited > <executions > <execution > <phase > none</phase > <goals > <goal > attached-rpm</goal > </goals > </execution > </executions > <configuration > <release > 1</release > <copyright > GPL (c) 2005, SWWDC</copyright > <distribution > loganshen</distribution > <group > ifengkou.github.io</group > <packager > loganshen</packager > <prefix > /opt/soft</prefix > <mappings > <mapping > <directory > /tmp</directory > </mapping > </mappings > </configuration > </plugin >
controller 项目是可执行jar包最终打包文件,这个与其他module 不一样
pom.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 <plugin > <groupId > org.codehaus.mojo</groupId > <artifactId > rpm-maven-plugin</artifactId > <version > 2.1.5</version > <executions > <execution > <id > generate-rpm</id > <phase > none</phase > <goals > <goal > attached-rpm</goal > </goals > </execution > </executions > <configuration > <license > GPL (c) 2005, SWWDC</license > <distribution > loganshen</distribution > <group > ifengkou.github.io</group > <packager > loganshen</packager > <name > rpm-package-name</name > <prefix > ${rpm.basedir}</prefix > <version > ${project.version}</version > <autoProvides > false</autoProvides > <autoRequires > false</autoRequires > <needarch > noarch</needarch > <targetOS > linux</targetOS > <release > ${rpm.release}</release > <defineStatements > <defineStatement > _unpackaged_files_terminate_build 0</defineStatement > </defineStatements > <mapping > <directory > ${rpm.basedir}/${rpm.release}/jars</directory > <sources > <source > <location > ${basedir}/target/web-api.jar</location > </source > </sources > </mapping > <mapping > <directory > ${rpm.basedir}/${rpm.release}/bin</directory > <sources > <source > <location > ${basedir}/../builder/scripts</location > </source > </sources > </mapping > </mappings > </configuration > </plugin >
三、前端项目打包 前后端分离,前端使用npm run build 构建,生产dist 静态文件,需要在构建时执行shell脚本进行项目构建。构建后需要将生产的目标文件夹倒入到rpm包中
这里用到两个maven plugin:exec-maven-plugin
和 rpm-maven-plugin
先利用exec-maven-plugin
执行shell脚本对工程进行打包生成静态文件,再利用 rpm-maven-plugin
进行rpm打包
日常构建可以通过 mvn clean install 进行构建(需要跳过测试):
1 mvn clean install -Dmaven.test.skip=true
rpm打包可以通过:
1 mvn clean install rpm:attached-rpm -Dmaven.test.skip=true -U
pom.xml
pom.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <groupId > io.github.ifengkou</groupId > <artifactId > front-web</artifactId > <version > 1.0</version > <properties > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > <rpm.release > 2.9.4</rpm.release > <rpm.basedir > /data/micro-services/front-web</rpm.basedir > </properties > <pluginRepositories > <pluginRepository > <id > central</id > <url > http://maven.aliyun.com/nexus/content/groups/public/</url > </pluginRepository > </pluginRepositories > <repositories > <repository > <id > central</id > <name > alimaven</name > <url > http://maven.aliyun.com/nexus/content/groups/public/</url > <layout > default</layout > <releases > <enabled > true</enabled > </releases > <snapshots > <enabled > true</enabled > </snapshots > </repository > </repositories > <build > <plugins > <plugin > <groupId > org.codehaus.mojo</groupId > <artifactId > exec-maven-plugin</artifactId > <version > 1.5.0</version > <executions > <execution > <id > npm_build</id > <phase > install</phase > <goals > <goal > exec</goal > </goals > <configuration > <executable > ${basedir}/npmbuild.sh</executable > </configuration > </execution > </executions > </plugin > <plugin > <groupId > org.codehaus.mojo</groupId > <artifactId > rpm-maven-plugin</artifactId > <version > 2.1.5</version > <executions > <execution > <id > generate-rpm</id > <phase > none</phase > <goals > <goal > attached-rpm</goal > </goals > </execution > </executions > <configuration > <license > GPL (c) 2005, SWWDC</license > <distribution > loganshen</distribution > <group > ifengkou.github.io</group > <packager > loganshen</packager > <prefix > ${rpm.basedir}</prefix > <name > front-web</name > <version > ${project.version}</version > <autoProvides > false</autoProvides > <autoRequires > false</autoRequires > <needarch > noarch</needarch > <targetOS > linux</targetOS > <release > ${rpm.release}</release > <defineStatements > <defineStatement > _unpackaged_files_terminate_build 0</defineStatement > </defineStatements > <mappings > <mapping > <directory > ${rpm.basedir}/${rpm.release}</directory > <username > tomcat</username > <groupname > tomcat</groupname > <sources > <source > <location > ${basedir}/dist</location > </source > </sources > </mapping > </mappings > <postinstallScriptlet > <script > ln -s ${rpm.basedir}/${rpm.release}/server ${rpm.basedir}/server; chown -R isuhadoop:isuhadoop ${rpm.basedir}; </script > </postinstallScriptlet > <postremoveScriptlet > <script > echo "remove symbolic link " ; rm -rf ${rpm.basedir}/server; echo "uninstall success" ; </script > </postremoveScriptlet > </configuration > </plugin > </plugins > </build > </project >
npmbuild.sh为前端工程 build 命令,最终在当前目录生成 dist 的静态文件夹
1 2 3 4 5 # !/bin/sh echo "start npm install......" npm install echo "start npm run build ......" npm run build
生成 dist 的静态文件夹后,只需要通过rpm plugin 的mapping 将该目录打包到rpm的指定目录,后续可以通过nginx 代理到该目录的index.html
四、rpm script 应用-通过自动创建软连接实现rpm包自动升级 例如web-api服务,通过rpm安装之后的路径是/opt/soft/web-api-1.0。然后rpm那能自动创建一个软链接/opt/soft/web-api连接到/opt/soft/web-api-1.0.0,之后如果要升级到web-api-1.1只需要通过rpm包安装web-api-1.1,rpm包自动将/opt/soft/web-api连接到web-api-1.1上。
rpm-plugin 配置
pom.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 <plugin > <groupId > org.codehaus.mojo</groupId > <artifactId > rpm-maven-plugin</artifactId > <version > 2.1.5</version > <executions > <execution > <id > generate-rpm</id > <phase > none</phase > <goals > <goal > attached-rpm</goal > </goals > </execution > </executions > <configuration > <license > GPL (c) 2005, SWWDC</license > <distribution > loganshen</distribution > <group > ifengkou.github.io</group > <packager > loganshen</packager > <prefix > ${rpm.basedir}</prefix > <name > web-api</name > <version > ${project.version}</version > <autoProvides > false</autoProvides > <autoRequires > false</autoRequires > <needarch > noarch</needarch > <targetOS > linux</targetOS > <release > ${rpm.release}</release > <defineStatements > <defineStatement > _unpackaged_files_terminate_build 0</defineStatement > </defineStatements > <mappings > <mapping > <directory > ${rpm.basedir}/${rpm.release}/jars</directory > <sources > <source > <location > ${basedir}/target/${project.artifactId}-${project.version}.jar</location > </source > </sources > </mapping > <mapping > <directory > ${rpm.basedir}/${rpm.release}/bin</directory > <sources > <source > <location > ${basedir}/scripts</location > </source > </sources > </mapping > </mappings > <preinstallScriptlet > <scriptFile > install/preinstall.sh</scriptFile > <fileEncoding > utf-8</fileEncoding > </preinstallScriptlet > <postinstallScriptlet > <script > ln -s ${rpm.basedir}/${rpm.release}/bin ${rpm.basedir}/bin; ln -s ${rpm.basedir}/${rpm.release}/jars ${rpm.basedir}/jars; chown -R ${rpm.owner}:${rpm.owner} ${rpm.basedir}; </script > </postinstallScriptlet > <preremoveScriptlet > <scriptFile > install/preremove.sh</scriptFile > <fileEncoding > utf-8</fileEncoding > </preremoveScriptlet > <postremoveScriptlet > <scriptFile > install/postremove.sh</scriptFile > <fileEncoding > utf-8</fileEncoding > </postremoveScriptlet > </configuration > </plugin >
有用到了 scriptFile 和 scrpit,scriptFile 没找到怎么传参数,像${rpm.basedir}之类的没法传进去;script 不适合写复杂的shell。还有一种方式是<script>sh ${rpm.basedir}/shell/xxx.sh ${param1} ${param2} </script>
,不过要提前将脚本通过mapping复制到${rpm.basedir}/shell,所以只能在postinstall 后用
install/preinstall.sh
主要是为了初始化用户之类的,比如允许web-api 需要特定的用户,那么可以在这个脚本中检测,如果不存在这个用户则创建
install/preremove.sh
主要是为了在卸载rpm 时,检测该安装服务是否在运行,如果在运行,则通过命令先shutdown
postinstallScriptlet
主要是为了在安装完成后,创建软连接、对目录或者文件进行chown/chmod,或者是创建service ,自启动等等,根据需求来
install/postremove.sh
主要是为了在卸载完成后,主动去删除 安装完成后创建的软连接
以下脚本仅做参考:
preinstall.sh
preinstall.sh 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 echo "hi,preinstall" ROOT="/data/micro-services/9090-web-api" echo ${ROOT} id isuhadoop have_user=$? if [ ${have_user} -ne 0 ];then echo "add isuhadoop user" useradd isuhadoop fi if [ -d ${ROOT} ];then echo "${ROOT} is existed" else echo "mkdir -p ${ROOT}" mkdir -p ${ROOT} chmod 777 ${ROOT} fi
postinstall.sh
postinstall.sh 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # !/bin/bash echo "hi,pre uninstall" ROOT="/data/micro-services/9090-web-api" set +e if test -f ${ROOT}/bin/lryhis.pid ; then if test -f ${ROOT}/bin/shutdown.sh ;then echo "try to shutdown the service: sh bin/shutdown.sh" sh ${ROOT}/bin/shutdown.sh kill_state=$? if [ ${kill_state} -ne 0 ];then echo "shutdown failed" fi fi fi set -e
postremove.sh
postremove.sh 1 2 3 4 5 6 #!/bin/bash echo "hi,after uninstall,remove base dir & symbolic link" ROOT="/data/micro-services/9090-web-api" echo "remove symbolic link " rm -rf ${ROOT} /bin ${ROOT} /jars echo "uninstall success"
参考 https://www.mojohaus.org/rpm-maven-plugin/adv-params.html
https://www.mojohaus.org/exec-maven-plugin/