Anthony Law
Posted on June 1, 2019
Learning journey #RoadToDevOps
Last week I pick Terraform as my study and learning topic.
Terraform are very useful and powerful tools for DevOps development, it allows you writing a plan (Infrastructure as Code) and manage your cloud service.
which mean you can write a cloud infrastructure in coding, such as define how many instanse services, what port number you should active in the firewall. It's interesting to handling so many servers just a few lines of code.
Introduction
By using Terrafrom to deploy a virtual machine (ubuntu OS) in AWS EC2.
Objectives
In this article, you should able:
- Setup AWS account
- Use Basic Terraform-CLI command
- Writing Terraform Language (HCL)
- Deploy Virtual machine (EC2) in AWS cloud.
AWS Setup
If you are new in AWS please sign up here enjoy AWS Free Tier
We need User's Access Key ID
and Secret Key ID
from AWS User, and grant promission to User
with AmazonEC2FullAccess
.
if you dont know how to create user -> watch this
Terraform
Ensure your machine are Install Terraform.
We know if you writing in javascript
programming, you will name the file extension as *.js
. In Terraform the will define the extension as *.tf
and using JSON format or HCL (HashiCorp Configuration Language).
You may feel strange what is HCL (HashiCorp Configuration Language). No worry, It's not complicated and easy to learn and understand. HCL Docs
Once you have done your *.tf
script, you have to use Terrform-CLI to execute tf
files.
Hands-on
We will use keywords from HCL
.
keywords | description | example |
---|---|---|
provider | define cloud service provider | aws, google |
resource | define the resource we will use | aws_instance, google_compute_instance |
variable | define variable | - |
output | print output after executed | - |
We will use keywords from Terraform CLI
.
keywords | description |
---|---|
init | To init terraform project in the folder |
plan | To evaluate current your infrastructure from *.tf
|
apply | To add all define resources. |
show | To list resource infomation and current state |
destroy | To remove all defined resources. |
start
Create a folder in your machine.
create a files
my-first-vm.tf
.Open the files in the editor and start code.
# my-first-vm.tf
# We are pointing "aws" as our provider.
provider "aws" {
region = "ap-southeast-1"
access_key = "<access-key-from-aws-user>"
secret_key = "<secret-key-from-aws-user>"
}
command:
$ terraform init
Initializing provider plugins...
The following providers do not have any version constraints in configuration,
so the latest version was installed.
* provider.aws: version = "~> 2.12"
Terraform has been successfully initialized!
append resource "aws_instance" in my-first-vm.tf
provider "aws" {...}
resource "aws_instance" "ec2" { # I called name "ec2", you can change it
ami = "ami-0dad20bd1b9c8c004" # Image: Ubuntu Server 18.04 LTS (HVM), SSD Volume Type
instance_type = "t2.micro" # VM Spec
}
command:
$ terraform plan
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
+ aws_instance.ec2
id: <computed>
ami: "0dad20bd1b9c8c004"
arn: <computed>
associate_public_ip_address: <computed>
availability_zone: <computed>
cpu_core_count: <computed>
cpu_threads_per_core: <computed>
ebs_block_device.#: <computed>
ephemeral_block_device.#: <computed>
get_password_data: "false"
host_id: <computed>
instance_state: <computed>
instance_type: "t2.micro"
ipv6_address_count: <computed>
ipv6_addresses.#: <computed>
key_name: <computed>
network_interface.#: <computed>
network_interface_id: <computed>
password_data: <computed>
placement_group: <computed>
primary_network_interface_id: <computed>
private_dns: <computed>
private_ip: <computed>
public_dns: <computed>
public_ip: <computed>
root_block_device.#: <computed>
security_groups.#: <computed>
source_dest_check: "true"
subnet_id: <computed>
tenancy: <computed>
volume_tags.%: <computed>
vpc_security_group_ids.#: <computed>
Plan: 1 to add, 0 to change, 0 to destroy.
it showing infrastructure going to execute, you will see computed
it's because the terraform will help you assign the value, if you are not defined.
In additional, you see Plan: 1 to add, 0 to change, 0 to destroy.
it mean 1 resource will be executed.
So in this stage, actually you already completed setup an instance.
command:
$ terraform apply
Terraform will perform the following actions:
+ aws_instance.ec2
...
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
...
aws_instance.ec2: Still creating... (10s elapsed)
aws_instance.ec2: Still creating... (20s elapsed)
aws_instance.ec2: Creation complete after 22s (ID: i-083d6c6c7b01d1640)
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Congratulations, you are successful setup an instance EC2 in AWS, you may login and check it out in AWS dashboard.
Try on this command to get resource infomation.
$ terraform show
aws_instance.ec2:
id = i-083d6c6c7b01d1640
ami = ami-0dad20bd1b9c8c004
arn = arn:aws:ec2:ap-southeast-1:907443295242:instance/i-083d6c6c7b01d1640
associate_public_ip_address = true
...
...
!!!!
But wait, how you able to access without setup ssh
in the firewall.
let append resource "aws_security_group" in my-first-vm.tf
provider "aws" {...}
resource "aws_instance" "ec2" {...}
# Setup aws_security_group with SSH access
resource "aws_security_group" "allow_ssh" {
name = "allow ssh"
description = "only ssh"
ingress {
from_port = 22
to_port = 22
protocol = "TCP"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
Now we have let our "ec2" instance to apply "aws_security_group" we define, and also assign keypair for the instance.
so we can use the keypair
to access instance with port ssh 22
.
if you dont know how to create keypair in AWS, watch this
provider "aws" {...}
resource "aws_instance" "ec2" { # I called name "ec2", you can change it
ami = "ami-0dad20bd1b9c8c004" # Image: Ubuntu Server 18.04 LTS (HVM), SSD Volume Type
instance_type = "t2.micro" # VM Spec
security_groups = ["${aws_security_group.allow_ssh.name}"]
key_name = "aws-anthony"
}
# Setup aws_security_group with SSH access
resource "aws_security_group" "allow_ssh" {...}
command:
$ terraform apply
aws_instance.ec2: Refreshing state... (ID: i-083d6c6c7b01d1640)
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
-/+ destroy and then create replacement
Terraform will perform the following actions:
-/+ aws_instance.ec2 (new resource required)
...
...
+ aws_security_group.allow_ssh
...
...
Plan: 2 to add, 0 to change, 1 to destroy.
...
...
...
aws_instance.ec2: Still creating... (10s elapsed)
aws_instance.ec2: Still creating... (20s elapsed)
aws_instance.ec2: Creation complete after 32s (ID: i-079e9b8c1d98e4af5)
Apply complete! Resources: 2 added, 0 changed, 1 destroyed.
You may see it's different from just now, because terraform will keep track all resource status in *.tfstate
.
So it shows that, it will destroy
the previous instance and recreate again.
great, you now can check it out in your AWS dashboard.
finally, you successfully create an instance in Ubuntu OS. It's trouble to login AWS dashboard and checking what is the instance public ip address.
you may use output
keywords to display the public IP address.
provider "aws" {...}
resource "aws_instance" "ec2" {...}
resource "aws_security_group" "allow_ssh" {...}
output "showPublicIP" {
value = "${aws_instance.ec2.*.public_dns}"
}
$ terraform apply
aws_security_group.allow_ssh: Refreshing state... (ID: sg-0ca7e9133a701f216)
aws_instance.ec2: Refreshing state... (ID: i-079e9b8c1d98e4af5)
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
showPublicIP = [
ec2-3-0-184-126.ap-southeast-1.compute.amazonaws.com
]
ssh -i aws-anthony.pem ubuntu@ec2-3-0-184-126.ap-southeast-1.compute.amazonaws.com
Summary
Terraform always execute the *tf
in folder, each infrastructure should create a folder, such as aws-instance
or google-instance
.
if you feel put everything in 1 .tf
file is to mess, you may seperate in different .tf
such as aws_provider.tf , aws_security.tf
Posted on June 1, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.