{"id":47271,"date":"2017-03-30T18:09:36","date_gmt":"2017-03-30T12:39:36","guid":{"rendered":"http:\/\/www.tothenew.com\/blog\/?p=47271"},"modified":"2017-03-31T09:57:31","modified_gmt":"2017-03-31T04:27:31","slug":"how-to-use-dynamic-inventory-for-aws-with-ansible","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/how-to-use-dynamic-inventory-for-aws-with-ansible\/","title":{"rendered":"How to Use Dynamic Inventory for AWS with Ansible?"},"content":{"rendered":"<p>Do you know how Ansible works? Well, before we walk you through how to setup dynamic inventory, here&#8217;s some food for thoughts on <a title=\"Ansible\" href=\"http:\/\/www.tothenew.com\/blog\/ansible-configuration-management-system\/\">Ansible Configuration Management System<\/a><\/p>\n<p>A user using configuration management system will often want to save inventory in a different software system. As described in inventory, a basic text-based system is provided by Ansible. Some examples include pulling inventory from a cloud provider, LDAP, Cobbler, and a piece of expensive enterprise CMDB software.<\/p>\n<p>These options are supported by Ansible through an external inventory system. Some of these such as EC2\/Eucalyptus, Rackspace Cloud, and OpenStack are already a part of the\u00a0contrib\/inventory directory.<\/p>\n<p>Maintaining an inventory file might not be the best approach if you <a title=\"DevOps on AWS\" href=\"http:\/\/www.tothenew.com\/devops-aws\">use Amazon Web Services EC2<\/a>. This is because the hosts may vary over time, they can be managed by external applications, or you might be using AWS autoscaling. In such a case, you can use the\u00a0<a href=\"https:\/\/raw.github.com\/ansible\/ansible\/devel\/contrib\/inventory\/ec2.py\">EC2 external inventory<\/a>\u00a0script.<\/p>\n<p><b>Setting up EC2 External Inventory Script With Ansible<\/b><\/p>\n<p><span style=\"font-weight: 400;\">One way to setup an ec2 external inventory script is to copy the script to \/etc\/Ansible\/ec2.py and chmod +x it. You will also need to copy the <\/span><a href=\"https:\/\/raw.githubusercontent.com\/ansible\/ansible\/devel\/contrib\/inventory\/ec2.ini\"><span style=\"font-weight: 400;\">ec2.ini<\/span><\/a><span style=\"font-weight: 400;\"> file to \/etc\/Ansible\/ec2.ini. Once done, you can run Ansible as you would normally do.<\/span><\/p>\n<p>For making a successful API call to AWS,\u00a0<span style=\"font-weight: 400;\">you will need to configure Boto (the Python interface to AWS). There are a\u00a0<\/span><a href=\"http:\/\/docs.pythonboto.org\/en\/latest\/boto_config_tut.html\"><span style=\"font-weight: 400;\">variety of methods<\/span><\/a><span style=\"font-weight: 400;\"> available, but the simplest is to export the following environment variables:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">export AWS_ACCESS_KEY_ID=&#8217;AK123&#8242;<\/span><span style=\"font-weight: 400;\"><br \/>\n<\/span><span style=\"font-weight: 400;\">export AWS_SECRET_ACCESS_KEY=&#8217;abc123&#8242;<\/span><span style=\"font-weight: 400;\"><br \/>\n<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Now, you will need to set up a few more environment variables to the inventory management script such as\u00a0<\/span><\/p>\n<p><em><strong>$ export ANSIBLE_HOSTS=\/etc\/ansible\/ec2.py<\/strong>\u00a0<\/em>This variable<span style=\"font-weight: 400;\">\u00a0tells Ansible to use the dynamic EC2 script instead of a static \/etc\/ansible\/hosts file.\u00a0<\/span>Open up ec2.py in a text editor and make sure that the path to ec2.ini config file is defined correctly at the top of the script:<\/p>\n<p><strong>$ export EC2_INI_PATH=\/etc\/ansible\/ec2.ini <\/strong><span style=\"font-weight: 400;\">This variable tells ec2.py where the ec2.ini config file is located.<\/span><\/p>\n<p>You can test the script to make sure your config is correct:<\/p>\n<p><span style=\"font-weight: 400;\">cd \/etc\/ansible<\/span><span style=\"font-weight: 400;\"><br \/>\n<\/span><span style=\"font-weight: 400;\">.\/ec2.py &#8211;list<\/span><\/p>\n<p><span style=\"font-weight: 400;\">After some time, you should be able to see the entire EC2 inventory across all regions in JSON. You can have a look at the scripts of <a href=\"https:\/\/raw.githubusercontent.com\/ansible\/ansible\/devel\/contrib\/inventory\/ec2.py\">EC2.py<\/a> and <a href=\"https:\/\/raw.githubusercontent.com\/ansible\/ansible\/devel\/contrib\/inventory\/ec2.ini\">EC2.ini<\/a><\/span><\/p>\n<p><b>Understanding Tags and Host variables<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Let us first understand how tags in external inventory work followed by how we can use them. Here&#8217;s an example playbook command:<\/span><\/p>\n<p><b>\/etc\/ansible\/playbooks$ ansible-playbook docker-update.yml &#8211;extra-vars \u00a0\u00a0\u00a0\u201cvariable_host=tag_Ecs_true:tag_User_ec2:&amp;tag_Environment_stage\u201d<\/b><\/p>\n<p><span style=\"font-weight: 400;\">In the above example:<\/span><\/p>\n<ol>\n<li><span style=\"font-weight: 400;\"> ansible-playbook is the standard command to run a playbook<\/span><\/li>\n<li><span style=\"font-weight: 400;\"> docker-update.yml is the name of our playbook inside the playbooks folder<\/span><\/li>\n<li><span style=\"font-weight: 400;\"> &#8211;extra-vars is a parameter which tells the main command to take the following string as an input for the playbook file<\/span><\/li>\n<li><span style=\"font-weight: 400;\"> variable_host is the variable that is being called inside the playbook to place a value for the hosts<\/span><\/li>\n<li><span style=\"font-weight: 400;\"> tag_Ecs_true:tag_User_ec2:&amp;tag_Environment_stage: These are tags and a way to tell playbook where to run the tasks, which user and key file to use to access the hosts<\/span><\/li>\n<\/ol>\n<p><span style=\"font-weight: 400;\">Whenever Ansible sees <em>tag_Ecs_true<\/em>, it tries to find all the<em> ec2s<\/em> in AWS account that has the tag Name \u2018Ecs\u2019 and Value \u2018true\u2019.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Simultaneously, Ansible also searches a group variable <em>(inside group_vars folder)<\/em> file with the name <em>tag_Ecs_true<\/em> for any host variable that we may have provided in that file.\u00a0<\/span>The above stands true for all and any \u2018tag_abc_xyz\u2019 provided along with the ansible-playbook command.<\/p>\n<p><span style=\"font-weight: 400;\">Let&#8217;s break these tags and see what they mean<\/span><\/p>\n<p><b>Key file management:<\/b><span style=\"font-weight: 400;\"> tag_Environment_stage &#8212; We need to tag all the ec2s in our account with the environment tag and respective value. We make use of this tag for providing the location of the key file required to access those ec2s. As explained earlier, Ansible will search inside the group_vars folder for a file named tag_Environment_stage, where we have already mentioned\u00a0<\/span>ansible_ssh_private_key_file: ~\/.ssh\/environment-staging.pem<\/p>\n<p><span style=\"font-weight: 400;\">This\u00a0is nothing but the location of the key file. Similarly, we can manage all the key files.<\/span><\/p>\n<p><b>User management:<\/b><span style=\"font-weight: 400;\"> tag_User_ec2 &#8212; Now, Ansible will again search inside the group_vars folder for a file named tag_User_ec2, where we have already mentioned\u00a0<\/span>ansible_ssh_user: ec2-user. Thus, it uses ec2-user to access the hosts.<\/p>\n<p><b>Where to run the playbook: <\/b><span style=\"font-weight: 400;\">tag_Ecs_true &#8212; This enables Ansible to look for all the hosts with the tag Ecs:true Name:value pair. We need to tag all the ECS instances with this tag so that we can make use of it whenever we need to run a playbook on them.<\/span><\/p>\n<p><b>Patterns and Combinations of Tags<\/b><\/p>\n<p><span style=\"font-weight: 400;\">We will need various combinations of tags for which we can make use of standard Ansible patterns.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">In the previous example, tag_Ecs_true:tag_User_ec2:&amp;tag_Environment_stage, \u2018:\u2019 means that all the hosts in group tag_Ecs_true and tag_User_ec2 are to be managed if they are in the group tag_Environment_stage also \u2018&amp;\u2019.<\/span><\/p>\n<p><strong><span style=\"font-weight: 400;\">Please refer <a href=\"http:\/\/docs.ansible.com\/ansible\/intro_patterns.html\">patterns document<\/a><\/span><span style=\"font-weight: 400;\">\u00a0for a\u00a0detailed explanation about patterns.<\/span><\/strong><\/p>\n<p><b>Handling Python Version Dependency\u00a0<\/b><\/p>\n<ul>\n<li>Ansible server checks for a specific version of python in all the target hosts to be able to run the playbooks or perform any action. As we are aware of the various OS families we are using in our infrastructure we don\u2019t want to get stuck with python version dependencies.<\/li>\n<\/ul>\n<p>In order to achieve this, we use Ansible pre_tasks (inside every playbook) which are actions that run prior to the actual role or tasks that we want to perform on any host. Before even calling the pre_tasks, we explicitly stop the \u2018setup\u2019 process of the playbook where it gathers facts about the hosts. It is in the pre_tasks, that we mention about a\u00a0version of python which needs to be installed on each host where a playbook runs.<\/p>\n<p>Once this is done, the \u2018setup\u2019 is explicitly called and then the execution of actual roles\/tasks are performed by the playbook.<\/p>\n<p>Here is an example playbook that updates docker version:<\/p>\n<p>&#8211; hosts: &#8220;{{ variable_host | default(&#8216;web&#8217;)}}&#8221;<\/p>\n<p>gather_facts: no<\/p>\n<p>pre_tasks:<\/p>\n<p>&#8211; name: update on ubuntu<\/p>\n<p>raw: sudo apt-get -y update<\/p>\n<p>ignore_errors: true<\/p>\n<p>&#8211; name: &#8216;install python2 on ubuntu&#8217;<\/p>\n<p>raw: sudo apt-get -y install python-simplejson<\/p>\n<p>ignore_errors: true<\/p>\n<p>notify:<\/p>\n<p>&#8211; Gathering facts<\/p>\n<p>&#8211; name: update on Centos\/Redhat<\/p>\n<p>raw: sudo yum -y update<\/p>\n<p>ignore_errors: true<\/p>\n<p>&#8211; name: &#8216;install python2 on Centos\/Redhat&#8217;<\/p>\n<p>raw: sudo yum -y install python<\/p>\n<p>ignore_errors: true<\/p>\n<p>notify:<\/p>\n<p>&#8211; Gathering facts<\/p>\n<p>roles:<\/p>\n<p>&#8211; role: docker-update-role<\/p>\n<p>handlers:<\/p>\n<p>&#8211; name: Gathering facts<\/p>\n<p>setup:<\/p>\n<ul>\n<li>Another important addition in each playbook is provision for dynamic hosts: &#8211; hosts: &#8220;{{ variable_host | default(&#8216;web&#8217;)}}&#8221;<\/li>\n<\/ul>\n<p>We know our hosts are variable and we are not maintaining a static inventory of hosts. This is the reason why we don&#8217;t want our playbooks to be hosts dependent. Therefore, in all the playbooks we need to make the above entry.<\/p>\n<p>Hope this blog was useful and you will be able to use dynamic inventory for AWS with Ansible.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Do you know how Ansible works? Well, before we walk you through how to setup dynamic inventory, here&#8217;s some food for thoughts on Ansible Configuration Management System A user using configuration management system will often want to save inventory in a different software system. As described in inventory, a basic text-based system is provided by [&hellip;]<\/p>\n","protected":false},"author":934,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":48},"categories":[1174,4308,2348,1],"tags":[1172,1933,248,2366,1892,4164,1358],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/47271"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/934"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=47271"}],"version-history":[{"count":0,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/47271\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=47271"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=47271"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=47271"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}