Step 5: Deploy Additional Web Application - Alex-Burgess/ansible-demo GitHub Wiki
As part of deploying an additional web application, called webappA, we will look into the Ansible playbooks and configuration at a deeper level. This will show the extensibility of the way this project has been structured.
Non-Ansible Specific Components
The non-ansible components are as follows.
- Infrastructure stack
- Web Application Files
- Web Content (Sites)
Infrastructure Stack
As in earlier steps, webservers.template will be used to create a CloudFormation stack of the infrastructure required for the web app. A parameters file, params_webappA.json has already been created with the necessary values. The only difference between the parameters for webappA and demo webapp is WebAppName. To build the stack:
$ cd AnsibleWebDemo/cloudformation
$ aws cloudformation create-stack \
--stack-name WebAppA \
--template-url https://s3.amazonaws.com/ansible-hello-world/cloudformation/webservers.template \
--parameters file://params_webappA.json \
--capabilities CAPABILITY_NAMED_IAM
Web Application Files
Each web app has it's own directory, where the httpd configuration files reside. These files are copied to the webserver instances after a base install of apache is deployed. This allows each web application to have different configuration.
webapps/
|-- ansiblewebdemo
| |-- config
| | |-- httpd
| | | |-- conf
| | | | |-- httpd.conf
| | | | |-- magic
| | | |-- conf.d
| | | | |-- autoindex.conf
| | | | |-- php.conf
| | | | |-- vhost.conf
...etc
The vhost.conf file has particular significance for this project as it is where the document root(s) of the web content are configured. For example, in this snippet the helloworld.com site is configured as a document root:
NameVirtualHost *:80
<VirtualHost *:80>
ServerAdmin [email protected]
ServerName helloworld.com
ServerAlias www.helloworld.com
DocumentRoot /var/www/html/helloworld.com/html/
ErrorLog /var/www/html/helloworld.com/logs/error.log
CustomLog /var/www/html/helloworld.com/logs/access.log combined
</VirtualHost>
Note, it is possible to define multiple virtual hosts in this file, for multiple sites.
Sites
The site(s) that are defined in the vhost.conf httpd configuration file exist in sites. e.g.
sites/
|-- helloworld.com
| |-- config
| | |-- ...
| |-- html
| | |-- ...
|-- monitoring.com
| |-- ...
...etc
Separating sites from the web app configuration, keeps things clear and easy to understand, as well as meaning that a given site can be deployed to multiple web apps.
Ansible Specific Components
The Ansible specific components are:
- Inventory
- Group variables
- Main Playbook
- Roles
Inventory
A hosts file which defines the instances the web app will be deployed to. As before, we need to update the hosts file for webappA.
$ aws ec2 describe-instances --query 'Reservations[*].Instances[*].{IP:PrivateIpAddress,AZ:Placement.AvailabilityZone}' --output text --filters 'Name=instance-state-name,Values=running' 'Name=tag:Type,Values=Webserver' 'Name=tag:Environment,Values=test' 'Name=tag:WebApp,Values=webappA'
$ vi inventories/test/webappA_hosts
Group_vars
In order to use site.yml playbook to deploy different webapps, we use a variable based approach to alter the playbook operation. So each webapp has a group vars file, which is tied to a webapp group in the hosts file. Below you can see the webappA group in the hosts file, and the webappA.yml group vars file definition:
inventories/test/webappA_hosts:
[webservers:children]
webappA
[webappA:children]
eu-west-1a-webservers
eu-west-1b-webservers
eu-west-1c-webservers
[eu-west-1a-webservers]
10.0.0.231
[eu-west-1b-webservers]
10.0.1.59
[eu-west-1c-webservers]
inventories/test/group_vars/webappA.yml:
---
sites:
- helloworld.com
- monitoring.com
webapp_root_path: /tmp/git_checkout/webapps/webappA
webapp_httpd_path: "{{ webapp_root_path }}/config/httpd"
sites_root_path: /tmp/git_checkout/sites
app_html_src_path: "{{ sites_root_path }}/{{ site }}/html"
app_config_src_path: "{{ sites_root_path }}/{{ site }}/config"
app_config_app_ini_file: "{{ app_config_src_path }}/app.ini.test"
Main Playbook
In previous steps, we used the site.yml file to deploy the demo web app. To deploy webappA we will use the same playbook but with the webappA_hosts inventory file:
$ ansible-playbook -i inventories/test/webappA_hosts site.yml
The operation of the tasks in this playbook (or referenced by this playbook), are altered by the group vars related to the group defined in the hosts file.
Roles
The content of the site.yml playbook, is actually quite limited. The playbook just includes 2 roles, one called repo and the other web. As the Ansible documentation states, Roles are ways of automatically loading certain vars_files, tasks and handlers based on a known file structure. Grouping content by roles also allows easy sharing of roles with other users.
The main role is the web role. This performs the tasks to install the web server and then copy the configuration and content to the correct locations on the instances. The web role has default vars set in the roles/web/defaults/main.yml file, but in this instance they are overridden by the inventories/test/group_vars/webappA.yml group vars file.
When deploying the configuration and content, it is intended to deploy the latest version from the git repository. So, the repo role is used to perform this task. It is possible to deploy a different branch though for testing purposes, which is achieved by specifying a git_branch extra variable on the command line when executing the site.yml playbook.
Above was a limited explanation of the roles. One of the beauties of Ansible is that it's declarative so the playbooks should be straight forward to understand. For more details on Ansible Roles see the documentation
Conclusion
Assuming the site.yml playbook was already triggered with the webappA hosts file, it's possible to test the application via the load balancer:
$ aws cloudformation describe-stacks --query 'Stacks[*].Outputs[?OutputKey==`URL`].OutputValue' --output text --stack-name WebAppA
http://webappA-test-1234567890.eu-west-1.elb.amazonaws.com
As stated at the beginning of this page, the structure employed in this project allows for extensiblity, as site.yml can deploy different web applications. The necessary structural components for each webapp need to be defined, but crucially there are no changes required to the playbooks/roles.
For additional notes see Ansible Inventory Information Inventory