How to implement continuous deployment for a web service - maven

I have a Java application, which runs inside web container (Jetty at the moment) and responds to requests via web services.
Now I want to create a mechanism, which allows to deploy (transfer the WAR file to the server, install the new version there) a new version of the application to Amazon EC2 instance as easily as possible (ideally - by running some Maven command).
I'm using Beanstalk for my version control and they offer deployment support, but I couldn't figure out how to apply it to my scenario.
Are there any tutorials on how to deploy web applications to Amazon EC2 with Maven (with or without Beanstalk) ?
Update 1 (10.04.2013): Beanstalk staff has recommended me to use SSH deployments.
Update 2 (11.04.2013 23:17 MSK):
In my first attempt to use Maven Cargo plugin, I added following stuff to my pom.xml:
<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>
[...]
<build>
[...]
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<configuration>
<container>
<containerId>Heaven7</containerId>
<type>remote</type>
</container>
<configuration>
<type>runtime</type>
<properties>
<cargo.remote.username>myusername</cargo.remote.username>
<cargo.remote.password>mypassword</cargo.remote.password>
</properties>
</configuration>
<!-- Deployer configuration -->
<deployer>
<type>remote</type>
</deployer>
<deployables>
<deployable>
<groupId>ru.mycompany</groupId>
<artifactId>my-product</artifactId>
<type>war</type>
</deployable>
</deployables>
</configuration>
</plugin>
</plugins>
</build>
[...]
</project>
Then I ran mvn cargo:deploy and got following output:
[ERROR] Failed to execute goal org.codehaus.cargo:cargo-maven2-plugin:1.3.3:dep
oy (default-cli) on project [...]: Execution default-cli of goal org.codeh
us.cargo:cargo-maven2-plugin:1.3.3:deploy failed: Cannot create configuration.
here's no registered configuration for the parameters (container [id = [Heaven7
, type = [remote]], configuration type [runtime]). Actually there are no valid
ypes registered for this configuration. Maybe you've made a mistake spelling it
2 questions:
How can I fix it?
Where can I specify the address my Tomcat container?
Update 3 (12.04.2013 22:36 MSK):
I changed the section related to Cargo plugin like this:
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.3.3</version>
<configuration>
<container>
<containerId>tomcat7</containerId>
<type>remote</type>
</container>
<configuration>
<type>runtime</type>
<properties>
<cargo.remote.username>myuser</cargo.remote.username>
<cargo.remote.password>mypassword</cargo.remote.password>
<cargo.hostname>ec2-NN-NNN-NN-NN.compute-1.amazonaws.com</cargo.hostname>
<cargo.protocol>http</cargo.protocol>
<cargo.servlet.port>8080</cargo.servlet.port>
</properties>
</configuration>
<!-- Deployer configuration -->
<deployer>
<type>remote</type>
</deployer>
<deployables>
<deployable>
<groupId>ru.mycompany</groupId>
<artifactId>myproduct</artifactId>
<type>war</type>
</deployable>
</deployables>
</configuration>
</plugin>
</plugins>
Then I executed mvn cargo:deploy and got this output:
[ERROR] Failed to execute goal org.codehaus.cargo:cargo-maven2-plugin:1.3.3:depl
oyer-deploy (default-cli) on project ccp-server: Execution default-cli of goal o
rg.codehaus.cargo:cargo-maven2-plugin:1.3.3:deployer-deploy failed: Cannot creat
e configuration. There's no registered configuration for the parameters (contain
er [id = [tomcat7], type = [remote]], configuration type [runtime]). Actually th
ere are no valid types registered for this configuration. Maybe you've made a mi
stake spelling it? -> [Help 1]
Update 4 (12.04.2013 23:12):
I changed pom.xml once again to:
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.3.3</version>
<configuration>
<container>
<containerId>tomcat7x</containerId>
<type>remote</type>
</container>
<configuration>
<type>runtime</type>
<properties>
<cargo.remote.username>myuser</cargo.remote.username>
<cargo.remote.password>mypassword</cargo.remote.password>
<cargo.hostname>ec2-NN-NNN-NN-NN.compute-1.amazonaws.com</cargo.hostname>
<cargo.protocol>http</cargo.protocol>
<cargo.servlet.port>8080</cargo.servlet.port>
</properties>
</configuration>
<!-- Deployer configuration -->
<deployer>
<type>remote</type>
</deployer>
<deployables>
<deployable>
<groupId>ru.mycompany</groupId>
<artifactId>myproduct</artifactId>
<type>war</type>
</deployable>
</deployables>
</configuration>
</plugin>
Then, I used following commands to deploy my application to the server:
mvn clean
mvn install
mvn cargo:deploy
Please note that <packaging> must be set to war in order for this sequence to work (otherwise you may get strange error messages).

You could use the cargo maven plugin to deploy on a remote server. See this example for a remote deployment on a Tomcat server : Maven: How do I deploy my WAR file to a remote Tomcat server?

Please correct me if I'm wrong. I understand that you're using the Tomcat version 7. The Cargo configuration for Tomcat 7 should be as the following: -
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.3.3</version>
<configuration>
<container>
<containerId>tomcat7x</containerId>
<type>remote</type>
</container>
<configuration>
<type>runtime</type>
<properties>
<cargo.remote.username>myusername</cargo.remote.username>
<cargo.remote.password>mypassword</cargo.remote.password>
<cargo.hostname>MY_HOST</cargo.hostname>
<cargo.protocol>http</cargo.protocol>
<cargo.servlet.port>SERVER_PORT</cargo.servlet.port>
</properties>
</configuration>
<!-- Deployer configuration -->
<deployer>
<type>remote</type>
<deployables>
<deployable>
<groupId>ru.mycompany</groupId>
<artifactId>my-product</artifactId>
<type>war</type>
<properties>
<context>MY_CONTEXT</context>
</properties>
</deployable>
</deployables>
</deployer>
</configuration>
</plugin>
Please note that
<cargo.hostname> is the remote host name or ip address.
<cargo.protocol> is either http or https.
<cargo.servlet.port> is the remote port based on the <cargo.protocol>, e.g. 8080 or 8443
<context> is the context name to use when deploying the web application.
Please refer to Cargo: Tomcat 7.x and Maven2 Plugin Reference Guide for further information.
I hope this may help.

As Charlee and Dmitri answered earlier, the cargo plugin would usually be the easiest way to go.
While doing that, you might also consider the way you actually create your EC2 instances (as in many scenarios, both dev/test ones and production ones) you would like to always create fresh instances (see Martin Fowler's thoughts on this at http://martinfowler.com/bliki/PhoenixServer.html and http://martinfowler.com/bliki/SnowflakeServer.html .
An interesting solution for doing so is provided by Ravello Systems, which basically lets you easily create a full blown replica of an application in the cloud, and they even implemented a maven plugin to help in automating that. Take a look at http://www.ravellosystems.com/blog/ravello_maven_plugin/ - you can tie the whole process together end-to-end with maven - from creating the environment to deploying the application, testing it, and tearing it down.

Related

Cargo:run If you specify a containerId, you also need to specify a containerUrl

I am trying to run tomcat though cargo. Tomcat is already installed. cargo:deploy is working fine but when I try cargo:run I get the following error
If you specify a containerId, you also need to specify a containerUrl.
If I specify a containerURL I get the following error
[ERROR] Failed to execute goal org.codehaus.cargo:cargo-maven2-
plugin:1.4.13:run (default-cli) on project ctm: Unable to parse configuration
of mojo org.codehaus.cargo:cargo-maven2-plugin:1.4.13:run for parameter
containerURL: Cannot find 'containerURL' in class org.codehaus.cargo.maven2.configuration.Container
...
This is my Maven config
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.4.13</version>
<configuration>
<container>
<type>existing</type>
<containerId>${cargo.maven.containerId}</containerId>
<home>${container.home}</home>
</container>
<configuration>
<type>existing</type>
<home>${container.home}</home>
</configuration>
<deployables>
<deployable>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<type>war</type>
<properties>
<context>example</context>
</properties>
</deployable>
</deployables>
</configuration>
<executions>
<execution>
<id>run</id>
<configuration>
<configuration>
<type>existing</type>
</configuration>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
this is my profile
<profile>
<id>developer-properties</id>
<properties>
<cargo.maven.containerId>tomcat7x</cargo.maven.containerId>
<container.home>C:/apache-tomcat-7.0.35</container.home>
</properties>
</profile>
According to cargo documentation; type "existing" should use an existing container installation. I don't think I need containerURL unless the type is "standalone". I don't understand why I'm getting the containerURL error.
Documentation on type is here: https://codehaus-cargo.github.io/cargo/Existing+Local+Configuration.html
I think the documentation is unclear. I think cargo:run always uses a standalone local configuration, hence the description
If the plugin configuration defines a container with a standalone
local configuration, it will create the configuration.
So it's probably ignoring your existing local configuration.

Using cargo maven plugin to start the server without artifact deployment

I'm trying to use the cargo maven plugin just to start a JBoss AS 7 server from maven, without executing any deployments.
I'm able to start the server but as I can read in cargo pluging documentation the goals cargo:run and cargo:start will deploy automatically the current project if project's packaging is Java EE (WAR, EAR, etc.) and if I'm not using deployable sections in the plugin configuration.
This is my simple cargo plugin section in the pom file:
<plugins>
...
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.4.13</version>
<configuration>
<!-- Container configuration -->
<container>
<containerId>jboss73x</containerId>
<home>${jboss-as.home}</home>
</container>
</configuration>
</plugin>
...
</plugins>
Since I'm not using deployables and the project packaging is war, cargo automatically deploys my project when the server starts.
I would like use the goal cargo:run just to start my local server without deploy any project artifacts.
Is it possible with the cargo maven plugin? Any idea or alternative?
I think that it might not be possible to ask the plugin not to deploy the project in which it is configured, when you are in the case of a deployable archive project.
But what you could do is creating a pom project, with no source in it just the pom.xml, and run your cargo plugin in that project.
My example below starts and stops the cargo plugin when I run the goal install on it :
<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>fr.fabien.perso</groupId>
<artifactId>pom-project-tests</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<executions>
<execution>
<id>start-container</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop-container</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
<configuration>
<container>
<type>embedded</type>
</container>
</configuration>
</plugin>
</plugins>
</build>
</project>
Yes Yersan, it is possible to start the server without self built artifact deployment. It can be achieved by adding an empty <deployer /> element on the <configuration> tag of the project.
I found the info at the cargo plugin reference site. In addition, I have tested the configuration in my local project to confirm it works.

Cargo Cannot deploy to remote tomcat 8 with using cargo-maven-plugin

I am trying to deploy war on tomcat8 using cargo plugin my entry is as follows:
<plugins>
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.4.8</version>
<configuration>
<container>
<containerId>tomcat8x</containerId>
<type>remote</type>
</container>
<configuration>
<type>runtime</type>
<properties>
<cargo.remote.username>tomcat</cargo.remote.username>
<cargo.remote.password>s3cret</cargo.remote.password>
<cargo.tomcat.manager.url>http://localhost:1234/manager/text</cargo.tomcat.manager.url>
</properties>
</configuration>
<deployables>
<deployable>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<type>war</type>
<properties>
<context>/auditAPP</context>
</properties>
</deployable>
</deployables>
</configuration>
</plugin>
</plugins>
when i trying to run this using mvn cargo:deploy its giving me the following error
Failed to execute goal org.codehaus.cargo:cargo-maven2-plugin:1.4.8:deploy (default-cli) on project Audit_Management_DS: Execution default-cli of goal org.codehaus.cargo:cargo-maven2-plugin:1.4.8:deploy failed: Cannot create configuration. There's no registered configuration for the parameters (container [id = [tomcat8x], type = [remote]], configuration type[runtime]). Actually there are no valid types registered for this configuration. Maybe you've made a mistake spelling it? -> [Help 1]
Update to cargo-plugin version 1.4.13 solved this error message for me.

Cargo maven plugin - start goal ignores configuration, "run" works fine

I want cargo maven plugin to start a Tomcat7 so i put into my pom:
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.2.0</version>
<!-- minimal configuration to let adb run (mvn package org.codehaus.cargo:cargo-maven2-plugin:run) in a local tomcat -->
<configuration>
<containerId>tomcat7x</containerId>
<containerUrl>http://archive.apache.org/dist/tomcat/tomcat-7/v7.0.16/bin/apache-tomcat-7.0.16.zip
</containerUrl>
<configuration>
<properties>
<cargo.servlet.port>1718</cargo.servlet.port>
</properties>
</configuration>
</configuration>
</plugin>
The Problem is if i run:
mvn package org.codehaus.cargo:cargo-maven2-plugin:run
all is working fine but if i run
mvn package org.codehaus.cargo:cargo-maven2-plugin:start
the configuration set in pom is beeing ignored:"No container defined, using a default [jetty6x, embedded] container"
you can reproduce this easily. just create an war-maven app:
mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-webapp -DarchetypeArtifactId=maven-archetype-webappp
Then add the code above to pom and run both commands.
So how to set ContainerId and Url properly for goal start -- Am I missing something?!
so i contacted cargo support. the configuration above works indeed only with run goal, but there is also a configuration that works with both (the cargo doc is somehow misguiding):
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.2.0</version>
<!-- minimal configuration to let adb run (mvn package org.codehaus.cargo:cargo-maven2-plugin:run) in a local tomcat -->
<configuration>
<container>
<containerId>tomcat7x</containerId>
<zipUrlInstaller>
<url>http://archive.apache.org/dist/tomcat/tomcat-7/v7.0.16/bin/apache-tomcat-7.0.16.zip</url>
</zipUrlInstaller>
</container>
<configuration>
<properties>
<cargo.servlet.port>1718</cargo.servlet.port>
</properties>
</configuration>
</configuration>
</plugin>
notice the additional container and zipUrlInstaller tag instead of containerUrl.

GlassFish 3 + Maven + remote deploy

I couldn't find any clear answer about how to deploy simple Maven based project to remote GlassFish server via maven like
mvn package xxx:deploy
I think only cargo plugin supports GlassFish 3. Right?
I've problems at configuration side.
Any sample remote GlassFish deployment will be great. Cargo is not a must, if others are support remote GlassFish then we can also use it too.
In case you want to only use maven-glassfish-plugin (let say version 2.1), you can do a remote deploy by specifying the "host" parameter. Below is an example where configurations are setup in maven settings.xml and an plugin loads them using a profile:
In settings.xml define a profile:
<profile>
<id>production-config</id>
<properties>
<glassfish.glassfishDirectory>/var/local/glassfish/</glassfish.glassfishDirectory>
<glassfish.user>admin</glassfish.user>
<glassfish.adminPassword>adminadmin</glassfish.adminPassword>
<glassfish.domain.name>prd-domain</glassfish.domain.name>
<glassfish.domain.host>NAMEOFYOURREMOTEHOST</glassfish.domain.host>
<glassfish.domain.adminPort>10161</glassfish.domain.adminPort>
.
.
</properties>
</profile>
Next put this profile in your active profiles:
<activeProfiles>
<activeProfile>production-config</activeProfile>
</activeProfiles>
In your maven project pom.xml, create a profile and add the maven-glassfish-plugin in your list of profiles:
<profile>
<id>production</id>
<activation>
<activeByDefault>false</activeByDefault>
<os>
<arch>x86</arch>
<family>linux</family>
</os>
<property>
<name>profile</name>
<value>production</value>
</property>
<file>
<exists>
${glassfish.glassfishDirectory}/domains/${glassfish.domain.name}/config/domain.passwords
</exists>
</file>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.glassfish.maven.plugin</groupId>
<artifactId>maven-glassfish-plugin</artifactId>
<configuration>
<terse>true</terse>
<echo>true</echo>
<debug>true</debug>
<glassfishDirectory>${glassfish.glassfishDirectory}</glassfishDirectory>
<user>${glassfish.user}</user>
<adminPassword>${glassfish.adminPassword}</adminPassword>
<domain>
<name>${glassfish.domain.name}</name>
<host>${glassfish.domain.host}</host>
<adminPort>${glassfish.domain.adminPort}</adminPort>
</domain>
<components>
<component>
<name>${project.artifactId}</name>
<artifact>${project.build.directory}/${project.build.finalName}.war</artifact>
</component>
</components>
</configuration>
<executions>
<execution>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
This should do the trick. You can run this profile using maven : mvn glassfish:deploy -P production or just mvn deploy -P production (since we have added the goal deploy inside the executions part of plugin)
Using the model above you can create different profile per environment (dev, acc, tst, prd), and use different settings. For instance you can create a developer profile where a local glassfish is being used to deploy and run unit/integration tests on it.
Common mistake people make is to mix up the settings for the machine from where you are doing the remote deployment with the host where deployment is to be installed. glassfishDirectory is place from where you are running the deployment plugin from. As a result of mistake plugin just hangs, doing nothing and just waiting giving the impression that something is happening. Another mistake is to specify a password file instead of a password for a remote deploy which will also result in nothing.
As far as I know and could find around, only Cargo delivers (or deploys, in this case).
This is an example tested as working on a Maven OSGi WAR project:
<build>
<plugins>
...
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.1.2</version>
<configuration>
<container>
<containerId>glassfish3x</containerId>
<type>remote</type>
</container>
<configuration>
<type>runtime</type>
<properties>
<cargo.hostname>myhostname</cargo.hostname>
<cargo.remote.username>myusername</cargo.remote.username>
<cargo.remote.password>mypassword</cargo.remote.password>
</properties>
</configuration>
</configuration>
<dependencies>
<dependency>
<groupId>org.glassfish.deployment</groupId>
<artifactId>deployment-client</artifactId>
<version>3.2-b06</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
As you can see, the trick lies in the deployment-client dependency.
For the sake of completeness, you then just mvn package cargo:deploy and Bob's your uncle.

Resources