Big Picture

To install terraform, refer to the respective documentation here

provider "aws" {
  region = "us-east-1"
}
terraform init
Initializing the backend...

Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v3.61.0...
- Installed hashicorp/aws v3.61.0 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
# Data Source for getting Amazon Linux AMI
data "aws_ami" "amazon-2" {
  most_recent = true

  filter {
    name = "name"
    values = ["amzn2-ami-hvm-*-x86_64-ebs"]
  }
  owners = ["amazon"]
}

# Resource for podtatohead-main
resource "aws_instance" "podtatohead-main" {
  ami = data.aws_ami.amazon-2.id
  instance_type = "t3.micro"

  tags = {
    Name = "podtatohead-main"
  }
}

# Resource for podtatohead-legs
resource "aws_instance" "podtatohead-legs" {
  ami = data.aws_ami.amazon-2.id
  instance_type = "t3.micro"

  tags = {
    Name = "podtatohead-legs"
  }
}

# Resource for podtatohead-arms
resource "aws_instance" "podtatohead-arms" {
  ami = data.aws_ami.amazon-2.id
  instance_type = "t3.micro"

  tags = {
    Name = "podtatohead-arms"
  }
}

# Resource for podtatohead-hats
resource "aws_instance" "podtatohead-hats" {
  ami = data.aws_ami.amazon-2.id
  instance_type = "t3.micro"

  tags = {
    Name = "podtatohead-hats"
  }
}
❯ terraform validate
Success! The configuration is valid.
Plan: 4 to add, 0 to change, 0 to destroy.

───────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't
guarantee to take exactly these actions if you run "terraform apply" now.
[...]

Plan: 4 to add, 0 to change, 0 to destroy.
aws_instance.podtatohead-main: Creating...
aws_instance.podtatohead-legs: Creating...
aws_instance.podtatohead-arms: Creating...
aws_instance.podtatohead-hats: Creating...
aws_instance.podtatohead-legs: Still creating... [10s elapsed]
aws_instance.podtatohead-main: Still creating... [10s elapsed]
aws_instance.podtatohead-arms: Still creating... [10s elapsed]
aws_instance.podtatohead-hats: Still creating... [10s elapsed]
aws_instance.podtatohead-main: Creation complete after 19s [id=i-0024742a855b87fe8]
aws_instance.podtatohead-arms: Creation complete after 19s [id=i-026ffc94cd3117a72]
aws_instance.podtatohead-hats: Creation complete after 19s [id=i-04183576772e51162]
aws_instance.podtatohead-legs: Creation complete after 19s [id=i-095392d47383309ba]

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

Inspect our environment

Set up the Cloud Init Templates

#!/bin/bash
sudo yum update -y
sudo amazon-linux-extras install docker -y
sudo service docker start
sudo usermod -a -G docker ec2-user
sudo docker run -p 8080:8080 -e PORT=8080 -e VERSION=${version} -d ${container_image}:${podtato_version}
#!/bin/bash
sudo yum update -y
sudo amazon-linux-extras install docker -y
sudo service docker start
sudo usermod -a -G docker ec2-user
sudo docker run -p 8080:8080 -e PORT=8080 -e LEFT_VERSION=${left_version} -e RIGHT_VERSION=${right_version} -d ${container_image}:${podtato_version}
#!/bin/bash
sudo yum update -y
sudo amazon-linux-extras install docker -y
sudo service docker start
sudo usermod -a -G docker ec2-user
sudo docker run -p 8080:8080 -e PORT=8080 -e HATS_HOST=${hats_host} -e HATS_PORT=8080 -e ARMS_HOST=${arms_host} -e ARMS_PORT=8080 -e LEGS_HOST=${legs_host} -e LEGS_PORT=8080 -d ${container_image}:${podtato_version}

Use the Cloud Init Templates

  user_data = templatefile("${path.module}/templates/init_main.tpl", { container_image = "ghcr.io/fhb-codelabs/podtato-small-main", hats_host = aws_instance.podtatohead-hats.private_ip, arms_host = aws_instance.podtatohead-arms.private_ip, legs_host = aws_instance.podtatohead-legs.private_ip, podtato_version=var.podtato_version } )
   user_data = templatefile("${path.module}/templates/init.tpl", { container_image = "ghcr.io/fhb-codelabs/podtato-small-legs", podtato_version=var.podtato_version, left_version=var.left_leg_version, right_version=var.right_leg_version} )
resource "aws_instance" "podtatohead-main" {
  ami = data.aws_ami.amazon-2.id
  instance_type = "t3.micro"

  user_data = templatefile("${path.module}/templates/init_main.tpl", { container_image = "ghcr.io/fhb-codelabs/podtato-small-main", hats_host = aws_instance.podtatohead-hats.private_ip, arms_host = aws_instance.podtatohead-arms.private_ip, legs_host = aws_instance.podtatohead-legs.private_ip, podtato_version=var.podtato_version } )

  tags = {
    Name = "podtatohead-main"
  }
}
  user_data = templatefile("${path.module}/templates/init.tpl", { container_image = "ghcr.io/fhb-codelabs/podtato-small-arms", podtato_version=var.podtato_version, left_version=var.left_arm_version, right_version=var.right_arm_version } )
  user_data = templatefile("${path.module}/templates/init_hats.tpl", { container_image = "ghcr.io/fhb-codelabs/podtato-small-hats", podtato_version=var.podtato_version, version=var.hats_version } )

Validate the configuration

Error: Reference to undeclared input variable
│
│   on main.tf line 30, in resource "aws_instance" "podtatohead-legs":
│   30:   user_data = templatefile("${path.module}/templates/init.tpl", { container_image = "ghcr.io/fhb-codelabs/podtato-small-legs", podtato_version=var.podtato_version, left_version=var.left_leg_version, right_version=var.right_leg_version} )
│
│ An input variable with the name "podtato_version" has not been declared. This
│ variable can be declared with a variable "podtato_version" {} block.

Defining Variables

variable "podtato_version" {
  type = string
}

variable "hats_version" {
  type = string
}

variable "left_arm_version" {
  type = string
}

variable "right_arm_version" {
  type = string
}

variable "right_leg_version" {
  type = string
}

variable "left_leg_version" {
  type = string
}

Assigning Variables

podtato_version="v0.1.0"
left_arm_version = "v1"
right_arm_version = "v2"
left_leg_version = "v3"
right_leg_version = "v3"
hats_version = "v4"

Plan and apply the configuration

[...] 
Plan: 4 to add, 0 to change, 4 to destroy.

───────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't
guarantee to take exactly these actions if you run "terraform apply" now.

Open a shell to your instances

Big Picture

resource "aws_security_group" "ingress-all-ssh" {
  name = "allow-all-ssh"
  ingress {
    cidr_blocks = [
      "0.0.0.0/0"
    ]
    from_port = 22
    to_port = 22
    protocol = "tcp"
  }
  // Terraform removes the default rule
  egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
resource "aws_security_group" "ingress-all-http" {
  name = "allow-all-http"
  ingress {
    cidr_blocks = [
      "0.0.0.0/0"
    ]
    from_port = 8080
    to_port = 8080
    protocol = "tcp"
  }
  // Terraform removes the default rule
  egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

Assign the Security Groups

 vpc_security_group_ids = [aws_security_group.ingress-all-ssh.id, aws_security_group.ingress-all-http.id]
resource "aws_instance" "podtatohead-main" {
  ami = data.aws_ami.amazon-2.id
  instance_type = "t3.micro"

  user_data = templatefile("${path.module}/templates/init_main.tpl", { container_image = "ghcr.io/fhb-codelabs/podtato-small-main", hats_host = aws_instance.podtatohead-hats.private_ip, arms_host = aws_instance.podtatohead-arms.private_ip, legs_host = aws_instance.podtatohead-legs.private_ip, podtato_version=var.podtato_version } )

  vpc_security_group_ids = [aws_security_group.ingress-all-ssh.id, aws_security_group.ingress-all-http.id]

  tags = {
    Name = "podtatohead-main"
  }

  lifecycle {
    create_before_destroy = true
  }
}

Apply the configuration

output "podtato-url" {
  value = "http://${aws_instance.podtatohead-main.public_ip}:8080"
}

Big Picture

Clean up