I must confess I'm new to maven world after years of living in the world of monstrous debuild/ant/makefile chimeric constructions. I just don't have yet that very feeling which helps seasoned developer to choose right decisions, and it's looks like there are plenty different ways in maven.
So, I have a simple project containing of web-app. I want basically following:
For distinguishing between development and production I've created profiles, dev
and prod
. The dev
profile is activated by default. When I want to deploy something to production, I just type mvn -P prod tomcat:deploy
I've read about release plugin, as well as about buildnumber plugin. But I'm just not sure I'm going the right way.
So, the question is - what is the most succint, self-contained and "mavenish" way to resolve the task I'm asking about.
Deploy should mean take all of my artifacts and either copy them to a server, or execute them on a server. It should truly be a simple process. Build means, process all of my code/artifacts and prepare them for deployment. Meaning compile, generate code, package, etc.
Shabunk, as I was commented out, Maven is driving you on the best way to do what you want, inheriting from years of developpers experience.
I would explain what I would (and what I myself really) do.
So you're right to use Maven Release Plugin, plus another one (cargo for instance) You're trying to do two differents things :
Maven Release Plugin
Consider that your own process is maybe ligher than other dev teams are used to. I mean that there is more steps between unit testing and production deployment in larger teams (Q&A, user acceptance, non regression campains). It seems that you make a shortcut linking tag and production deployement. If you want to deploy your webapp on different environnements (integration, user acceptannce, performance, preprod, and so on) you had to identify your version and had to be able to build it again (sure and "repeatable").
That what maven-release-plugin is intended to. It helps you to verify that your source code is clean (all files under source control, with no modification), can compile and pass all tests phases. Then, it deals with pom version and tagging, and finish by storing it for later use in you Maven enterprise repository.
You have many configurations to set up (ditributionManagement, SCM, maven plugin release configuration). But once it is in place, releasing version stand in one simple command line :
mvn release:prepare release:perform
If you want some examples, I can give you some.
<scm> <!-- Base URL repository --> <url>scm:svn:http://svn.myorg.corp/svn/repository/</url> <!-- Developper URL (from trunk or branche) --> <developerConnection>scm:svn:http://svn.myorg.corp/svn/repository/trunk/project1</developerConnection> <connection>scm:svn:http://svn.myorg.corp/svn/repository/trunk/project1</connection> </scm> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-scm-plugin</artifactId> <version>1.6</version> <configuration> <username>${from.settings.xml.user}</username> <password>${from.settings.xml.password}</password> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-release-plugin</artifactId> <version>2.2.2</version> <configuration> <tagBase>http://svn.myorg.corp/svn/repository/tags/</tagBase> <scmCommentPrefix>[DEV#SCM]</scmCommentPrefix> </configuration> </plugin> </plugins> [...] </build> <distributionManagement> <repository> <id>enterprise_repo</id> <name>Enteprise Repository on Artifactory - Stable versions</name> <url>http://repo.corp:8080/artifactory/prj-xxx-releases</url> </repository> <snapshotRepository> <id>enterprise_repo</id> <name>Enteprise Repository on Artifactory - DEV versions</name> <url>http://repo.corp:8080/artifactory/prj-xxx-snapshots</url> </snapshotRepository> <site> <id>corporate_site</id> <name>Corporate public site</name> <!-- must add wagon plugin that support this protocol --> <url>ftp://...</url> </site> </distributionManagement>
Deployement
Once again, you may have multiple environnements on which you want to test your app against. There is many plugins that allow you to send and deploy your war : the general cargo-plugin, or more specific ones tomcat-plugin, glassfish-plugin, ... Plugins are giving you the hability to do what you want. Then, configuration can be performed in many ways.
Full Maven way : The full integrated way with Maven is to use Profile and maybe Filters. Profiles let describe properites and behaviour, as you seem to know. Filters are kind of .properties grouping a set of variable that will be used to replace patterns in you xml configuration file into the war (for instance, db connection). It's not the one I use because I find it less flexible than externalizing files. But no matter
Maven with its ecosystem: The way I prefer is to build my apps with Maven and Jenkins (or Continous Integration tool). This is why I'm agree with Aaron when he says that you had to konw limitations of your tools. Using Jenkins, I run every hours/day my application against Unit Tests, generatio Q&A reports, documentation, ... I have a release build that help me to produce all I want to deliver it (to my test team or my customer), and I provide some information to my jobs to deploy it onto different environnements (using maven profiles or jenkins built-in configuration).
It works really fine for me, and I'm pretty sure this is the right way to do.
[EDIT]
Deployment
Once again, deployment mean different phases of Lifecycle.
Local / Dev environnement
I'd never use tomcat:deploy until now, but only because I'd prefer using jetty as light web container (and well integrated with maven). But I'm pretty sure that every kinf of configuration would fit your needs here.
Continuous Integration Environnement In an continous integration environnement, I usually copy the war directly with Jenkins (exporting *.war on the desired machine). The way I do depends on many things :
Most of time, it's a simple copy. If I can't, I use some integrated maven plugins (like jahia:deploy plugin for the famous CMS : www.jahia.com), or just cargo plugin : http://cargo.codehaus.org/Maven2+plugin. I don't have any example, but it's really easy to find some on internet because this configuration is often recommanded.
Q&A / Acceptance / Production environnement
For those kind of environnements, which often (as far I as I saw in my job) deals with Service Level Agreement, we (I or admin team) wrote some specific scripts. I'm sure you will be desapointed, but as I mentionned, I don't rely on Maven for everything, and for deployement in particular. IMHO, this is one limit of this tool. You can maybe rely on cargo plugin, or specific ones, but releasing a version, or building one don't match (in time sequence) with real deployement. Even more, I didn't find any plugin that allow me easily to deploy on multiple instances ... and even worth you had to shutdown instances in a specific order (SLA's needs). That said, I didn't mentionned external properties, or SQL scripts, or anything else. They are additional reasons to rely on a dedicated tool.
So, generally, we wrote our own ant / sell scripts. If somebody else have better solutions, I'm obviously interrested in !
I hope I was clear enough.
Regards.
The original question asked for "the best practice" to do production deploys with Maven. I expected to get more than one "best practice" and offered the bounty to see different solutions and learn from them. I do not care if they are pure maven solutions or if they utilize different tools.
Parallel to this thread I did also some researching and would like to post here the different approaches I am seeing. I tried 1) and 3), they are pure maven and regardless what Aaron is saying, they are working also.
In my current project I have a development environment, a test environment, a staging environment and a production environment. From my maven pom I would like to work with the development environment and deploy only to the test environment. I see the following approaches with maven pom:
In all solutions I am using integration test (surefire plugin), version plugin and release plugin for building the war. For the deployment I am implementing approach number 3 following the arguments from https://stackoverflow.com/a/1151870/734687 (a post which expresses very good what I also prefer).
Since the application has to work unchanged in all environment you have to distinguish the different settings on runtime and that can be very complicated. Our operational team wants to have settings per application outside the container so I support an environment var which points me to the proper directory but is optional. If nothing is set then I use the development settings inside the war. See a Spring sample here:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="ignoreResourceNotFound" value="true"/> <property name="locations"> <list> <value>classpath:META-INF/spring/*.properties</value> <value>file:///${picservice.configdir:-}/*.properties</value> </list> </property> </bean>
The properties in the META-INF/spring dir are loaded always. Additionaly I integrate properties from the file system which can override the properties above. If no properties are found this will not trigger an exeception because I set ignoreResourceNotFound
. If the property picservice.configdir
is set it directs me to an directory, if not than I provided a default value with :
. The -
says that I want to have no value which is the current directory.
For logging I have a similar solution. You can find very interesting articles about properties file handling with Spring at following links:
I found an interesting presentation about this topic, see Automated Deployment with Maven and friends.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With