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 same reason, it is a good idea to put the logic about how to deploy our code with the code itself. 

Our helloworld repository currently contains the application that we created inside a new GitHub organization (yogeshrahejahelloworld in my case). It also contains the applications tests and a repository with name helloworld . We are now going to add the information that CodeDeploy needs in order to execute the deployment of our service.

CodeDeploy relies on an application specification file called appspec.yml to manage deployment. We first need to create this file. Go to the directory where the helloworld GitHub project is cloned and create a new branch off the master:

$ git clone https://github.com/<YOUR GITHUB ORGANIZATION>/helloworld.git
$ cd helloworld
$ 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 which version of the AppSpec file we want to use. Currently, the only version that is 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 our service. In our case, this is Linux:

os: linux 

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

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

Thanks to this 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, which isn't currently in the repository.

Back in the Terminal of  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 https://raw.githubusercontent.com/yogeshraheja/Effective-DevOps-with-AWS/master/Chapter02/helloworld.conf -O scripts/helloworld.conf

We can now add the helloworld.conf file 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 that we need in order to run our application as a service will now be present in the appropriate locations. In order to deploy our application, we need more files. 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: when a deployment 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 DownloadBundle event. The install section will be used to copy the files defined in our template to their destinations.

CodeDeploy uses the 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 these three scripts in the scripts directory that we created previously. 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  

This is all we need. We are now going to create our stop script file:

$ touch scripts/stop.sh  

As we did before, edit it as follows:

#!/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 because it will be executed during the BeforeInstall step. The basic logic is the same: we are making a call to stop the helloworld application. We have some extra calls before this because 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 this book, we are carrying out the most basic validation possible. This consists of a HEAD request on the only route that our application has. In a more realistic application, we would test more routes and anything 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 create a hooks section below the files 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

When our deploy pipeline runs, 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 as follows:

$ 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; once it is approved, you can merge your pull request.

In order to perform deployment, we essentially need to answer three questions—what are we trying to deploy? Where are we trying to deploy it? How can we deploy it? We answered the second question when we created the job in CodeDeploy and the third question with our appspec file and its helper scripts. We now need to look into the first question—what are we trying to deploy? 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
18.220.235.104