{"id":5619,"date":"2020-02-05T02:45:16","date_gmt":"2020-02-05T07:45:16","guid":{"rendered":"\/db-blog\/?p=5619"},"modified":"2020-03-12T01:03:41","modified_gmt":"2020-03-12T05:03:41","slug":"aws-ansible-provision-a-lightsail-instance-using-infrastructure-as-code","status":"publish","type":"post","link":"https:\/\/droidbasement.com\/db-blog\/aws-ansible-provision-a-lightsail-instance-using-infrastructure-as-code\/","title":{"rendered":"AWS\/Ansible \u2013 Provision a Lightsail instance using Infrastructure as Code"},"content":{"rendered":"\n<p><em>Note: This article has been duplicated from the <a rel=\"noreferrer noopener\" aria-label=\"previous article (opens in a new tab)\" href=\"https:\/\/droidbasement.com\/db-blog\/aws-terraform-provision-a-lightsail-instance-using-infrastructure-as-code\/\" target=\"_blank\">previous article<\/a> which uses Terraform and has been modified for Ansible.<\/em><\/p>\n\n\n\n<p>AWS has introduced <a rel=\"noreferrer noopener\" aria-label=\"Lightsail (opens in a new tab)\" href=\"https:\/\/aws.amazon.com\/lightsail\/\" target=\"_blank\">Lightsail<\/a> to compete with Digital Ocean, Linode, etc. for an inexpensive VPS (Virtual Private Server) offering.<\/p>\n\n\n\n<p>In this article we will use <a href=\"https:\/\/www.ansible.com\/\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\" (opens in a new tab)\">Ansible<\/a> (Infrastructure as Code) to swiftly bring up an AWS Lightsail instance in us-east-1 on a dynamic IP and install docker\/docker-compose on it.<\/p>\n\n\n\n<p>We will use &#8216;myweb&#8217; as an example in this article, using the same base path of &#8216;dev&#8217; that was <a rel=\"noreferrer noopener\" aria-label=\"previously created (opens in a new tab)\" href=\"https:\/\/droidbasement.com\/db-blog\/?p=5346\" target=\"_blank\">previously created<\/a>, the <a rel=\"noreferrer noopener\" aria-label=\"container-admin group (opens in a new tab)\" href=\"https:\/\/droidbasement.com\/db-blog\/?p=5501\" target=\"_blank\">container-admin group<\/a> and using ~\/.local\/bin|lib for the binaries\/libraries.<\/p>\n\n\n\n<p>Please use <a rel=\"noreferrer noopener\" aria-label=\"'Get started with Lightsail for free' (opens in a new tab)\" href=\"https:\/\/portal.aws.amazon.com\/billing\/signup?client=lightsail&amp;fid=1A3F6B376ECAC516-2C15C39C5ACECACB&amp;redirect_url=https%3A%2F%2Flightsail.aws.amazon.com%2Fls%2Fsignup#\/start\" target=\"_blank\">&#8216;Get started with Lightsail for free&#8217;<\/a> prior to commencing with this article.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>&#8211;&gt;<br>Go in to the dev directory\/link located within your home directory:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ cd ~\/dev<\/pre>\n\n\n\n<p>Upgrade the AWS CLI on your host:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ pip3 install awscli --upgrade --user &amp;&amp; chmod 754 ~\/.local\/bin\/aws<\/pre>\n\n\n\n<p>Install\/Upgrade Ansible:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ pip3 install ansible --upgrade --user &amp;&amp; chmod 754 ~\/.local\/bin\/ansible ~\/.local\/bin\/ansible-playbook<\/pre>\n\n\n\n<p>Install\/Upgrade Boto3:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ pip3 install boto3 --upgrade --user<\/pre>\n\n\n\n<p>Create a work folder and change in to it:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ mkdir -p ansible\/myweb\/scripts &amp;&amp; cd ansible\/myweb<\/pre>\n\n\n\n<p>Add an IAM Policy to the container-admin group so it will have access to the Lightsail API:<br>AWS UI Console -&gt; Services -&gt; Security, Identity, &amp; Compliance -&gt; IAM -&gt; Policies -&gt; Create Policy -&gt; JSON (replace &lt;AWS ACCOUNT ID&gt; in the Resource arn with your Account\u2019s ID (shown under the top right drop-down (of your name) within the My Account page next to the Account Id: under Account Settings)):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">{\n     \"Version\": \"2012-10-17\",\n     \"Statement\": [\n         {\n             \"Effect\": \"Allow\",\n             \"Action\": [\n                 \"lightsail:GetRelationalDatabaseEvents\",\n                 \"lightsail:GetActiveNames\",\n                 \"lightsail:GetOperations\",\n                 \"lightsail:GetBlueprints\",\n                 \"lightsail:GetRelationalDatabaseMasterUserPassword\",\n                 \"lightsail:ExportSnapshot\",\n                 \"lightsail:UnpeerVpc\",\n                 \"lightsail:GetRelationalDatabaseLogEvents\",\n                 \"lightsail:GetRelationalDatabaseBlueprints\",\n                 \"lightsail:GetRelationalDatabaseBundles\",\n                 \"lightsail:CopySnapshot\",\n                 \"lightsail:GetRelationalDatabaseMetricData\",\n                 \"lightsail:PeerVpc\",\n                 \"lightsail:IsVpcPeered\",\n                 \"lightsail:UpdateRelationalDatabaseParameters\",\n                 \"lightsail:GetRegions\",\n                 \"lightsail:GetOperation\",\n                 \"lightsail:GetDisks\",\n                 \"lightsail:GetRelationalDatabaseParameters\",\n                 \"lightsail:GetBundles\",\n                 \"lightsail:GetRelationalDatabaseLogStreams\",\n                 \"lightsail:CreateKeyPair\",\n                 \"lightsail:ImportKeyPair\",\n                 \"lightsail:DeleteKeyPair\",\n                 \"lightsail:GetInstance\",\n                 \"lightsail:CreateInstances\",\n                 \"lightsail:DeleteInstance\",\n                 \"lightsail:GetDomains\",\n                 \"lightsail:GetDomain\",\n                 \"lightsail:CreateDomain\",\n                 \"lightsail:DeleteDomain\",\n                 \"lightsail:GetStaticIp\",\n                 \"lightsail:AllocateStaticIp\",\n                 \"lightsail:AttachStaticIp\",\n                 \"lightsail:DetachStaticIp\",\n                 \"lightsail:ReleaseStaticIp\"\n             ],\n             \"Resource\": \"*<em>\"         <\/em>\n         },\n         {\n             \"Effect\": \"Allow\",\n             \"Action\": \"lightsail:\",\n             \"Resource\": [\n                 \"arn:aws:lightsail::&lt;AWS ACCOUNT ID&gt;:StaticIp\/*\",\n                 \"arn:aws:lightsail::&lt;AWS ACCOUNT ID&gt;:ExportSnapshotRecord\/*\",\n                 \"arn:aws:lightsail::&lt;AWS ACCOUNT ID&gt;:Instance\/*<em>\",<\/em>\n                 <em>\"<\/em>arn:aws:lightsail::&lt;AWS ACCOUNT ID&gt;:CloudFormationStackRecord<em>\/<\/em>*\",\n                 \"arn:aws:lightsail::&lt;AWS ACCOUNT ID&gt;:RelationalDatabaseSnapshot\/*<em>\",<\/em>\n                 <em>\"<\/em>arn:aws:lightsail::&lt;AWS ACCOUNT ID&gt;:RelationalDatabase<em>\/<\/em>*\",\n                 \"arn:aws:lightsail::&lt;AWS ACCOUNT ID&gt;:InstanceSnapshot\/*<em>\",<\/em>\n                 <em>\"<\/em>arn:aws:lightsail::&lt;AWS ACCOUNT ID&gt;<em>:<\/em>Domain<em>\/<\/em>*\",\n                 \"arn:aws:lightsail::&lt;AWS ACCOUNT ID&gt;:LoadBalancer\/*<em>\",<\/em>\n                 <em>\"<\/em>arn:aws:lightsail::&lt;AWS ACCOUNT ID&gt;:KeyPair<em>\/<\/em>*\",\n                 \"arn:aws:lightsail::&lt;AWS ACCOUNT ID&gt;:Disk\/*\"\n             ]\n         }\n     ]\n }<\/pre>\n\n\n\n<p>Review Policy -&gt;<\/p>\n\n\n\n<p>Name: AllowLightsail<br>Description: Allow access to Lightsail.<\/p>\n\n\n\n<p>Create Policy.<\/p>\n\n\n\n<p>Groups -&gt; container-admin -&gt; Attach Policy -&gt; Search for AllowLightsail -&gt; Attach Policy.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Generate an SSH Key Pair (no password) and restrict permissions on it:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ ssh-keygen -q -t rsa -b 2048 -N '' -f ~\/.ssh\/myweb &amp;&amp; chmod 400 ~\/.ssh\/myweb<\/pre>\n\n\n\n<p>Import the public key to Lightsail:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ aws lightsail import-key-pair --key-pair-name myweb --public-key-base64 file:\/\/~\/.ssh\/myweb.pub<\/pre>\n\n\n\n<p>Create a hosts file and specify localhost:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ cat &lt;&lt; 'EOF' &gt; hosts\n&gt; [local]\n&gt; localhost\n&gt; EOF<\/pre>\n\n\n\n<p>Create a micro instance based off of Ubuntu 18_04 and reference an extraneous file for user_data (run once script on Virtual Machine boot):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ cat &lt;&lt; 'EOF' &gt; lightsail.yml\n&gt; # Create a new AWS Lightsail instance, register the instance details and add a way to destroy it\n&gt; ---\n&gt; - hosts: local\n&gt;   connection: local\n&gt;\n&gt;   tasks:\n&gt;     - lightsail:\n&gt;         state: present\n&gt;         name: myweb.com\n&gt;         region: us-east-1\n&gt;         zone: us-east-1a\n&gt;         blueprint_id: ubuntu_18_04\n&gt;         bundle_id: micro_2_0\n&gt;         key_pair_name: myweb\n&gt;         user_data: \"{{ lookup('file', '.\/scripts\/install.sh') }}\"\n&gt;         wait_timeout: 500\n&gt;       register: myweb\n&gt;\n&gt;     - debug: msg=\"Public IP is {{ myweb.instance.public_ip_address }} for {{ myweb.instance.name }}\"\n&gt;       when: myweb.instance.public_ip_address is defined\n&gt;\n&gt;     - debug: msg=\"Run this playbook for {{ myweb.instance.name }} shortly to list the Public IP.\"\n&gt;       when: myweb.instance.public_ip_address is not defined\n&gt;\n&gt;     - lightsail:\n&gt;         state: absent\n&gt;         name: myweb.com\n&gt;         region: us-east-1\n&gt;       tags: [ 'never', 'destroy' ]\n&gt; EOF<\/pre>\n\n\n\n<p>Create the shell script for user_data:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ cat &lt;&lt; 'EOF' > scripts\/install.sh\n> #!\/bin\/bash\n>\n> MY_HOME=\"\/home\/ubuntu\"\n> export DEBIAN_FRONTEND=noninteractive\n>\n> # Install prereqs\n> apt update\n> apt install -y python3-pip apt-transport-https ca-certificates curl software-properties-common\n> # Install docker\n> curl -fsSL https:\/\/download.docker.com\/linux\/ubuntu\/gpg | apt-key add -\n> add-apt-repository \"deb [arch=amd64] https:\/\/download.docker.com\/linux\/ubuntu $(lsb_release -cs) stable\"\n> apt update\n> apt install -y docker-ce\n> # Install docker-compose\n> su ubuntu -c \"mkdir -p $MY_HOME\/.local\/bin\"\n> su ubuntu -c \"pip3 install docker-compose --upgrade --user &amp;&amp; chmod 754 $MY_HOME\/.local\/bin\/docker-compose\"\n> usermod -aG docker ubuntu\n> # Add PATH\n> printf \"\\nexport PATH=\\$PATH:$MY_HOME\/.local\/bin\\n\" >> $MY_HOME\/.bashrc\n>\n> exit 0\n> EOF<\/pre>\n\n\n\n<p>Run the playbook:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ ansible-playbook -i hosts lightsail.yml<\/pre>\n\n\n\n<p>Log on to the instance (up to ~30 seconds may be needed for the attachment of the dynamic IP to the instance):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ ssh -i ~\/.ssh\/myweb ubuntu@&lt;The value of public_ip_address that was reported.  One can also re-run the playbook to print it again.&gt;<\/pre>\n\n\n\n<p>Type yes and hit enter to accept.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>On the host (a short while is needed for the run-once script to complete):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ docker --version\n$ docker-compose --version\n$ logout<\/pre>\n\n\n\n<p>Tear down the instance:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ ansible-playbook -i hosts lightsail.yml --tags \"destroy\"<\/pre>\n\n\n\n<p>&lt;&#8211;<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>References:<\/p>\n\n\n\n<p>Source: <br><a href=\"https:\/\/github.com\/pershoot\/ansible_myweb\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"ansible_myweb (opens in a new tab)\">ansible_myweb<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Note: This article has been duplicated from the previous article which uses Terraform and has been modified for Ansible. AWS has introduced Lightsail to compete with Digital Ocean, Linode, etc. for an inexpensive VPS (Virtual Private Server) offering. In this article we will use Ansible (Infrastructure as Code) to swiftly bring up an AWS Lightsail [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-5619","post","type-post","status-publish","format-standard","hentry","category-devops"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/posts\/5619","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/comments?post=5619"}],"version-history":[{"count":20,"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/posts\/5619\/revisions"}],"predecessor-version":[{"id":6227,"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/posts\/5619\/revisions\/6227"}],"wp:attachment":[{"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/media?parent=5619"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/categories?post=5619"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/tags?post=5619"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}