DevOps for an Application Developer: CodeDeploy

havimaki
5 min readMar 29, 2021

It can be easy for software application developers to focus solely on app development, without ever understanding the underlying infrastructure the application is actually built upon.

This is Part 1 of a series that will take a look at useful services provided by AWS for software applications. Each article will dive into a particular service and highlight how this knowledge can be helpful for application developers on both a technical and theoretical level. This article will focus on the CI/CD pipeline, and how CodeDeploy as a service works.

So what is CI/CD?

CI/CD stands for “Continuous Integration/Continuous Deployment”, and it is an integral part of DevOps. CI/CD is both a set of principles and practices that allow for teams to push and deliver code in an automated fashion, allowing for teams to deliver and reiterate much faster. The CI/CD pipeline is the implementation.

What are the benefits of understanding the CI/CD pipeline?

While you may never be the one building the infrastructure, it’s valuable to understand the services that are involved, even at a higher level. It’s more than just getting your code “out there”, it’s also about knowing what the process is and the components involved. That way, you can have a better understanding of two things:

  1. Knowing where the points of failures are
  2. Knowing how to course correct

Now let’s talk CodeDeploy

CodeDeploy is a service in AWS that automates deploying applications. This service is extremely useful for a few reasons, as manually automating your own deployment can:

  1. Take a lot of time
  2. Be prone to human error
  3. Be complicated and hard to maintain

CodeDeploy removes the hassle of manually coordinating a deployment to multiple servers, by guaranteeing deploying the same application across multiple servers, every time.

So let’s walk through CodeDeploy in the console and take a look at the basics

In the snapshot below, I’m in the CodeDeploy service in the AWS console. I’ve already stepped into the screen that displays all previous and current deployments. Each row of data defines a deployment.

Here are some main takeaways from this table:

  • The Deployment Id is a link in UUID format, which links to further details about the deployment itself.
  • The status of the deployment defines whether the deployment failed, succeeded or is currently in progress
  • The name of the application defines which server is being deployed
  • The deployment group, at a high level, is an entity that groups servers or functions together for a particular deployment. For example, a deployment group can specify three separate servers required to successfully deploy to a staging environment.

You can take a look at the details of a particular deployment by clicking on the Deployment Id.

At the bottom, you can see the Deployment Lifecycle events table. Each row of data specifies a deployment to a server. In this example, the application was only deployed to one server. If you were deploying to two servers, there would be two rows of data, and so on and so forth.

There are three particular columns to take note of:

  1. Instance ID: this links to the server to which the application was deployed.
  2. Status: This specifies whether the deployment to that server was successful or not.
  3. Events: An event is a deployment hook that is executed once per deployment, during which you can specify particular scripts to run. There are over a dozen events, inherent to CodeDeploy — the necessary events vary, depending on how the application is hosted. The three valid options are EC2, ECS and lambda deployments. You can read more about that here.

Now let’s take a look at the events by clicking on “View Events”. This is where an application developer can truly make use of CodeDeploy.

The example above shows a deployment made for an EC2 instance. You can see that there are 10 events listed, each with a duration, a status, an error code (null if no errors), a start time and an end time. You, as a developer, can inject code into these events. All you would need to do is update the appspec.yml file related to your CodeDeploy configuration. It should be formatted something along the lines of:

version: 0.0
os: linux
files:
- source: ** file that stores images URI **
destination: /home/ec2-user
hooks:
ApplicationStart:
- location: ** location of bash script **
timeout: ** length in seconds
ValidateService:
- location: scripts/validate_service.sh
timeout: 30
- location: scripts/remove_unused_images.sh
timeout: 30

You can see under the hooks section, a key that specifies the hook name, a location of the script to run, and how long CodeDeploy should attempt to run this script before timing out. You can also see that you can add more than one script file per hook, each with its own timeout value. An example of a very simple script that can be added would be a health check, executed within the ValidateService event hook.

#!/usr/bin/env bashVALIDATE_URL=https://localhost/api/health
MAX_ATTEMPTS=10
ATTEMPTS=0
function validate(){
((ATTEMPTS++))
echo "Validating endpoint ${VALIDATE_URL}"
RESP=$(curl -ksSi "${VALIDATE_URL}" 2>&1)
if [ $? != 0 ]; then
echo ERROR:
echo "${RESP}"
return 2
fi
local CODE=$(echo $RESP | head -n 1 | awk '{print $2}')
echo "Response: ${CODE}"
if [ $CODE -ge 200 ] && [ $CODE -lt 400 ]; then
return 0
fi
return 1
}
validate
while [ $? != 0 ] && [ $ATTEMPTS -lt $MAX_ATTEMPTS ]; do
sleep 2
validate
done
if [ $? != 0 ]; then
echo "Service failed to validate after ${ATTEMPTS} attempts"
exit 1
else
echo "Validated service after ${ATTEMPTS} attempts"
exit 0
fi

In the appspec file, the ValidateService event hook specified the filename validated_servicea bash script that calls the server’s health endpoint and looks for a status response of 200. After 10 tries, it then exits the script, the deployment stops and the instance is rolled back to its original state with the previous code.

Conclusion

So that’s a very small example of where understanding CodeDeploy as an application developer really comes in handy. You can try to think of other scripts that can be added which would be uniquely useful for your application. Maybe it’s calling two endpoints to validate different services, or removing old docker images — having this foundational understanding of the service can not only expand your application technically, but it can also help evolve your thought process as an application developer.

Hope this helps. :)

⚡ Stay tuned for more!
Danielle Havimaki

--

--

havimaki

Full Stack Software Developer @ RBCVentures with a love for new learnings, both rustic and shiny. Mainly backend + devOps.