Adding the CodeDeploy configuration and scripts to our repository

When we worked on creating a Jenkins pipeline earlier in this chapter, we created a Jenkinsfile file inside the helloworld GitHub repository. The reason for this was that we could change the code and the way the code is tested in the same change set. For the very same reason, it is very practical to put the logic behind how to deploy our code alongside the code itself.

Our helloworld repository currently has the application and its tests. We are going to add the information CodeDeploy needs to execute a deploy of our service.

CodeDeploy relies on a file called appspec.yml (application specification file) to manage the deployment. We are first going to create it.

Go to the directory where the helloworld GitHub project is cloned and create a new branch off the master:

$ cd helloworld
$ git checkout master
$ git pull
$ git checkout -b helloworld-codedeploy

We are now going to create and edit the file appspec.yml:

$ touch appspec.yml  

On the first line of the file, we are going to define the version of the AppSpec file. Currently, the only version supported is 0.0:

version: 0.0 

On the next line, we are going to specify the operating system on which we wish to deploy, in our case Linux:

os: linux 

We are now going to describe which file goes where. To do that, we are going to create a section called files and put each file we want to deploy using a format source destination. Note that the file is written in YAML and therefore the spacing and alignment is important:

version: 0.0 
os: linux 
files:
- source: helloworld.js
destination: /usr/local/helloworld/

Thanks to that section, CodeDeploy now knows to copy the helloworld.js in the target destination /usr/local/helloworld. Our helloworld directory will be automatically created by CodeDeploy. In order to start the application, we will also need our Upstart script that isn't currently in the repository.

Back in our Terminal in the root directory of the helloworld project, we are going to create a subdirectory called scripts and add the Upstart script to it:

$ mkdir scripts
$ wget http://bit.ly/2uDrMam -O scripts/helloworld.conf  

We can now add that new file to our appspsec.yml by adding another block with the source and destination of the Upstart script as follows:

files: 
  - source: helloworld.js 
    destination: /usr/local/helloworld/ 
  - source: scripts/helloworld.conf
destination: /etc/init/

The two files we need in order to run our application as a service will now be present in the appropriate locations, but in order to deploy our application, we need more. We need CodeDeploy to start and stop the service. Previously, we started the application using Ansible, but this time around we aren't using Ansible to manage our service. CodeDeploy has a much more elegant solution for that. When a deploy starts, the CodeDeploy agent running on the EC2 instance will go through the following sequence of events:

The archive containing our application will be downloaded on the system during the Download Bundle event, and the Install section will be used to copy the files defined in our template in their destinations.

CodeDeploy has a concept of hooks. In the appspec.yml file we can create a number of hooks to execute custom scripts during each of the stages described previously. We are going to create three scripts: a script to start our application, a script to stop it, and finally a script to check if the deployment was successful.

We will put those three scripts in the scripts directory we previously created. Let's create the first file start.sh and start editing it:

$ touch scripts/start.sh  

The script is very straightforward. We are simply going to call Upstart to start the service:

#!/bin/sh
    
start helloworld  

That's all we need; we are now going to create our stop script file:

$ touch scripts/stop.sh  

Then, as before, we can edit it:

#!/bin/sh
    
[[ -e /etc/init/helloworld.conf ]] 
  && status helloworld | 
    grep -q '^helloworld start/running, process' 
  && [[ $? -eq 0 ]] 
  && stop helloworld || echo "Application not started"  

The stop script is slightly more complicated than the start script as it will be executed during the BeforeInstall step. The basic logic is the same: we are going to call for helloworld to stop. The reason why we have some extra calls beforehand is that we need to handle the case of the first deployment where the application hasn't been installed and started before.

The last script we will create is called validate.sh:

$ touch scripts/validate.sh  

Once again, the code is very simple:

#!/bin/sh
curl -I localhost:3000  

For the purposes of the book, we are making the most basic validation possible, doing a HEAD request on the only route our application has. In a more realistic application, we would test more routes and everything that could potentially go wrong when new code is pushed out.

Our scripts need to be executable to avoid any unnecessary warnings in CodeDeploy:

$ chmod a+x scripts/{start,stop,validate}.sh  

We can now add our hooks in our appspec.yml file.

Open the file again and below the files section, create a hooks section:

version: 0.0 
os: linux 
files: 
[...] 
hooks: 

We will first declare the stop script that we want to run at the BeforeInstall stage. In the hooks section, add the following:

hooks: 
  BeforeInstall: 
    - location: scripts/stop.sh 
      timeout: 30 

We are allowing 30 seconds for the execution of the stop command to complete.

We are going to repeat a similar operation to add our start and validate scripts as follows:

hooks: 
  BeforeInstall: 
    - location: scripts/stop.sh 
      timeout: 30 
  ApplicationStart:
- location: scripts/start.sh
timeout: 30
ValidateService:
- location: scripts/validate.sh

At the point when our deploy pipeline will run, it will try to do the following:

  1. Download our application package and decompress it in a temporary directory.
  2. Run the stop script.
  3. Copy the application and Upstart script.
  4. Run the start script.
  5. Run the validate script to make sure everything is working as expected.

We can add all our new files to git, commit and push the changes, and send a pull request:

$ git add scripts appspec.yml
$ git commit -m "Adding CodeDeploy support to the application"
$ git push  

The branch will go through Jenkins and be tested. A peer can then review the code change and once approved, you can merge your pull request.

In order to perform a deployment, we essentially need to answer three questions: What to deploy? Where to deploy it? How to deploy it? We answered the Where to deploy? question when we created the job in CodeDeploy and just answered the How to deploy? question with our appspec file and its helper scripts. We now need to look into the What to deploy? question. This is where we are going to use AWS CodePipeline.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset