{"id":6081,"date":"2020-03-04T05:52:29","date_gmt":"2020-03-04T10:52:29","guid":{"rendered":"\/db-blog\/?p=6081"},"modified":"2020-03-12T01:10:40","modified_gmt":"2020-03-12T05:10:40","slug":"aws-ansible-provision-an-ec2-instance-using-infrastructure-as-code","status":"publish","type":"post","link":"https:\/\/droidbasement.com\/db-blog\/aws-ansible-provision-an-ec2-instance-using-infrastructure-as-code\/","title":{"rendered":"AWS\/Ansible \u2013 Provision an EC2 instance using Infrastructure as Code"},"content":{"rendered":"\n<p><em>Note: Some of this is a duplicate of the <a rel=\"noreferrer noopener\" aria-label=\"AWS Lightsail (opens in a new tab)\" href=\"https:\/\/droidbasement.com\/db-blog\/aws-ansible-provision-a-lightsail-instance-using-infrastructure-as-code\/\" target=\"_blank\">AWS Lightsail<\/a> article; modified for EC2.<\/em><\/p>\n\n\n\n<p><a rel=\"noreferrer noopener\" aria-label=\" (opens in a new tab)\" href=\"https:\/\/aws.amazon.com\/ec2\/\" target=\"_blank\">EC2<\/a> is the compute service in AWS.  It is flexible, adaptable, scalable and is able to run Virtual Machine workloads to fit most every need.<\/p>\n\n\n\n<p>In this article we will use <a rel=\"noreferrer noopener\" aria-label=\" (opens in a new tab)\" href=\"https:\/\/www.ansible.com\/\" target=\"_blank\">Ansible<\/a>  (Infrastructure as Code) to swiftly bring up an AWS EC2 instance in us-east-1 on a static IP (Elastic IP), in a new VPC with an Internet Gateway, add a DNS Zone (Route 53)  for the site in mention 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> (some of the IAM policy implemented there will be in use here) and using ~\/.local\/bin|lib for the binaries\/libraries.<\/p>\n\n\n\n<p> Please use <a rel=\"noreferrer noopener\" 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;<\/a><a rel=\"noreferrer noopener\" href=\"https:\/\/aws.amazon.com\/free\/?all-free-tier.sort-by=item.additionalFields.SortRank&amp;all-free-tier.sort-order=asc\" target=\"_blank\">AWS Free Tier<\/a><a rel=\"noreferrer noopener\" 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;<\/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>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>Install\/Upgrade Boto (required by ec2_eip):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ pip3 install boto --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 EC2 and related (EIP\/VPC\/Routes\/IGW\/Route 53\/SG\/KeyPair):<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<p>Note: This is identical to the section in the <a rel=\"noreferrer noopener\" aria-label=\"AWS\/Terraform (opens in a new tab)\" href=\"https:\/\/droidbasement.com\/db-blog\/aws-terraform-provision-an-ec2-instance-using-infrastructure-as-code\/\" target=\"_blank\">AWS\/Terraform<\/a> article, but adds an allowance for route53:ListHostedZones, ec2:DescribeInstanceStatus and ec2:UpdateSecurityGroupRuleDescriptionsEgress: <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> {\n     \"Version\": \"2012-10-17\",\n     \"Statement\": [\n         {\n             \"Effect\": \"Allow\",\n             \"Action\": [\n                 \"ec2:UpdateSecurityGroupRuleDescriptionsEgress\",\n                 \"ec2:TerminateInstances\",\n                 \"route53:GetChange\",\n                 \"route53:GetHostedZone\",\n                 \"route53:ChangeTagsForResource\",\n                 \"route53:DeleteHostedZone\",\n                 \"route53:ListTagsForResource\" \n             ],\n             \"Resource\": [\n                \"arn:aws:ec2:*:&lt;AWS ACCOUNT ID&gt;:security-group\/\",\n                \"arn:aws:ec2:*:&lt;AWS ACCOUNT ID&gt;:instance\/*\",\n                \"arn:aws:route53:::hostedzone\/*\",\n                \"arn:aws:route53:::change\/*\"\n             ]<em>      <\/em>\n         },\n         {\n             \"Effect\": \"Allow\",\n             \"Action\": [\n                 \"ec2:DisassociateAddress\",\n                 \"ec2:DeleteSubnet\",\n                 \"ec2:DescribeAddresses\",\n                 \"ec2:DescribeInstances\",\n                 \"ec2:DescribeInstanceAttribute\",\n                 \"ec2:CreateVpc\",\n                 \"ec2:AttachInternetGateway\",\n                 \"ec2:DescribeVpcAttribute\",\n                 \"ec2:AssociateRouteTable\",\n                 \"ec2:DescribeInternetGateways\",\n                 \"ec2:DescribeNetworkInterfaces\",\n                 \"ec2:CreateInternetGateway\",\n                 \"ec2:CreateSecurityGroup\",\n                 \"ec2:DescribeVolumes\",\n                 \"ec2:DescribeAccountAttributes\",\n                 \"ec2:ModifyVpcAttribute\",\n                 \"ec2:DescribeKeyPairs\",\n                 \"ec2:DescribeNetworkAcls\",\n                 \"ec2:DescribeRouteTables\",\n                 \"ec2:DescribeInstanceStatus\",\n                 \"ec2:ReleaseAddress\",\n                 \"ec2:ImportKeyPair\",\n                 \"ec2:DescribeTags\",\n                 \"ec2:DescribeVpcClassicLinkDnsSupport\",\n                 \"ec2:CreateRouteTable\",\n                 \"ec2:DetachInternetGateway\",\n                 \"ec2:DisassociateRouteTable\",\n                 \"ec2:AllocateAddress\",\n                 \"ec2:DescribeInstanceCreditSpecifications\",\n                 \"ec2:DescribeSecurityGroups\",\n                 \"ec2:DescribeVpcClassicLink\",\n                 \"ec2:DescribeImages\",\n                 \"ec2:DescribeVpcs\",\n                 \"ec2:DeleteVpc\",\n                 \"ec2:AssociateAddress\",\n                 \"ec2:CreateSubnet\",\n                 \"ec2:DescribeSubnets\",\n                 \"ec2:DeleteKeyPair\",\n                 \"route53:CreateHostedZone\",\n                 \"route53:ListHostedZones\",\n                 \"sts:GetCallerIdentity\"\n             ],\n             \"Resource\": \"*\"\n         }\n     ]\n }<\/pre>\n\n\n\n<p>Review Policy -&gt;<\/p>\n\n\n\n<p>Name: AllowEC2<br>Description: Allow access to EC2 and related.<\/p>\n\n\n\n<p>Create Policy.<\/p>\n\n\n\n<p>Groups -&gt; container-admin -&gt; Attach Policy -&gt; Search for AllowEC2 -&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>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>The following is performed with this script\/code:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>create a Route 53 DNS Zone of myweb.com (no A records will be added)<\/li><li>create a Virtual Private Cloud for network 10.0.0.0\/16 (tenancy is default)<\/li><li>add a subnet of 10.0.1.0\/24 within the VPC<\/li><li>allocate a static Public IP<\/li><li>create a Security Group and add a Security rule for allowing SSH (port 22) Inbound<\/li><li>create an Internet Gateway and add a route out to it<\/li><li>create a T3a.micro instance (tenancy is default) based off of Ubuntu 18_04, our public key added as authorized and reference an extraneous file for user_data (initialization script on Virtual Machine boot).  Elastic\/Root Block Store is GP2<\/li><li>DNS support is enabled but DNS host names is not<\/li><li>tag all resources<\/li><\/ul>\n\n\n\n<p>Note: assign_public_ip was needed (an assignment at boot from the Amazon pool) so as not to disrupt user_data execution, due to Elastic IP (Static) being bound a bit later:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ cat &lt;&lt; 'EOF' > aws_ec2.yml\n> # Create an AWS EC2 instance and add a way to destroy it\n> ---\n> - hosts: local\n>   connection: local\n>\n>   vars:\n>     region: us-east-1\n>     prefix: myweb\n>     subnet_name: internal\n>\n>   tasks:\n>   - name: Create a DNS Zone\n>     route53_zone:\n>       state: present\n>       zone: \"{{ prefix }}.com\"\n>       comment: \"{{ prefix }}-dn\"\n>\n>   - name: Create a Virtual Private Cloud\n>     ec2_vpc_net:\n>       state: present\n>       name: \"{{ prefix }}-vpc\"\n>       cidr_block: 10.0.0.0\/16\n>       region: \"{{ region }}\"\n>       dns_hostnames: no\n>       tenancy: default\n>       tags:\n>           Site: \"{{ prefix }}.com\"\n>           Name: \"{{ prefix }}-vpc\"\n>     register: vpc\n>\n>   - name: Create a Security Group and allow inbound port(s)\n>     ec2_group:\n>       state: present\n>       name: \"{{ prefix }}\"\n>       description: Allow Ports\n>       vpc_id: \"{{ vpc.vpc.id }}\"\n>       region: \"{{ region }}\"\n>       rules:\n>         - proto: tcp\n>           from_port: 22\n>           to_port: 22\n>           cidr_ip: 0.0.0.0\/0\n>           rule_desc: SSH\n>       rules_egress:\n>         - proto: -1\n>           from_port: 0\n>           to_port: 0\n>           cidr_ip: 0.0.0.0\/0\n>           rule_desc: All\n>       tags:\n>           Site: \"{{ prefix }}.com\"\n>           Name: \"{{ prefix }}-sg\"\n>     register: sg\n>\n>   - name: Add a Subnet\n>     ec2_vpc_subnet:\n>       state: present\n>       vpc_id: \"{{ vpc.vpc.id }}\"\n>       cidr: 10.0.1.0\/24\n>       region: \"{{ region }}\"\n>       az: \"{{ region }}a\"\n>       tags:\n>           Site: \"{{ prefix }}.com\"\n>           Name: \"{{ subnet_name }}\"\n>     register: internal\n>\n>   - name: Create an Internet Gateway\n>     ec2_vpc_igw:\n>       state: present\n>       vpc_id: \"{{ vpc.vpc.id }}\"\n>       region: \"{{ region }}\"\n>       tags:\n>           Site: \"{{ prefix }}.com\"\n>           Name: \"{{ prefix }}-igw\"\n>     register: igw\n>\n>   - name: Add a route to the Internet Gateway\n>     ec2_vpc_route_table:\n>       state: present\n>       vpc_id: \"{{ vpc.vpc.id }}\"\n>       region: \"{{ region }}\"\n>       subnets: \"{{ internal.subnet.id }}\"\n>       routes:\n>         - dest: 0.0.0.0\/0\n>           gateway_id: \"{{ igw.gateway_id }}\"\n>       tags:\n>           Site: \"{{ prefix }}.com\"\n>           Name: \"{{ prefix }}-rt\"\n>\n>   - name: Add Public Key as authorized\n>     ec2_key:\n>       state: present\n>       name: \"{{ prefix }}\"\n>       key_material: \"{{ lookup('file', '~\/.ssh\/{{ prefix }}.pub') }}\"\n>       region: \"{{ region }}\"\n>\n>   - name: Select Ubuntu 18.04\n>     ec2_ami_info:\n>       region: \"{{ region }}\"\n>       owners: 099720109477 # Canonical\n>       filters:\n>         name: \"ubuntu\/images\/hvm-ssd\/ubuntu-bionic-18.04-amd64-server-*\"\n>     register: ec2_ami\n>\n>     # Get the latest Ubuntu 18.04 AMI\n>   - set_fact:\n>       ec2_ami_latest: \"{{ ec2_ami.images | selectattr('name', 'defined') | sort(attribute='creation_date') | last }}\"\n>\n>   - name: Create an Ubuntu Virtual Machine with key based access and run a script on boot\n>     ec2_instance:\n>       state: present\n>       name: \"{{ prefix }}-ec2\"\n>       key_name: \"{{ prefix }}\"\n>       region: \"{{ region }}\"\n>       instance_type: t3a.micro\n>       image_id: \"{{ ec2_ami_latest.image_id }}\"\n>       security_group: \"{{ sg.group_id }}\"\n>       network:\n>         assign_public_ip: true\n>       wait: yes\n>       wait_timeout: 500\n>       vpc_subnet_id: \"{{ internal.subnet.id }}\"\n>       tenancy: default\n>       user_data: \"{{ lookup('file', '.\/scripts\/install.sh') }}\"\n>       tags:\n>           Site: \"{{ prefix }}.com\"\n>     register: ec2\n>\n>   - name: Allocate and Associate a Static Public IP\n>     ec2_eip:\n>       state: present\n>       region: \"{{ region }}\"\n>       in_vpc: yes\n>       reuse_existing_ip_allowed: yes\n>       device_id: \"{{ ec2.instance_ids[0] }}\"\n>     register: eip\n>\n>   - debug: msg=\"Public IP (Static) is {{ eip.public_ip }} for {{ ec2.instances[0].tags.Name }}\"\n>     when: eip.public_ip is defined\n>\n>   - debug: msg=\"Run this playbook for {{ ec2.instances[0].tags.Name }} shortly to Allocate, Associate and list the Static Public IP.\"\n>     when: eip.public_ip is not defined\n>\n>   - name: Destroy the Elastic IP\n>     # Gather EC2 info.\n>     ec2_instance_info:\n>       filters:\n>         tag:Site: \"{{ prefix }}.com\"\n>         tag:Name: \"{{ prefix }}-ec2\"\n>         instance-state-name: [ \"running\", \"present\", \"started\", \"stopped\" ]\n>     register: ec2\n>     tags: [ 'never', 'destroy' ]\n>\n>     # Gather EIP info.\n>   - ec2_eip_info:\n>       filters:\n>         instance-id: \"{{ ec2.instances[0].instance_id }}\"\n>     register: eip\n>     when: ec2.instances[0].instance_id is defined\n>     tags: [ 'never', 'destroy' ]\n>\n>   - ec2_eip:\n>       state: absent\n>       region: \"{{ region }}\"\n>       device_id: \"{{ eip.addresses[0].instance_id }}\"\n>       release_on_disassociation: yes\n>     when: eip.addresses[0].instance_id is defined\n>     tags: [ 'never', 'destroy' ]\n>\n>   - name: Destroy the Elastic Compute 2 instance\n>     ec2_instance:\n>       state: absent\n>       instance_ids: \"{{ ec2.instances[0].instance_id }}\"\n>     when: ec2.instances[0].instance_id is defined\n>     tags: [ 'never', 'destroy' ]\n>\n>   - name: Destroy the Public Key\n>     ec2_key:\n>       state: absent\n>       name: \"{{ prefix }}\"\n>     tags: [ 'never', 'destroy' ]\n>\n>   - name: Destroy the Route to the Internet Gateway\n>     # Gather Route info.\n>     ec2_vpc_route_table_info:\n>       region: \"{{ region }}\"\n>       filters:\n>         tag:Site: \"{{ prefix }}.com\"\n>         tag:Name: \"{{ prefix }}-rt\"\n>     register: rt\n>     tags: [ 'never', 'destroy' ]\n>\n>   - ec2_vpc_route_table:\n>       state: absent\n>       vpc_id: \"{{ rt.route_tables[0].vpc_id }}\"\n>       region: \"{{ region }}\"\n>       route_table_id: \"{{ rt.route_tables[0].id }}\"\n>       lookup: id\n>     when: rt.route_tables[0].vpc_id is defined\n>     tags: [ 'never', 'destroy' ]\n>\n>   - name: Destroy the Subnet\n>     # Gather Subnet info.\n>     ec2_vpc_subnet_info:\n>       filters:\n>         tag:Site: \"{{ prefix }}.com\"\n>         tag:Name: \"{{ subnet_name }}\"\n>     register: internal\n>     tags: [ 'never', 'destroy' ]\n>\n>   - ec2_vpc_subnet:\n>       state: absent\n>       vpc_id: \"{{ internal.subnets[0].vpc_id }}\"\n>       cidr: \"{{ internal.subnets[0].cidr_block }}\"\n>       when: internal.subnets[0].vpc_id is defined\n>     tags: [ 'never', 'destroy' ]\n>\n>   - name: Destroy the Internet Gateway\n>     # Gather IGW info.\n>     ec2_vpc_igw_info:\n>       filters:\n>         tag:Site: \"{{ prefix }}.com\"\n>         tag:Name: \"{{ prefix }}-igw\"\n>     register: igw\n>     tags: [ 'never', 'destroy' ]\n>\n>   - ec2_vpc_igw:\n>       state: absent\n>       vpc_id: \"{{ igw.internet_gateways[0].attachments[0].vpc_id }}\"\n>       region: \"{{ region }}\"\n>     when: igw.internet_gateways[0].attachments[0].vpc_id is defined\n>     tags: [ 'never', 'destroy' ]\n>\n>   - name: Destroy the Security Group\n>     # Gather SG info.\n>     ec2_group_info:\n>       filters:\n>         tag:Site: \"{{ prefix }}.com\"\n>         tag:Name: \"{{ prefix }}-sg\"\n>     register: sg\n>     tags: [ 'never', 'destroy' ]\n>\n>   - ec2_group:\n>       state: absent\n>       group_id: \"{{ sg.security_groups[0].group_id }}\"\n>     when: sg.security_groups[0].group_id is defined\n>     tags: [ 'never', 'destroy' ]\n>\n>   - name: Destroy the Virtual Private Cloud\n>     # Gather VPC info.\n>     ec2_vpc_net_info:\n>       filters:\n>         tag:Site: \"{{ prefix }}.com\"\n>         tag:Name: \"{{ prefix }}-vpc\"\n>     register: vpc\n>     tags: [ 'never', 'destroy' ]\n>\n>   - ec2_vpc_net:\n>       state: absent\n>       name: \"{{ prefix }}-vpc\"\n>       cidr_block: \"{{ vpc.vpcs[0].cidr_block }}\"\n>       region: \"{{ region }}\"\n>     when: vpc.vpcs[0].cidr_block is defined\n>     tags: [ 'never', 'destroy' ]\n>\n>   - name: Destroy the DNS Zone\n>     route53_zone:\n>       state: absent\n>       zone: \"{{ prefix }}.com\"\n>       tags: [ 'never', 'destroy' ]\n> EOF <\/pre>\n\n\n\n<p>Create the shell script for user_data.<\/p>\n\n\n\n<p>Note: If you have gone through the AWS\/Ansible against Lightsail article, then this can be disregarded:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ cat &lt;&lt; 'EOF' &gt; scripts\/install.sh\n&gt; #!\/bin\/bash\n&gt;\n&gt; MY_HOME=\"\/home\/ubuntu\"\n&gt; export DEBIAN_FRONTEND=noninteractive\n&gt;\n&gt; # Install prereqs\n&gt; apt update\n&gt; apt install -y python3-pip apt-transport-https ca-certificates curl software-properties-common\n&gt; # Install docker\n&gt; curl -fsSL https:\/\/download.docker.com\/linux\/ubuntu\/gpg | apt-key add -\n&gt; add-apt-repository \"deb [arch=amd64] https:\/\/download.docker.com\/linux\/ubuntu $(lsb_release -cs) stable\"\n&gt; apt update\n&gt; apt install -y docker-ce\n&gt; # Install docker-compose\n&gt; su ubuntu -c \"mkdir -p $MY_HOME\/.local\/bin\"\n&gt; su ubuntu -c \"pip3 install docker-compose --upgrade --user &amp;&amp; chmod 754 $MY_HOME\/.local\/bin\/docker-compose\"\n&gt; usermod -aG docker ubuntu\n&gt; # Add PATH\n&gt; printf \"\\nexport PATH=\\$PATH:$MY_HOME\/.local\/bin\\n\" &gt;&gt; $MY_HOME\/.bashrc\n&gt;\n&gt; exit 0\n&gt; EOF<\/pre>\n\n\n\n<p>Run the playbook:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ ansible-playbook -i hosts aws_ec2.yml<\/pre>\n\n\n\n<p>Log on to the instance after a short while:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ ssh -i ~\/.ssh\/myweb ubuntu@&lt;The value of public_ip 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 aws_ec2.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\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Note: Some of this is a duplicate of the AWS Lightsail article; modified for EC2. EC2 is the compute service in AWS. It is flexible, adaptable, scalable and is able to run Virtual Machine workloads to fit most every need. In this article we will use Ansible (Infrastructure as Code) to swiftly bring up an [&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-6081","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\/6081","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=6081"}],"version-history":[{"count":47,"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/posts\/6081\/revisions"}],"predecessor-version":[{"id":6230,"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/posts\/6081\/revisions\/6230"}],"wp:attachment":[{"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/media?parent=6081"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/categories?post=6081"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/tags?post=6081"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}