Creating roles to deploy and start our web application

We are going to use roles to recreate the HelloWorld stack we previously made using the UserData block of CloudFormation. If you recall, the UserData looked roughly like this:

yum install --enablerepo=epel -y nodejs 
wget http://bit.ly/2vESNuc -O /home/ec2-user/helloworld.js 
wget http://bit.ly/2vVvT18 -O /etc/init/helloworld.conf 
start helloworld 

You will notice three different types of operation in the preceding script. We are first preparing the system to run our application. To do that, in our example, we are simply installing Node.js. Next, we copy the different resources needed to run the application, in our case, the JavaScript code and the Upstart configuration. Finally, we start the service.

As always when programming, it is important to keep the code DRY. If deploying and starting our application is very unique to our HelloWorld project, installing Node.js likely isn't. In order to make the installation of Node.js a reusable piece of code, we are going to create two roles: one to install Node.js and one to deploy and start the HelloWorld application.

By default, Ansible expects to see roles inside a roles folder at the root of the Ansible repository. The first thing we need to do is to create this folder and cd into it:

$ mkdir roles
$ cd roles  

We can now create our roles.

Ansible has an ansible-galaxy command, which can be used to initialize the creation of a role. The first role we will look into is the role that will install Node.js:

$ ansible-galaxy init nodejs
- nodejs was created successfully  
As briefly mentioned, Ansible like most other configuration management systems has strong community support, which shares roles online via https://galaxy.ansible.com/. In addition to using the ansible-galaxy command to create the skeleton for new roles, you can also use ansible-galaxy to import and install community-supported roles.

This creates a directory nodejs and a number of subdirectories that will let us structure the different sections of our role. We are going to go into that directory:

$ cd nodejs  

The most important folder inside that nodejs directory is the one called tasks. When Ansible executes a playbook, it runs the code present in the file tasks/main.yml.

Open the file with your favorite text editor.

When you first open main.yml, you will see the following:

--- 
# tasks file for nodejs 

The goal of the nodejs role is to install Node.js and npm. To do so, we will proceed similarly to how we did in the UserData script and use yum to perform those tasks.

When writing a task in Ansible, you sequence a number of calls to various Ansible modules. The first module we are going to look at is a wrapper around the yum command. The documentation on it is available at http://bit.ly/28joDLe. This will let us install our packages. We are also going to introduce the concept of loops. Since we have two pages to install, we will want to call the yum module twice. We use the operator with_items.

After the initial three dashes and comments, we are going to call the yum module in order to install our packages:

--- 
# tasks file for nodejs 
 
- name: Installing node and npm 
  yum: 
    name: "{{ item }}" 
    enablerepo: epel 
    state: installed 
  with_items: 
    - nodejs 
    - npm 

Whenever Ansible runs that playbook, it will look at packages installed on the system and if it doesn't find the nodejs or npm packages, it will install them.

This first role is complete. For the purpose of this book, we are keeping the role very simple, but you can imagine, in a more production-type environment, having a role that will install specific versions of Node.js and npm, fetching the binaries directly from https://nodejs.org/en/, and maybe even installing specific dependencies.

Our next role will be dedicated to deploying and starting the Hello World application we built previously. We are going to go one directory up back into the roles directory and call ansible-galaxy one more time:

$ cd ..
$ ansible-galaxy init helloworld
- helloworld was created successfully  

Like before, we will now go inside the newly created helloworld directory:

$ cd helloworld  

This time, we will explore some of the other directories present. One of the subdirectories that was created when we ran the ansible-galaxy command is the directory called files. Adding files to that directory will give us the ability to copy files on the remote hosts.

To do so, we are first going to download our two files in this directory:

$ wget http://bit.ly/2vESNuc -O files/helloworld.js
$ wget http://bit.ly/2vVvT18 -O files/helloworld.conf  

We can now use task files to perform the copy on the remote system. Open the file tasks/main.yml and, after the initial three dashes and comment, add the following:

- name: Copying the application file 
  copy: 
    src: helloworld.js 
    dest: /home/ec2-user/ 
    owner: ec2-user 
    group: ec2-user 
    mode: 0644 
  notify: restart helloworld 

We are taking advantage of the copy module documented at http://bit.ly/1WBv08E to copy our application file in the home directory of the ec2-user. On the last line of that call, we add at the end a notify option (note how the notify statement is aligned with the call to the copy module). Notify actions are triggers that can be added at the end of each block of tasks in a playbook. In this example, we are telling Ansible to call the restart helloworld directive if the file helloworld.js changed (we will define how to do a restart of the helloworld application a bit later in a different file). One of the big differences between CloudFormation and Ansible is that Ansible is expected to run multiple times throughout the lifetime of your systems. A lot of the functionalities built into Ansible are optimized for long-running instances. As such, the notify option makes it easy to trigger events when a system changes state. Similarly, Ansible will know to stop the execution when an error is encountered preventing outages as far as possible.

Now that we have copied our application file, we can add our second file, the Upstart script. After the previous call to copy the helloword.js file we are going to add the following call:

- name: Copying the upstart file 
  copy: 
    src: helloworld.conf 
    dest: /etc/init/helloworld.conf 
    owner: root 
    group: root 
    mode: 0644 

The last task we need to perform is to start our service. We will use the service module for that. The module documentation is available at http://bit.ly/22I7QNH:

- name: Starting the HelloWorld node service 
  service: 
    name: helloworld 
    state: started 

Our task file is now completed. You should end up with something resembling the following: http://bit.ly/2uPlJTk. Having finished our task file, we are going to move on to the next file, which will give Ansible knowledge of how to restart helloworld as called out in the notify parameter of our task.

These types of interaction are defined in the handler section of the role. We are going to edit the file handlers/main.yml. Here too, we are going to use the service module. The following is a comment:

--- 
# handlers file for helloworld 

Now, add the following code snippet:

- name: restart helloworld 
  service: 
    name: helloworld 
    state: restarted 

No surprises here; we are using the same module we previously used to manage the service. We need one more step in our role. In order for that role to work, the system needs to have Node.js installed. Ansible supports the concept of role dependencies. We can explicitly tell that our helloworld role depends on the nodejs role we previously created such that, if the helloworld role is executed, it will first call the nodejs role and install the necessary requirements to run the app.

Open the file meta/main.yml.

This file has two sections. The first one under galaxy_info lets you fill in information on the role you are building. If you desire, you can ultimately publish your role on GitHub and link to it back into ansible-galaxy to share your creation with the Ansible community. The second section at the bottom of the file is called dependencies and it is the one we want to edit to make sure that Node.js is present on the system prior to starting our application.

Remove the square brackets ([]) and add an entry to call nodejs as follows:

dependencies: 
  - nodejs 

Your file should look like this: http://bit.ly/2uOUyry.

This concludes the creation of the code for the role. From a documentation standpoint, it is good practice also to edit README.md.

Once done, we can move on to creating a playbook file that will reference our newly created role.

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

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