<?xml version="1.0"?>
<document>
  <header>
    <product>resin</product>
    <title>Cluster Application Deployment</title>
    <type>contents</type>
    <description>
      <p/>
    </description>
  </header>
  <body>
    <localtoc/> 

    <s1 title="Comparison to File Based Deployment">
      <p> Like other lightweight servlet containers
      and Java EE application servers, Resin supports
      <a href="deploy.xtp">file-system based
      deployment</a>. In order to deploy an application, all you need
      to do is copy your file to the Resin deployment directory. As
      you might also know, Resin has supported hot deployment for
      quite a while, which is a great feature for agile development
      that often results in frequent incremental deployments.  </p>

      <p>
      This deployment model is very simple, effective and popular. However,
      file-system based deployment has a few weaknesses that can arise
      in environments with very stringent availability and reliability
      requirements. It is very difficult to do deployment in a clustered
      environment because the same file must be deployed simultaneously to
      all servers in the cluster. Often this can result in some down-time
      that must be announced beforehand. No back-up facility is provided
      by the file system, so you must often save a backup copy of the
      old deployment somewhere yourself. File system based deployment
      also makes it very difficult to use the same server environment for
      different stages of development such as QA, user acceptance testing
      and production without following complicated deployment procedures.
      </p>

      <p>
      The remote deployment model introduced in Resin 4.0 goes a long
      way in solving these particular problems by supporting clustered,
      versioned and staged deployment.
      </p>
    </s1>

    <s1 title="Remote Clustered Deployment">

      <p>
        Instead of using the file system, you will need to use
        either the Resin Ant or Maven plug-ins to do remote
        deployment. There are a few simple steps to do this, the
        first of which is to enable remote deployment on the server,
        which is disabled by default. You do this using the following
        Resin configuration:
      </p>

      <example title="Cluster deployment configuration">
&lt;resin xmlns=http://caucho.com/ns/resin
       xmlns:resin="urn:java:com.caucho.resin">
  &lt;cluster id="">
    &lt;resin:AdminAuthenticator password-digest="none">
      &lt;resin:user name="admin" password="myadminpass"/>
    &lt;/resin:AdminAuthenticator>
    &lt;resin:RemoteAdminService/>
    &lt;resin:DeployService/>
  ...
&lt;/resin>
      </example>

      <p>
        In the example above, both the remote admin service and the
        deployment service is enabled. Note, the admin authenticator most be
        enabled for any remote administration and deployment for obvious
        security reasons. To keep things simple, we used a clear-text
        password above, but you should likely use a password hash instead.
      </p>

      <p>
        Once you start Resin, you can use the Ant snippet below to
        do a remote deployment:
      </p>

      <example title="Ant build.xml upload deploy configuration">
&lt;?xml version="1.0"?>
&lt;project name="test" default="test" basedir="."
         xmlns:resin="antlib:com.caucho.ant">
  &lt;target name="test">
    &lt;resin:upload-war server="localhost"
                      port="8080"
                      user="admin"
                      password="myadminpass"
                      warFile="foo.war"/>
  &lt;/target>
&lt;/project>
      </example>

      <p>
        After you run the Ant script above, you will see output like this:
      </p>

      <results>
[resin:upload-war] Deployed foo.war to tag wars/default/default/foo
      </results>

      <p>
        The output exposes a few important things about the
        underlying remote deployment implementation for Resin. Remote
        deployment for Resin uses Git under the hood. In case you
        are not familiar with it, Git is a newish version control
        system similar to Subversion. A great feature of Git is
        that it is really clever about avoiding redundancy and
        synchronizing data across a network, which comes in very
        handy for Resin. Under the hood, Resin stores deployed files
        as nodes in Git with tags representing the type of file,
        development stage, virtual server, web application context
        root name and version. The format used is this:
      </p>

      <def>
&lt;type>/&lt;stage>/&lt;virtual host>/&lt;context root>[-&lt;version>]
      </def>

      <p>
        In our example, all web applications are stored under wars, we
        didn’t specify a stage or virtual host in the Ant task so the
        default is used, the web application root is foo and no version
        is used since one was not specified. This format is key to the
        versioning and staging featured we will discuss shortly.
      </p>

      <p>
        As soon as your web application is uploaded to the Resin
        deployment repository, it is propagated to all the servers in
        the cluster - including dynamic nodes that are added to the
        cluster at a later point in time after initial propagation
        happens. This means that you can eliminate complicated
        scripts to deploy your application throughout each cluster
        member manually. Remember too that we’re using Git under
        the hood, which is pretty intelligent about the way it stores
        files. If you upload a new version of your application to
        one Resin instance, only the files that changed need to
        be retransmitted across to the other instances in order
        to bring them up to date. In other words, you only end up
        using as much network traffic as you have new material,
        which is a great performance boost.
      </p>

      <p>
        Doing remote deployment with the Resin Maven plug-in is
        just as simple. You’ll need to setup the plug-in like this:
      </p>

      <example title="Maven pom.xml upload deploy configuration">
&lt;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/maven-v4_0_0.xsd">
  &lt;modelVersion>4.0.0&lt;/modelVersion>
  &lt;groupId>com.test&lt;/groupId>
  &lt;artifactId>test&lt;/artifactId>
  &lt;packaging>war&lt;/packaging>
  &lt;version>1.0-SNAPSHOT&lt;/version>
  &lt;name>Test Maven Web Application&lt;/name>
  &lt;url>http://maven.apache.org&lt;/url>

  &lt;dependencies>
  &lt;/dependencies>

  &lt;pluginRepositories>
    &lt;pluginRepository>
      &lt;snapshots>
        &lt;enabled>true&lt;/enabled>
        &lt;updatePolicy>always&lt;/updatePolicy>
        &lt;checksumPolicy>ignore&lt;/checksumPolicy>
      &lt;/snapshots>
      &lt;id>caucho&lt;/id>
      &lt;name>Caucho&lt;/name>
      &lt;url>http://caucho.com/m2-snapshot&lt;/url>
    &lt;/pluginRepository>
  &lt;/pluginRepositories>

  &lt;build>
    &lt;finalName>foo&lt;/finalName>

    &lt;plugins>
      &lt;plugin>
        &lt;groupId>com.caucho&lt;/groupId>
        &lt;artifactId>resin-maven-plugin&lt;/artifactId>
        &lt;version>4.0-SNAPSHOT&lt;/version>
        &lt;configuration>
          &lt;server>127.0.0.1&lt;/server>
          &lt;port>8086&lt;/port>
          &lt;user>admin&lt;/user>
          &lt;password>myadminpass&lt;/password>
        &lt;/configuration>
      &lt;/plugin>
    &lt;/plugins>
  &lt;/build>
&lt;/project>
      </example>

      <p>
        You can then remote deploy your application from the command
        line like so:
      </p>

      <def>
mvn resin:upload-war
      </def>
    </s1>

    <s1 title="Deployment Versioning">

      <p>
        In addition to automatically propagating a deployment to
        all clustered nodes, Resin remote deployment also supports
        versioning. When you upload an application, you can specify a
        version number for it. Resin then figures out what the latest
        version of an application is and shows that to application
        users as they arrive. All this is done in real time, so any
        users of the older version of the application can continue
        using the application until they log off or their session is
        timed out. Next time these users access the application they
        get the newer version instead. Versioning comes in very handy
        if you need to roll-back a deployment quickly. All you need
        to do is set the older version of the application already
        stored in the Resin deployment repository as the active one.
      </p>

      <p>
        Let’s see how this works by modifying our previous Ant example:
      </p>

      <example title="Ant upload task with version">
&lt;resin:upload-war server="localhost"
                  port="8080"
                  user="admin"
                  password="myadminpass"
                  warFile="foo.war"
                  version="1.0"/>
      </example>

      <p>
        Notice in this case we’ve explicitly set a version
        number (in a real life Ant script you would of course
        likely externalize things like versions through properties
        instead of hard-coding them). After you run the Ant script,
        you should see something like this:
      </p>

      <results>
[resin:upload-war] Deployed foo.war to tag wars/default/default/foo-1.0
[resin:upload-war] Wrote head version tag wars/default/default/foo
      </results>

      <p>
        The Maven equivalent of this command would look like the
        following where we would specify the resin.version system
        property:
      </p>

      <example title="Maven upload command with version">
mvn resin:upload-war -Dresin.version="1.0"
      </example>

      <p>
        Now let’s suppose we want to upgrade the application. This
        is how we could do it:
      </p>

      <example title="Ant upload task with version, upgrade">
&lt;resin:upload-war server="localhost"
                  port="8080"
                  user="admin"
                  password="myadminpass"
                  warFile="foo.war"
                  version="2.0"/>
      </example>

      <p>
        In this case we upgraded the application version to 2.0,
        so the head tag will be updated to point to the newly
        uploaded file, as indicated by the Ant task output:
      </p>

      <results>
[resin:upload-war] Deployed foo.war to tag wars/default/default/foo-2.0
[resin:upload-war] Wrote head version tag wars/default/default/foo
      </results>

      <p>
        The Maven version of the application upgrade would be like this:
      </p>

      <example title="Maven upload command with version, upgrade">
mvn resin:upload-war -Dresin.version="2.0"
      </example>

      <p>
        Keep in mind, although the head revision was updated so
        that users start to see the new version of the application,
        the older application remains intact in the deployment
        repository. This is extremely powerful if you need to back
        out the new deployment in a hurry. This can be done by
        simply copying back the older file to the head tag like this:
      </p>

      <example title="Ant copy tag task">
&lt;?xml version="1.0"?>
&lt;project name="test" default="test" basedir="."
         xmlns:resin="antlib:com.caucho.ant">
    ...
    &lt;resin:copy-tag server="localhost"
                    port="8080"
                    user="admin"
                    password="myadminpass"
                    sourceVersion="1.0"
                    sourceContextRoot="foo"
                    contextRoot="foo"/>
  &lt;/target>
&lt;/project>
      </example>

      <p>
        The key here is specifying the source version to be
        1.0. resin-copy-tag also has a version attribute to specify
        where the tag is being copied to, which was omitted because
        we want to copy to the head revision. The output from
        running the Ant task reveals the end result:
      </p>

      <results>
[resin:copy-tag] Copying wars/default/default/foo-1.0 to 
  wars/default/default/foo
      </results>

      <p>
        Here is the Maven version of the command:
      </p>

      <example title="Maven copy tag command">
mvn resin:copy-tag \
    -Dresin.sourceContextRoot='foo' \
    -Dresin.sourceVersion="1.0" \
    -Dresin.contextRoot="foo"
      </example>

      <p>
        If you feel you don’t need extra versions of applications
        in the repository, you can always delete them. For example,
        you can delete the faulty 2.0 deployment like this:
      </p>

      <example title="Ant delete tag task">
&lt;?xml version="1.0"?>
&lt;project name="test" default="test" basedir="."
         xmlns:resin="antlib:com.caucho.ant">
    ...
    &lt;resin:delete-tag server="localhost"
                      port="8080"
                      user="admin"
                      password="myadminpass"
                      version="2.0"
                      contextRoot="foo"/>
  &lt;/target>
&lt;/project>
      </example>

      <p>
        The Maven version is:
      </p>

      <example title="Maven delete tag command">
mvn resin:delete-tag -Dresin.version="2.0" -Dresin.contextRoot="foo"
      </example>

      <p>
        You can also always check out what versions of the
        application are currently installed in the Resin deployment
        repository:
      </p>

      <example title="Ant query tags task">
&lt;?xml version="1.0"?>
&lt;project name="test" default="test" basedir="."
         xmlns:resin="antlib:com.caucho.ant">
    ...
    &lt;resin:query-tags server="localhost"
                      port="8080"
                      user="admin"
                      password="myadminpass"
                      contextRoot="foo"/>
  &lt;/target>
&lt;/project>
      </example>

      <results>
[resin:query-tags] wars/default/default/foo-1.0
[resin:query-tags] wars/default/default/foo-2.0
      </results>

      <p>
        The Maven version looks like this:
      </p>

      <example title="Maven query tags command">
mvn resin:query-tags -Dresin.version='.*
      </example>
    </s1>

    <s1 title="Deployment Stages">
      <p>
        In a sense, stages are application versioning applied at
        the server level. As you saw, you can apply a development
        stage to each uploaded application. On the other hand,
        each server instance in the cluster can have an associated
        stage. The server only publishes applications that match
        the stage it is currently in. Applications in all other
        stages are ignored even if it is propagated and stored in
        the repository for the server instance.
      </p>

      <p>
        This feature can be very useful if you think about the
        typical short-comings of having completely separate
        environments for QA, user acceptance testing and
        production. Because the environments are physically
        separated, there are invariably some subtle differences
        that only become apparent when an actual release happens –
        usually a terrible time to be doing trouble shooting. One way
        to avoid this problem is using an actual production cluster
        server for things like beta testing or user acceptance
        testing (of course, in some environments this is not a
        realistic option for logistical reasons, in which case the
        traditional method of physically separating environments
        can still be used). Staging can also simply be used as
        away to do a last minute reality check in the production
        environment before doing a final roll-out.
      </p>

      <p>
        In this technique, you first deploy an application in something
        other than the default stage. As you know, this is propagated to
        all instances in the cluster. This is how you do it using Ant:
      </p>

      <example title="Ant upload task with stage">
&lt;resin:upload-war server="localhost"
                  port="8080"
                  user="admin"
                  password="myadminpass"
                  warFile="foo.war"
                  stage="preview"/>
      </example>

      <p>
        Notice we explicitly specified the application stage in
        the Ant task. The Maven version of this looks like this:
      </p>

      <example title="Maven upload command with stage">
mvn resin:upload-war -Dresin.stage="preview"
      </example>

      <p>
        Now, all servers in the default stage will simply ignore this
        application even though it is in the repository. All servers
        are normally in the default stage when started as below:
      </p>

      <example title="Starting the first triad server">
java -jar $RESIN_HOME/lib/resin.jar -server a start
      </example>

      <p>
        In order for a server to actually publish the application
        above, the server instance must be started in the
        “preview” stage (in general, you would probably want
        to start a preview stage server as a dynamic server, but
        to keep it simple we’ll omit those details here). You
        can do this as below:
      </p>

      <example title="Starting the second triad server as a preview server">
java -jar $RESIN_HOME/lib/resin.jar -server b -stage preview start
      </example>

      <p>
        You can use this server to do user acceptance testing or
        simply a last minute check (typically you will use IP
        blocking to isolate this server from normal production
        users). Once you are satisfied with the results, you can
        change the application to the default stage by doing a copy
        as below:
      </p>

      <example title="Ant copy tag task to move from preview to default stage">
&lt;resin:copy-tag server="localhost"
                port="8080"
                user="admin"
                password="myadminpass"
                sourceStage="preview"
                sourceContextRoot="foo"
                stage="default"
                contextRoot="foo"/>
      </example>

      <results>
[resin-copy-tag] Copying wars/preview/default/foo to wars/default/default/foo
      </results>

      <p>
        The Maven version of this looks like the following:
      </p>

      <example title="Maven copy tag command to move from preview to default stage">
mvn resin:copy-tag \
    -Dresin.sourceContextRoot='foo' \
    -Dresin.sourceStage="preview" \
    -Dresin.stage="default"
      </example>

      <p>
        Because the application already resides in all clustered
        instances, switching things over to production happens
        almost instantaneously.  You can interplay staging and
        versioning as well by staging new versions before deployment.
      </p>
    </s1>
  </body>
</document>
