Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The simplest way to deploy to production with builds

Tags:

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:

  • deploy to development Tomcat (I'm using tomcat:deploy), then do nothing.
  • deploy to production Tomcat, but before deployment update git repo, add tagged commit and upgrade build version.

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.

like image 575
shabunc Avatar asked Feb 14 '12 15:02

shabunc


People also ask

How do you deploy a build?

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.


2 Answers

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 :

  • Identifying a unique version, which means tagging it, and updating pom for a new version
  • Deploying your app (no matter which environnement it is)

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 :

  • if CI soft is on the same (physical|virtual) server than your app server (Tomcat, Jboss, Weblogic, Glassfish, ...), or distant one => copy time will outstand server refresh time and will produce unsafe deployement (generally corrupted archives)
  • if server is supporting hot reloading (exploded war in web-apps for Tomcat) or at least aware of file system modifications (full war in /deploy for JBoss)
  • if you need to stop your server before, ...

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.

like image 82
Jean-Rémy Revy Avatar answered Oct 11 '22 23:10

Jean-Rémy Revy


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:

  1. profiles with filtering properties
    When working with this approach the deliverable (the war file) has to be rebuilded for different environments. This forced me to offer the bounty because I didn't like that.
  2. profiles wit Maven WAR overlays or assembly plugin
    This also generated different artefacts for different platforms. But instead of rebuilding the war file it will be unpacked/patched/repacked (for the war overlay) or build and packed with different settings (assembly plugin). I didn't like this solution either.
  3. A deployment plugin (eg. Cargo plugin) without profiles
    Specify the complete build with installation and also include the cargo plugin doing a remote deployment but not connect it to any phase. So I always work with the development environment but when I explicitely call the cargo plugin it deploys the war from the repository to a container (the test environment). I can even use profiles to distinguish between different containers just for the deployment via cargo.

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:

  • http://springtips.blogspot.co.at/2008/09/configuring-applications-with-spring.html
  • http://www.summa-tech.com/blog/2009/04/20/6-tips-for-managing-property-files-with-spring/
  • and a similar discussion here: Using Maven for multiple deployment environment (production/development)

I found an interesting presentation about this topic, see Automated Deployment with Maven and friends.

like image 31
ChrLipp Avatar answered Oct 11 '22 21:10

ChrLipp