AWS has introduced Lightsail (https://aws NULL.amazon NULL.com/lightsail/) to compete with Digital Ocean, Linode, etc. for an inexpensive VPS (Virtual Private Server) offering.
In this article we will use Terraform (https://www NULL.terraform NULL.io/) (Infrastructure as Code) to swiftly bring up an AWS Lightsail instance in us-east-1 on a static IP, add a DNS Zone for the site in mention and install docker/docker-compose on it.
We will use ‘myweb’ as an example in this article, using the same base path of ‘dev’ that was previously created, the container-admin group and using ~/.local/bin for the binary.
Please use ‘Get started with Lightsail for free’ (https://portal NULL.aws NULL.amazon NULL.com/billing/signup?client=lightsail&fid=1A3F6B376ECAC516-2C15C39C5ACECACB&redirect_url=https%3A%2F%2Flightsail NULL.aws NULL.amazon NULL.com%2Fls%2Fsignup#/start) prior to commencing with this article.
–>
Go in to the dev directory/link located within your home directory:
$ cd ~/dev
Upgrade the AWS CLI on your host:
$ pip3 install awscli --upgrade --user && chmod 754 ~/.local/bin/aws
Grab Terraform:
$ wget https://releases.hashicorp.com/terraform/0.12.9/terraform_0.12.9_linux_amd64.zip
Install Unzip if you do not have it installed:
$ sudo apt update && sudo apt -y install unzip
Unzip it to ~/.local/bin and set permissions accordingly on it:
$ unzip terraform_0.12.9_linux_amd64.zip -d ~/.local/bin && chmod 754 ~/.local/bin/terraform
Create a work folder and change in to it:
$ mkdir -p terraform/myweb/scripts && cd terraform/myweb
Add an IAM Policy to the container-admin group so it will have access to the Lightsail API:
AWS UI Console -> Services -> Security, Identity, & Compliance -> IAM -> Policies -> Create Policy -> JSON (replace <AWS ACCOUNT ID> in the Resource arn with your Account’s ID (shown under the top right drop-down (of your name) within the My Account page next to the Account Id: under Account Settings)):
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "lightsail:GetRelationalDatabaseEvents", "lightsail:GetActiveNames", "lightsail:GetOperations", "lightsail:GetBlueprints", "lightsail:GetRelationalDatabaseMasterUserPassword", "lightsail:ExportSnapshot", "lightsail:UnpeerVpc", "lightsail:GetRelationalDatabaseLogEvents", "lightsail:GetRelationalDatabaseBlueprints", "lightsail:GetRelationalDatabaseBundles", "lightsail:CopySnapshot", "lightsail:GetRelationalDatabaseMetricData", "lightsail:PeerVpc", "lightsail:IsVpcPeered", "lightsail:UpdateRelationalDatabaseParameters", "lightsail:GetRegions", "lightsail:GetOperation", "lightsail:GetDisks", "lightsail:GetRelationalDatabaseParameters", "lightsail:GetBundles", "lightsail:GetRelationalDatabaseLogStreams", "lightsail:CreateKeyPair", "lightsail:ImportKeyPair", "lightsail:DeleteKeyPair", "lightsail:GetInstance", "lightsail:CreateInstances", "lightsail:DeleteInstance", "lightsail:GetDomains", "lightsail:GetDomain", "lightsail:CreateDomain", "lightsail:DeleteDomain", "lightsail:GetStaticIp", "lightsail:AllocateStaticIp", "lightsail:AttachStaticIp", "lightsail:DetachStaticIp", "lightsail:ReleaseStaticIp" ], "Resource": "*" }, { "Effect": "Allow", "Action": "lightsail:", "Resource": [ "arn:aws:lightsail::<AWS ACCOUNT ID>:StaticIp/*", "arn:aws:lightsail::<AWS ACCOUNT ID>:ExportSnapshotRecord/*", "arn:aws:lightsail::<AWS ACCOUNT ID>:Instance/*", "arn:aws:lightsail::<AWS ACCOUNT ID>:CloudFormationStackRecord/*", "arn:aws:lightsail::<AWS ACCOUNT ID>:RelationalDatabaseSnapshot/*", "arn:aws:lightsail::<AWS ACCOUNT ID>:RelationalDatabase/*", "arn:aws:lightsail::<AWS ACCOUNT ID>:InstanceSnapshot/*", "arn:aws:lightsail::<AWS ACCOUNT ID>:Domain/*", "arn:aws:lightsail::<AWS ACCOUNT ID>:LoadBalancer/*", "arn:aws:lightsail::<AWS ACCOUNT ID>:KeyPair/*", "arn:aws:lightsail::<AWS ACCOUNT ID>:Disk/*" ] } ] }
Review Policy ->
Name: AllowLightsail
Description: Allow access to Lightsail.
Create Policy.
Groups -> container-admin -> Attach Policy -> Search for AllowLightsail -> Attach Policy.
Generate an SSH Key Pair (no password) and restrict permissions on it:
$ ssh-keygen -q -t rsa -b 2048 -N '' -f ~/.ssh/myweb && chmod 400 ~/.ssh/myweb
Import the public key to Lightsail:
$ aws lightsail import-key-pair --key-pair-name myweb --public-key-base64 file://~/.ssh/myweb.pub
Set the version to greater then or equal to 2.0, interpolate the region and use the AWS CLI credentials file:
$ cat << 'EOF' > provider.tf > provider "aws" { > version = ">= 2.0" > > region = "${var.region}" > shared_credentials_file = "~/.aws/credentials" > profile = "default" > } > EOF
Set the default region as a variable:
$ cat << 'EOF' > vars.tf > variable "region" { > default = "us-east-1" > } > EOF
Create a Lightsail DNS Zone of myweb.com, allocate a static IP for it, create a micro instance based off of Ubuntu 18_04, reference an extraneous file for user_data (run once script on Virtual Machine boot), tag it and attach the allocated Static IP to it:
$ cat << 'EOF' > lightsail.tf > resource "aws_lightsail_domain" "myweb" { > domain_name = "myweb.com" > } > > resource "aws_lightsail_static_ip" "myweb" { > name = "static-ip_myweb" > } > > resource "aws_lightsail_instance" "myweb" { > name = "site_myweb" > availability_zone = "${var.region}a" > blueprint_id = "ubuntu_18_04" > bundle_id = "micro_2_0" > key_pair_name = "myweb" > user_data = "${data.template_file.init_script.rendered}" > > tags = { > Site = "myweb.com" > } > } > > resource "aws_lightsail_static_ip_attachment" "myweb" { > static_ip_name = "${aws_lightsail_static_ip.myweb.name}" > instance_name = "${aws_lightsail_instance.myweb.name}" > } > EOF
Output our allocated and attached static IP after creation:
$ cat << 'EOF' > output.tf > output "static_public_ip" { > value = "${aws_lightsail_static_ip.myweb.ip_address}" > } > EOF
Create a template file to reference a run-once on boot user_data script:
$ cat << 'EOF' > install.tf > data "template_file" "init_script" { > template = "${file("scripts/install.sh")}" > } > EOF
Create the shell script for user_data:
$ cat << 'EOF' > scripts/install.sh > #!/bin/bash > > MY_HOME="/home/ubuntu" > export DEBIAN_FRONTEND=noninteractive > > # Install prereqs > apt update > apt install -y python3-pip apt-transport-https ca-certificates curl software-properties-common > # Install docker > curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - > add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" > apt update > apt install -y docker-ce > # Install docker-compose > su ubuntu -c "mkdir -p $MY_HOME/.local/bin" > su ubuntu -c "pip3 install docker-compose --upgrade --user && chmod 754 $MY_HOME/.local/bin/docker-compose" > usermod -aG docker ubuntu > # Add PATH > printf "\nexport PATH=\$PATH:$MY_HOME/.local/bin\n" >> $MY_HOME/.bashrc > > exit 0 > EOF
Initialize the directory:
$ terraform init
Run a dry-run to see what will occur:
$ terraform plan
Provision:
$ terraform apply -auto-approve
Log on to the instance (up to ~30 seconds may be needed for the attachment of the static IP to the instance):
$ ssh -i ~/.ssh/myweb ubuntu@<The value of static_public_ip that was reported. One can also use 'terraform output static_public_ip' to print it again.>
Type yes and hit enter to accept.
On the host (a short while is needed for the run-once script to complete):
$ docker --version $ docker-compose --version $ logout
Tear down what was created by first performing a dry-run to see what will occur:
$ terraform plan -destroy
Tear down the instance:
$ terraform destroy -auto-approve
<–
References:
Source:
terraform_aws_myweb (https://github NULL.com/pershoot/terraform_aws_myweb)