Seamless App Deployment on EC2 with CodeDeploy

AWS (Amazon Web Service) is one of the widely used cloud service providers, and it is useful to know how to use it to deploy our application.
If you are new to AWS kindly check out my previous blog which will give you an idea of the elements required to deploy your app on Amazon EC2.
Now, here I will be using a Dash Python application to fetch the AQI data from Open-Meteo and create a dashboard using Dash in Python.
Preparing Code for Deployment
To deploy on the EC2 instance, we need an appspec.yml file in the root location.
version: 0.0
os: linux
files:
- source: /
destination: /home/ec2-user/app
hooks:
BeforeInstall:
- location: scripts/install_dependencies.sh
timeout: 600
runas: root
AfterInstall:
- location: scripts/configure_environment.sh
timeout: 300
runas: root
- location: scripts/set_permissions.sh
timeout: 300
runas: root
ApplicationStart:
- location: scripts/start_server.sh
timeout: 600
runas: ec2-user
ValidateService:
- location: scripts/validate_service.sh
timeout: 300
runas: ec2-user
Here, we will go step by step as it is the most crucial file to do deployment on EC2.
In the files section, we have instructed to copy everything from the root of the folder to the /home/ec2-user/app location of the server.
Later, we used hooks to instruct the scripts to run based on the stage of the deployment.
BeforeInstall is the first stage of deployment, where we will install basic things needed for our code to work. We will be running it as root to avoid any permission issues and kept the timeout to 600.
#!/bin/bash
# install_dependencies.sh
echo "Updating system and installing dependencies..."
sudo yum update -y
sudo yum install -y python3-pip python3
sudo yum install -y nc
# Ensure virtualenv is installed
pip3 install --upgrade virtualenv
# Check Python version
echo "Python version: $(python3 --version)"
After that comes, the AfterInstall stage where we will set the environment needed to fulfill the dependencies of our project. Here we will be executing two scripts, one to install the requirements, and another to make sure all the sh files are executable
# Set up virtual environment
cd /home/ec2-user/app
# Debugging: List directory contents to verify file presence
echo "Listing contents of /home/ec2-user/app directory:"
ls -l /home/ec2-user/app
# Check if requirements.txt exists
if [ -f "requirements.txt" ]; then
echo "requirements.txt found, creating virtual environment..."
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
else
echo "Error: requirements.txt not found in /home/ec2-user/app"
exit 1
fi
echo "Dependencies installed successfully!"
chmod +x /home/ec2-user/app/scripts/*.sh
After that, the code is ready to be deployed in the ApplicationStart stage, we will be running it as an ec2-user to not grant all the permissions which can later create issues for the EC2.
#!/bin/bash
# start_server.sh
PORT=8050
# Check if the port is in use
if sudo lsof -i :$PORT; then
echo "Port $PORT is already in use. Killing the process..."
# Get the PID of the process using the port and kill it
PID=$(sudo lsof -t -i :$PORT)
sudo kill -9 $PID
# Check if the process was killed
if [ $? -eq 0 ]; then
echo "Process on port $PORT has been killed."
else
echo "Failed to kill the process on port $PORT." >&2
exit 1
fi
else
echo "Port $PORT is free."
fi
# Change to the app directory
cd /home/ec2-user/app
# Activate the virtual environment
if source venv/bin/activate; then
echo "Virtual environment activated successfully."
else
echo "Failed to activate virtual environment." >&2
exit 1
fi
# Start the Dash app on port 8050 and run it in the background
echo "Starting Dash app on port $PORT..."
nohup python main.py > server.log 2>&1 &
# Check if the app started successfully
if [ $? -eq 0 ]; then
echo "Dash app started successfully on port $PORT."
else
echo "Failed to start Dash app." >&2
exit 1
fi
As it might take some time to start the applications, when we validate in the ValidateService stage we need to add some retries
#!/bin/bash
# validate_service.sh
PORT=8050
RETRIES=5
DELAY=2
for i in $(seq 1 $RETRIES); do
if nc -z localhost $PORT; then
echo "Application is running on port $PORT"
exit 0
else
echo "Attempt $i: Application is not running on port $PORT"
sleep $DELAY
fi
done
echo "Application failed to start after $RETRIES attempts."
exit 1
Now, we package all the code into a zip file, such that all files are in the root location including appspec.yml
AWS Setup/Configuration for deployment
First, we need an active AWS account. Kindly create one if you don’t have any.
Search IAM (Identity and Access Management) and create a new role. Select the trusted entity to CodeDeploy and add permissions to access EC2, S3, and CodeDeploy.
Search for S3, and create a bucket. Here we will be uploading our zipped code.
Create a new EC2 instance, with the Amazon Linux platform and all the configuration you need. (if unsure, use the default t2.micro). If the first time, need to create a key-value pair and add the above created IAM role as its role. Click on Create, it will take some time to make it live. Once the instance is running, Connect with the EC2 instance via the Connect button on the EC2 details page, and follow this step to install the CodeDeploy agent on the EC2 instance using
Copy the ARN of the instance before going to the next step from the EC2
Now, search for CodeDeploy, create a new Application, and select configuration such that to deploy to EC2, add a deployment group, where you need to post the ARN copied earlier which will indicate the instance to deploy on, and for role use the IAM role created earlier. Once the Deployment Group is created, go to Deployments, and Create, and connect the S3 location where you stored the zip file. Wait for it to complete deployment, and then you can go back to the EC2 instance page.
Copy the URL from the EC2 page, and the website will be live using it along with the port it is hosted on.
Conclusion
Deploying any web app or API on EC2 is easier once we are aware of the stages in the appspec.yml file and the services we will be using along with the appropriate permissions given.
Hope this guide has given a starting point for deploying your app on EC2, as depending on the application you want to deploy, changes will be required in the bash scripts file.
The journey of a thousand miles begins with a single step.
— Lao Tzu