TT Lab
Get started
Learn Learning paths Courses

Tomcat & nginx Operations

Zero-Downtime Switchover With WAR and Parallel Deployment

Continue in TT Lab

Goal

You confirm how WAR deployment actually behaves, raise the version with parallel deployment without cutting sessions, and become able to write a deployment script that also verifies the result.

Why it matters

In a single-WAS environment, it is easy to think that zero-downtime deployment requires removing and adding servers at an L4 in front. But Tomcat has a parallel deployment feature built in. If you add ##버전 (a double hash plus a version) to the file name, several versions coexist under the same context, and existing sessions go to the old version and new requests go to the new version. Many SI sites repeat dawn stop-and-deploys without knowing this feature. There is one more thing — if a deployment script doesn't wait for unpacking to finish, it reports a failed deployment as a success. That is far worse than a stop-and-deploy.

Steps

  1. Start Tomcat and deploy /opt/lab/samples/labhub-1.0.0.war as /opt/tomcat/webapps/labhub##001.war. http://127.0.0.1:8080/labhub/version must return 1.0.0, and catalina.out must contain a deployment record for labhub##001. (This deployment record is used as evidence in later steps.)
  2. Check the unpacked directory and create /root/tc/explode.csv. The first line is path,exists. Write Y/N for the four paths below. WEB-INF/web.xml, WEB-INF/classes, WEB-INF/lib, META-INF
  3. Deploy /opt/lab/samples/labhub-2.0.0.war as /opt/tomcat/webapps/labhub##002.war. At this point, do not delete ##001 first and leave the two versions coexisting. http://127.0.0.1:8080/labhub/version must now return 2.0.0, and catalina.out must contain deployment records for both labhub##001 and labhub##002.
  4. Write /root/tc/parallel.md. The body must contain the following three things.
    • Which version a request with an existing session goes to
    • Which version a new request goes to
    • Why notation such as ##1/##10 is dangerous, since version strings are sorted by string comparison Both strings 001 and 002 must appear.
  5. Remove the ##001 version completely (both the WAR and the unpacked directory). Even after removal, http://127.0.0.1:8080/labhub/version must still return 2.0.0.
  6. Start /opt/lab/samples/labhub-boot.jar in the background on port 8082 and leave the log in /root/tc/boot.log. http://127.0.0.1:8082/version must return 200.
  7. Create /root/tc/war-vs-jar.csv. The first line is 항목,WAR,JAR (item, WAR, JAR). There must be five items, 배포단위 (deployment unit), 톰캣버전관리 (Tomcat version management), 포트지정 (port specification), 롤백 (rollback) and 무중단 (zero downtime), and no cell may be empty.
  8. Create /root/tc/deploy-war.sh. It takes two arguments (WAR파일 컨텍스트명, the WAR file and the context name) and
    • If the WAR file doesn't exist or its size is 0, it ends immediately with a non-zero exit code.
    • If it exists, it places it in webapps and waits for unpacking by polling for up to 30 seconds.
    • If http://127.0.0.1:8080/<컨텍스트명>/version returns 200, exit code 0; if it doesn't within 30 seconds, it ends with a non-zero exit code.

Notes

Deploy the first version

Start Tomcat and deploy /opt/lab/samples/labhub-1.0.0.war as /opt/tomcat/webapps/labhub##001.war. http://127.0.0.1:8080/labhub/version must return 1.0.0, and catalina.out must contain a deployment record for labhub##001. (This deployment record is used as evidence in later steps.)

If you add ##version to the file name, the context path is the part before ##. Unpacking is asynchronous, so requesting right after copying can give a 404.

Check the unpacking result

Check the unpacked directory and create /root/tc/explode.csv. The first line is path,exists. Write Y/N for the four paths below. WEB-INF/web.xml, WEB-INF/classes, WEB-INF/lib, META-INF

A WAR is a zip. Look for the standard web application structure in the unpacked directory. Which parts are required and which are optional is the learning point of this step.

Deploy the second version in parallel

Deploy /opt/lab/samples/labhub-2.0.0.war as /opt/tomcat/webapps/labhub##002.war. At this point, do not delete ##001 first and leave the two versions coexisting. http://127.0.0.1:8080/labhub/version must now return 2.0.0, and catalina.out must contain deployment records for both labhub##001 and labhub##002.

Deploy with a higher version string on the same context name. Both WARs must be unpacked at the same time, and new requests must go to the higher version.

Summarize how session draining works

Write /root/tc/parallel.md. The body must contain the following three things.

Write out in sentences where existing sessions and new sessions each go in a parallel deployment. Also note that version strings are sorted by string comparison.

Take down the old version

Remove the ##001 version completely (both the WAR and the unpacked directory). Even after removal, http://127.0.0.1:8080/labhub/version must still return 2.0.0.

You must remove the old WAR and the unpacked directory together. The service must not be interrupted even after removal, and the version response must remain the new version.

Start an executable JAR

Start /opt/lab/samples/labhub-boot.jar in the background on port 8082 and leave the log in /root/tc/boot.log. http://127.0.0.1:8082/version must return 200.

The embedded Tomcat approach gives the port as a launch argument. Start it in the background and leave the log in a file.

WAR vs JAR comparison table

Create /root/tc/war-vs-jar.csv. The first line is 항목,WAR,JAR (item, WAR, JAR). There must be five items, 배포단위 (deployment unit), 톰캣버전관리 (Tomcat version management), 포트지정 (port specification), 롤백 (rollback) and 무중단 (zero downtime), and no cell may be empty.

Try to organize it from the viewpoint that what governs the actual choice is not technical superiority but 'which way the operations procedures are standardized'.

Write the deployment script

Create /root/tc/deploy-war.sh. It takes two arguments (WAR파일 컨텍스트명, the WAR file and the context name) and

A script that reports a failed deployment as a success is the most dangerous. The polling loop that waits for unpacking and a non-zero exit code when verification fails are the key.