Tomcat + CodeDeploy: Your Path to Effortless Application Deployment

Mahesh UpretiMahesh Upreti
5 min read

In DevOps, Continous Deployment is the term you will often hear. You might have also come across the AWS CodeDeploy and CodeDeploy-local. Codedeploy makes the deployment process easy and manageable. AWS also supports testing and debugging code-deploy locally before using the AWS Codedeploy service on instances. So, let's explore the code-deploy-local and tomcat setup along with it.

Install Codedeploy-agent

First thing first, install the code deploy-agent in your on-premise device.

You can follow this official AWS documentation link
https://docs.aws.amazon.com/codedeploy/latest/userguide/codedeploy-agent-operations-install-ubuntu.html

Setup Codedeploy-local

It is not a compulsory step, but it will make your journey easier.

If you use a configuration file on Amazon Linux, RHEL, or Ubuntu Server instances, you must either:

  • Use the :root_dir: and :log_dir: variables to specify locations other than the defaults for the deployment root and log directory folders.

  • Use sudo to run CodeDeploy agent commands.

These points are directly taken from AWS official documentation and you should keep this always in mind and especially the second point.

For your ease, follow this link https://aws.amazon.com/blogs/devops/how-to-test-and-debug-aws-codedeploy-locally-before-you-ship-your-code/ and create alias as said in the blog.

Leave the default path of the code deploy agent for now. You can change it but you should configure the configuration file as per the new directory.

It's time now to work on the main file.

Project Structure

Here, the demo-0.0.... is the war file which we will deploy in the Tomcat server.

Main appspec.yml

IT'S NOT YAML. IT'S YML. This one-letter difference took me almost 3 days. Yeah, it's my fault as I didn't watch the documentation properly but you be aware from the beginning. Create the appspec.yml file in the root directory where you want the project.

  • version

    This section specifies the version of the AppSpec file. Do not change this value. It is required. Currently, the only allowed value is 0.0. It is reserved by CodeDeploy for future use.

    Specify the version with a string.

  • os

    This section specifies the operating system value of the instance to which you deploy. It is required. The following values can be specified:

    • linux โ€“ The instance is an Amazon Linux, Ubuntu Server, or RHEL instance.

    • windows โ€“ The instance is a Windows Server instance.

      Specify os with a string.

  • hooks

    This section specifies scripts to run at specific deployment lifecycle events during the deployment.

    For more information, see AppSpec 'hooks' section.

In our case, there are four defined exclusively life cycle events.

ApplicationStop

This contains application-stop.sh script which stops the running tomcat service.

The script required for this event is inside the scripts-> application-stop.sh

BeforeInstall

This contains before-install.sh script which sets up the tomcat user and group, installs tomcat as per condition and copies the tomcat service file for systemd.

#!/bin/bash

set -e

CATALINA_DIR="/home/mahesh" #my tomcat catalina directory
TOMCAT_VERSION_NUMBER=9.0.78

echo "Tomcat group and user are going to be created."
TOMCAT_GROUP="tomcat"
TOMCAT_USER="tomcat"

# Create the Tomcat group
if ! getent group "${TOMCAT_GROUP}" > /dev/null; then
    groupadd "${TOMCAT_GROUP}"
fi

# Create the Tomcat user without login shell access
if ! getent passwd "${TOMCAT_USER}" > /dev/null; then
  useradd -M -g "${TOMCAT_GROUP}" -s /usr/sbin/nologin "${TOMCAT_USER}"
fi

# Print a message indicating the successful creation of the group and user
echo "group and user got created successfully"

#make PROJECT_HOME directory
if [ -d "${PROJECT_HOME}" ];
then
  rm -rf ${PROJECT_HOME}
  echo "removed PROJECT_HOME"
  mkdir ${PROJECT_HOME}
  echo "created PROJECT_HOME"
else
  mkdir ${PROJECT_HOME}
fi

#
#######changed the owner group
chmod 755 -R ${PROJECT_HOME}
chown tomcat:tomcat -R ${PROJECT_HOME}
echo "made the owner tomcat and changed the mode to 755"


##check if tomcat is already installed or not
if [[ -d "${CATALINA_DIR}/apache-tomcat-${TOMCAT_VERSION_NUMBER}" ]];
then
    echo "Tomcat is installed at ${CATALINA_DIR}/apache-tomcat-${TOMCAT_VERSION_NUMBER}"
    echo "no need to download"
else
    echo "Tomcat is not installed at ${CATALINA_DIR}/apache-tomcat-${TOMCAT_VERSION_NUMBER}"

    ###download tomcat
    wget https://downloads.apache.org/tomcat/tomcat-9/v${TOMCAT_VERSION_NUMBER}/bin/apache-tomcat-${TOMCAT_VERSION_NUMBER}.tar.gz

    ####extract tomcat
    tar -xzvf apache-tomcat-${TOMCAT_VERSION_NUMBER}.tar.gz -C ${CATALINA_DIR}
    rm -rf apache-tomcat-${TOMCAT_VERSION_NUMBER}.tar.gz

    ###permission to tomcat user
    #need to change owner and group from mahesh to tomcat in the final one
    chmod 755 -R "${CATALINA_DIR}/apache-tomcat-${TOMCAT_VERSION_NUMBER}"
    chown tomcat:tomcat -R "${CATALINA_DIR}/apache-tomcat-${TOMCAT_VERSION_NUMBER}"
fi

if [[ -f "/etc/systemd/system/tomcat.service" ]];
then
#    cp -f tomcat-service-file /etc/systemd/system/tomcat.service
    echo "found service file but copied new service file"
    chmod 755 /etc/systemd/system/tomcat.service
    chown tomcat:tomcat /etc/systemd/system/tomcat.service
    echo "changed user and permission for service file"
    systemctl daemon-reload
    systemctl enable tomcat
    echo "service found"
else
    echo "no service not found"
    ## description: Tomcat startup/ shutdown script
    # process name: tomcat

    cp -f tomcat-service-file /etc/systemd/system/tomcat.service
    echo "copied service file"

    chmod 755 /etc/systemd/system/tomcat.service
    chown tomcat:tomcat /etc/systemd/system/tomcat.service
    echo "changed user and permission for service file"
    systemctl daemon-reload
    systemctl enable tomcat

fi

AfterInstall

This contains after-install.sh which removes ROOT and ROOT.war from webapps of catalina directory and copies war file to webapps as ROOT.war and deplyos it to tomcat server.

#!/bin/bash

set -e

DEPLOY_TO_ROOT='true'
WAR_STAGED_LOCATION="/home/mahesh/Desktop/projects/tomcat-codedeploy-test/demo-0.0.1-SNAPSHOT.war"

CATALINA_DIR="/home/mahesh"
TOMCAT_VERSION_NUMBER=9.0.78

# In Tomcat, ROOT.war maps to the server root
if [[ "$DEPLOY_TO_ROOT" = 'true' ]];
then
    CONTEXT_PATH='ROOT'
fi

# Remove unpacked application artifacts
if [[ -f "${CATALINA_DIR}/apache-tomcat-${TOMCAT_VERSION_NUMBER}/webapps/${CONTEXT_PATH}.war" ]];
then
   rm "${CATALINA_DIR}/apache-tomcat-${TOMCAT_VERSION_NUMBER}/webapps/${CONTEXT_PATH}.war"
fi
if [[ -d "${CATALINA_DIR}/apache-tomcat-${TOMCAT_VERSION_NUMBER}/webapps/${CONTEXT_PATH}" ]];
then
   rm -rf "${CATALINA_DIR}/apache-tomcat-${TOMCAT_VERSION_NUMBER}/webapps/${CONTEXT_PATH}"
fi

# Copy the WAR fsile to the webapps directory
cp "${WAR_STAGED_LOCATION}" "${CATALINA_DIR}/apache-tomcat-${TOMCAT_VERSION_NUMBER}/webapps/${CONTEXT_PATH}.war"

ApplicationStart

This contains application-start.sh script which starts the tomcat service.

๐Ÿ’ก
Note: All scripts are run as the root.

Conclusion

If you have set up the following stepwise mentioned in the blog, you can run the command:

codedeploy-local #run it from the root where appspec.yml file is present

You can find me here:

GitHub ( Full code can be found in this repo. You can clone and make use of it)

LinkedIn (You can connect and message me in case of any issues)

Follow me on the hashnode for more content. Thank you!

0
Subscribe to my newsletter

Read articles from Mahesh Upreti directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Mahesh Upreti
Mahesh Upreti

I am a DevOps and Cloud enthusiast currently exploring different AWS services and DevOps tools.