Here we are going to go through the steps to auto deploy our code to an AWS EC2 instance using AWS CodeDeploy.
The purpose of this is to make our deploys easier and repeatable. This will allow us to move away from manual deploys which are not only more difficult and prone to error but also causes unnecessary anxiety.
STEP 1: Create an IAM service role for AWS CodeDeploy
To grant access to AWS CodeDeploy Service, we need to create the appropriate IAM role.
Go to AWS IAM Roles Dashboard and then click on Create Role Button.
On the succeeding page select the following:
Service: CodeDeploy
Use Case: CodeDeploy
Just use defaults for the Permissions and Tags stages.
Once in the Review stage, insert your preferred role name and description then create the role. For our use case we will use CodeDeployDemoServiceRole as the role name.
Step 2: Create an IAM role for AWS EC2 Instance Profile
This step will allow our EC2 instance to access AWS S3 buckets and Github repositories.
Again on the AWS Roles Dashboard click on Create Role.
On the succeeding page select EC2.
For Permissions search for AmazonS3ReadOnlyAccess and select it.
Just skip the tags value then proceed to review and create the role. We are naming this role CodeDeployDemo-EC2-Profile
Step 3: Assign Created Profile IAM role to EC2 Instance.
Go to EC2 instances page and right click on your instance.
Select Security > Modify IAM role.
Select the IAM role we created in Step 2 (CodeDeployDemo-EC2-Profile).
Then press Save.
Step 4: Assign Deploy Tags for AWS EC2 instance
We are assuming that you already created an EC2 instance. If not create one (there are a lot of resources discussing how to create EC2 available online).
CodeDeploy uses tags to know which instance should auto deployment be applied to. So in this step we are applying tags to our EC2 instance. You can select any key/value as long as it is consistent to the one applied for CodeDeploy. We will show this later in Step 6.
So to apply tags to your instance. Go to your EC2 dashboard. Right click on your instance and select **Instance Settings > Manage Tags **
For this demo we will be using the key/value:** autoDeploy / true**.
Step 5: Install CodeDeploy Agent in EC2 instances.
For our auto deploy to work we need to install Code Deploy's agent. Connect to your EC2 instances and follow the instructions (assuming you are using Ubuntu 20.04).
sudo apt update
sudo apt install ruby-full
sudo apt install wget
cd /home/ubuntu
Next run the following command based on your EC2's region's resource S3 bucket name. Use AWS Resource kit bucket names by Region as reference .
wget https://[bucket-name].s3.[region-identifier].amazonaws.com/latest/install
chmod +x ./install
sudo ./install auto > /tmp/logfile
sudo service codedeploy-agent status
If Active states active (running)
then CodeDeploy agent installation is successful. ** Note: Most of the initial CodeDeploy errors are due to the agent not being installed in the EC2 instance.
Step 6: Create AWS CodeDeploy Application
Now we are getting to where the magic happens. So in this stage we are going to create a CodeDeploy application which will be responsible for auto deploying our software to our AWS EC2 instance.
Go to CodeDeploy Application Dashboard Application
Here insert your preferred CodeDeploy application name and select compute platform EC2/On-premises. For this demo we will name our application CodeDeployDemoApp
Step 7: Create AWS CodeDeploy Deployment Group.
Next we will create a deployment group. Here we will link the our EC2 instance for auto deployment using the tag key/value pair in Step 4.
Listed are the settings for this demo:
Deployment Group Name: CodeDeployDemoGroup
Service Role: CodeDeployDemoServiceRole (we created this in Step 1)
Deployment Type: In-place
Environment Configuration: Amazon EC2 Instance. Here we will insert the tag key/value : autoDeploy / true to be able to autoDeploy to our EC2 instance. Any instance with this tag key/value pair will have be included in this auto deployment group.
Deployment Settings: CodeDeployDefault.AllAtOnce
Load Balancer: Disabled as we will not set this up for this demo.
Rolllbacks: Enabled so if an auto deploy fails it will rollback the EC2 state to the most recent successful deploy.
Step 8: Setup AWS CodePipeline to link with our Github Repo
Go to AWS CodePipeline and create a pipeline.
We will name this pipeline CodeDeployDemoPipeline and follow the pipeline settings below:
Now we link our Github repo. CodePipeline will monitor this repo and any changes will result to triggering the auto deployment pipeline to our deployment group. (Note: Other sources aside from Github can be used example AWS ECR).
(Note: We selected Start the pipeline on source code change. This means that any push to the our selected repo branch will trigger the auto deployment pipeline. Untick th box, if you want a more manual control of triggering the auto deployment by a press of button.
We will then skip the Add build stage and proceed to Add Deploy stag where we will select the following:
Deploy provider: AWS CodeDeploy
Region: Your AWS region
Application Name: CodeDeployDemoApp
Deployment Group: CodeDeployDemoGroup
Proceed on the review and create the pipeline.
Step 9: Add appspec.yml file in the root of your project.
AWS CodeDeploy uses appspec.yml as reference in order to conduct the auto deployment. It uses the specification file to determine what it should install to your EC2 instance for any revision in the monitored repository (repo linked to CodePipeline).
It also determines which lifecycle event hooks to run in response to deployment lifecycle events.
Without this file CodeDeploy will fail.
Insert the following in the appspec.yml file in your project's root:
# Template file for aws codedeploy with an EC2/On-premise
version: 0.0
os: linux
files:
- source: /
destination: /home/ubuntu/aws-code-deploy-demo
hooks:
ApplicationStop:
- location: aws-scripts/app-stop.sh
timeout: 300
BeforeInstall:
- location: aws-scripts/before-install.sh
timeout: 300
AfterInstall:
- location: aws-scripts/after-install.sh
timeout: 300
ApplicationStart:
- location: aws-scripts/app-start.sh
timeout: 300
The hooks section is very important as CodeDeploy will run the commands in the script files for each stage of the deployment lifecycle. The timing of your shell commands is very critical for the success of the auto deploy. For specific details on each of the lifecycle visit the AWS AppSpec 'hooks' section page
Step 10: Create the scripts for each of the hook stage in the appspec.yml
CodeDeploy will run the commands contained in each of the script files referenced in each hooks stage. Provide all the necessary shell commands which otherwise you would manually execute in a manual deploy. The example used for this project is the Create React App served via Nginx in a Docker container (AWS CodeDeploy has the ability to automatically deploy other application types as well).
Just to quickly show an example script files.
Here is before-install.sh
. This script will be executed before the downloading the updated aws-code-deploy-demo repo to our ec2 instance:
#!/bin/bash
# will install the dependencies to run the applications.
#install docker
sudo apt update
yes | sudo apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
sudo apt update
apt-cache policy docker-ce
yes | sudo apt install docker-ce
# update user to not require sudo for docker commands
sudo usermod -aG docker ${USER}
su - ${USER}
# install docker-compose
sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
Next let's look at app-start.sh
. This will be executed on the last hook stage and will run our application once all the installation and other necessary setup are executed in previous hook stages.
# commands to start apps
#!/bin/bash
cd /home/ubuntu/aws-code-deploy-demo/docker
docker-compose up -d --force-recreate --no-deps --build
To see the shell commands for the other hooks stage script files go to of the niccololampa/aws-code-deploy-demo/aws-scripts .
Step 11: Start the AWS Pipeline to trigger CodeDeploy
Depending on how you setup your Pipeline, auto deploy can be triggered manually by pressing release change in the pipeline page or automatically by pushing changes in our source code (e.g. Github repo).
For this demo, in Step 8, we selected to start the pipeline on source code change. So once we merge any pull request to master, it will trigger auto deploy to our EC2 instance.
In the our AWS CodeDeployDemoPipeline Page, you will see that the pipeline has been triggered by the merging of the pull request.
If we click on the Details link
of the Deploy stage and in the succeeding page click on View events link
. we will see the status of each hook stage we specified in our appspec.yml file.
As you can see in the images above our auto deploy is a success. Now it is time to check if our React Nginx app is working.
Troubleshooting: As mentioned in Step5, common auto deploy failures can be solved by installing/reinstalling CodeDeploy agent in the EC2 instance. For example:
Also check that correct tags and IAM role are attached to your EC2 instance.
Step 12: Check if our auto deployed react app is running.
To check whether our auto deploy using CodeDeploy is succesful, we need to check if the react app serverd through Nginx is running. To do this let's first open up our our EC2 instance's port 80 for inbound traffic.
Go to the AWS EC2 page > Network & Security > Security Groups > Create Security Groups.
We will name our security group, AWSCodeDeployDemo. Then we will create a new Inbound Rule that will allow access to port 80 for any EC2 instance belonging to the security group.
Go back to EC2 Instance page. Right click on your instance.
Then select Security> Change Security Groups
Next we will assign our EC2 instance to AWSCodeDeployDemo security group we created.
Click save.
Go to your browser and insert the IP of your ec2 instance.
You will see that our React App is running.
Quite a long process right? But all worth it given that moving forward you will prevent errors and save time now that everything is deployed automatically.
Until next time. Keep learning.
Stay stoked and code. :)
I hope you can voluntarily Buy Me A Coffee if you found this article useful and give additional support for me to continue sharing more content for the community. :)
Thank you very much. :)