I'm new to ECS Fargate and Terraform; I've based most of the config below on tutorials/blogs.
What I'm seeing:
My app doesn't start because it can't connect to RDS (cloudwatch logs). This is OK since I've not yet configured RDS.
ECS / Fargate drains the task that failed and creates a new ones.
This behaviour is expected.
But; I expect the deployment to fail because it simply won't boot any of the ECS container successfully (the ALB health check never returns true).
The config I've setup is designed to fail for the following reasons:
The ALB health_check is configured to match 499 reponse status (which doesn't exist in my app, in fact my app doesn't even have a /health checkpoint!)
The app doesn't start at all and quits within 10 seconds after booting, not even starting any HTTP service listener
But; the deployment always succeeds despite no container every being alive :-(
What I'm seeing is (assuming the desired app count is 3):
After deployment the ECS task gets "3 Pending Tasks"
It will start with "1 Running Task" and "2 Pending Tasks", which fails and goes back to "3 Pending Tasks"
Frequently it shows "2 Running Tasks", but they will fail and go back to "Pending tasks"
After a while it will briefly list "3 Running Tasks"
The moment it shows "3 Running Tasks" the deployment succeeds.
When the ECS lists "3 Running Tasks" none of the ALB health checks ever succeeded; running means it starts the container but it doesn't mean the health check succeeded.
It seems ECS only considers the "Running" state for success and never the ALB health check; which goes counter to what I've been reading how this is supposed to work.
On top of that, it starts new tasks even before the one started previously is completely healthy (here too ignoring the ALB health check). I was expecting it to start 1 container at a time (based on the ALB health check).
There are loads of topics about failing ECS deployments due to failed ELB health checks; but I'm encountering the exact opposite and struggling to find an explanation.
Given I'm new to all this I'm assuming I've made a misconfiguration or have some misunderstanding of how it is supposed to work.
But after more than 12 hours I'm not seeing it...
Hope someone can help!
I've configured the following terraform:
locals {
name = "${lower(var.project)}-${var.env}"
service_name = "${local.name}-api"
port = 3000
}
resource "aws_lb" "api" {
name = "${local.service_name}-lb"
internal = false
load_balancer_type = "application"
tags = var.tags
subnets = var.public_subnets
security_groups = [
aws_security_group.http.id,
aws_security_group.https.id,
aws_security_group.egress-all.id,
]
}
resource "aws_lb_target_group" "api" {
name = local.service_name
port = 3000
protocol = "HTTP"
target_type = "ip"
vpc_id = var.vpc_id
tags = var.tags
health_check {
enabled = true
healthy_threshold = 3
interval = 30
path = "/"
port = "traffic-port"
protocol = "HTTP"
matcher = "499" # This is a silly reponse code, it never succeeds
unhealthy_threshold = 3
}
# NOTE: TF is unable to destroy a target group while a listener is attached,
# therefore create a new one before destroying the old. This also means
# we have to let it have a random name, and then tag it with the desired name.
lifecycle {
create_before_destroy = true
}
depends_on = [aws_lb.api]
}
resource "aws_lb_listener" "api-http" {
load_balancer_arn = aws_lb.api.arn
port = "80"
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.api.arn
}
}
# This is the role under which ECS will execute our task. This role becomes more important
# as we add integrations with other AWS services later on.
#
# The assume_role_policy field works with the following aws_iam_policy_document to allow
# ECS tasks to assume this role we're creating.
resource "aws_iam_role" "ecs-alb-role" {
name = "${local.name}-api-alb-role"
assume_role_policy = data.aws_iam_policy_document.ecs-task-assume-role.json
tags = var.tags
}
data "aws_iam_policy_document" "ecs-task-assume-role" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ecs-tasks.amazonaws.com"]
}
}
}
data "aws_iam_policy" "ecs-alb-role" {
arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}
# Attach the above policy to the execution role.
resource "aws_iam_role_policy_attachment" "ecs-alb-role" {
role = aws_iam_role.ecs-alb-role.name
policy_arn = data.aws_iam_policy.ecs-alb-role.arn
}
# Based on:
# https://section411.com/2019/07/hello-world/
resource "aws_ecs_cluster" "cluster" {
name = "${local.name}-cluster"
tags = var.tags
}
resource "aws_ecs_service" "ecs-api" {
name = local.service_name
task_definition = aws_ecs_task_definition.ecs-api.arn
cluster = aws_ecs_cluster.cluster.id
launch_type = "FARGATE"
desired_count = var.desired_count
tags = var.tags
network_configuration {
assign_public_ip = false
security_groups = [
aws_security_group.api-ingress.id,
aws_security_group.egress-all.id
]
subnets = var.private_subnets
}
load_balancer {
target_group_arn = aws_lb_target_group.api.arn
container_name = var.container_name
container_port = local.port
}
# not sure what this does, it doesn't fix the problem though regardless of true/false
deployment_circuit_breaker {
enable = true
rollback = true
}
}
resource "aws_cloudwatch_log_group" "ecs-api" {
name = "/ecs/${local.service_name}"
tags = var.tags
}
resource "aws_ecs_task_definition" "ecs-api" {
family = local.service_name
execution_role_arn = aws_iam_role.ecs-alb-role.arn
tags = var.tags
# These are the minimum values for Fargate containers.
cpu = 256
memory = 512
requires_compatibilities = ["FARGATE"]
network_mode = "awsvpc"
container_definitions = <<EOF
[
{
"name": "${var.container_name}",
"image": "${var.ecr_url}/${var.container_name}:latest",
"portMappings": [
{
"containerPort": ${local.port}
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-region": "${var.aws_region}",
"awslogs-group": "/ecs/${local.service_name}",
"awslogs-stream-prefix": "ecs"
}
}
}
]
EOF
}
resource "aws_security_group" "http" {
name = "http"
description = "HTTP traffic"
vpc_id = var.vpc_id
tags = var.tags
ingress {
from_port = 80
to_port = 80
protocol = "TCP"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "https" {
name = "https"
description = "HTTPS traffic"
vpc_id = var.vpc_id
tags = var.tags
ingress {
from_port = 443
to_port = 443
protocol = "TCP"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "egress-all" {
name = "egress_all"
description = "Allow all outbound traffic"
vpc_id = var.vpc_id
tags = var.tags
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "api-ingress" {
name = "api_ingress"
description = "Allow ingress to API"
vpc_id = var.vpc_id
tags = var.tags
ingress {
from_port = 3000
to_port = 3000
protocol = "TCP"
cidr_blocks = ["0.0.0.0/0"]
}
}
My github action deploy config:
# This is based on:
# - https://docs.github.com/en/actions/guides/deploying-to-amazon-elastic-container-service
# - https://particule.io/en/blog/cicd-ecr-ecs/
env:
AWS_REGION: eu-west-1
ECR_REPOSITORY: my-service-api
ECS_SERVICE: my-service-dev-api
ECS_CLUSTER: my-service-dev-cluster
TASK_DEFINITION: arn:aws:ecs:eu-west-1:123456789:task-definition/my-service-dev-api
name: Deploy
on:
push:
branches:
- main
jobs:
build:
name: Deploy
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
packages: write
contents: read
steps:
- name: Checkout
uses: actions/checkout#v2
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials#13d241b293754004c80624b5567555c4a39ffbe3
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login#aaf69d68aa3fb14c1d5a6be9ac61fe15b48453a2
- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
IMAGE_TAG: ${{ github.sha }}
run: |
# Build a docker container and push it to ECR so that it can be deployed to ECS.
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$GITHUB_RUN_NUMBER .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$GITHUB_RUN_NUMBER
# Tag docker container with git tag for debugging purposes
docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$GITHUB_RUN_NUMBER $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
# We tag with ":latest" for debugging purposes, but don't use it for deployment
docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$GITHUB_RUN_NUMBER $ECR_REGISTRY/$ECR_REPOSITORY:latest
docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest
echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$GITHUB_RUN_NUMBER"
- name: Download task definition
id: download-task
run: |
aws ecs describe-task-definition \
--task-definition ${{ env.TASK_DEFINITION }} \
--query taskDefinition > task-definition.json
echo ${{ env.TASK_DEFINITION }}
echo "::set-output name=revision::$(cat task-definition.json | jq .revision)"
- name: Fill in the new image ID in the Amazon ECS task definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition#v1
with:
task-definition: task-definition.json
container-name: ${{ env.ECR_REPOSITORY }}
image: ${{ steps.build-image.outputs.image }}
- name: Deploy Amazon ECS task definition
uses: aws-actions/amazon-ecs-deploy-task-definition#v1
with:
task-definition: ${{ steps.task-def.outputs.task-definition }}
service: ${{ env.ECS_SERVICE }}
cluster: ${{ env.ECS_CLUSTER }}
wait-for-service-stability: true
wait-for-minutes: 5
- name: De-register previous revision
run: |
aws ecs deregister-task-definition \
--task-definition ${{ env.TASK_DEFINITION }}:${{ steps.download-task.outputs.revision }}
(I've anonymized some identifiers)
These configs deploy successfully, the only problem is the github CI doesn't fail while ECS containers never pass the ALB health check.
It seems ECS only considers the "Running" state for success and never
the ALB health check; which goes counter to what I've been reading how
this is supposed to work.
There's no "success" state that I'm aware of in ECS. I think you are expecting some extra deployment success criteria that doesn't really exist. There is a concept of "services reached a steady state" that indicates the services stopped being created/terminated and the health checks are passing. That is something that can be checked via the AWS CLI tool, or via a Terraform ECS service deployment. However I don't see the same options in the GitHub actions you are using.
On top of that, it starts new tasks even before the one started
previously is completely healthy (here too ignoring the ALB health
check). I was expecting it to start 1 container at a time (based on
the ALB health check).
You aren't showing your service configuration for desired count, and minimim healthy percent, so it is impossible to know exactly what is happening here. It's probably some combination of those settings, plus ECS starting new tasks as soon as the ALB reports the previous tasks as unhealthy that is causing this behavior.
Any reason why you aren't using a Terraform GitHub Action to deploy the updated task definition and update the ECS service? I think one terraform apply GitHub Action would replace the last 4 actions in your GitHub pipeline, keep Terraform updated with your current infrastructure state, and allow you to use the wait_for_steady_state attribute to ensure the deployment is successful before the CI pipeline exits.
Alternatively you could try adding another GitHub action that calls the AWS CLI
to wait for the ECS steady state, or possibly for the ALB to have 0 unhealthy targets.
Related
I have an ec2 instance defined in terraform along with some security rules.
These are the security rules:
resource "aws_security_group" "ec2_web" {
name = "${var.project_name}_${var.env}_ec2_web"
description = "ec2 instances that serve to the load balancer"
vpc_id = aws_vpc.main.id
}
resource "aws_security_group_rule" "ec2_web_http" {
type = "egress"
from_port = 80
to_port = 80
protocol = "tcp"
# cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.ec2_web.id
source_security_group_id = aws_security_group.elb.id
}
resource "aws_security_group_rule" "ec2_web_ssh" {
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["${var.ip_address}/32"]
security_group_id = aws_security_group.ec2_web.id
}
I'm trying to simply add another security rule:
resource "aws_security_group_rule" "ec2_web_ssh_test" {
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["${var.ip_address}/32"]
security_group_id = aws_security_group.ec2_web.id
}
And terraform wants to completely replace the security group, and that cascades into completely replacing the ec2 instance.
I'm modifying the .tf file and then running:
terraform apply
EDIT:
The security group itself seems completely unrelated. When I do "plan", I get the output:
# aws_instance.ec2 must be replaced
-/+ resource "aws_instance" "ec2" {
...
~ security_groups = [ # forces replacement
+ "sg-0befd5d21eee052ad",
]
The ec2 instance is created with:
resource "aws_instance" "ec2" {
ami = "ami-0b5eea76982371e91"
instance_type = "t3.small"
key_name = "${var.project_name}"
depends_on = [aws_internet_gateway.main]
user_data = <<EOF
#!/bin/bash
sudo amazon-linux-extras install -y php8.1 mariadb10.5
sudo yum install -y httpd mariadb php8.1 php8.1-cli
sudo systemctl start httpd
sudo systemctl enable httpd
echo 'yup' | sudo tee /var/www/html/index.html
echo '<?php echo phpinfo();' | sudo tee /var/www/html/phpinfo.php
EOF
tags = {
Name = "${var.project_name}_${var.env}_ec2"
}
root_block_device {
volume_size = 8 # GB
volume_type = "gp3"
}
security_groups = [aws_security_group.ec2_web.id]
# vpc_security_group_ids = [aws_security_group.main.id]
subnet_id = aws_subnet.main1.id
}
If I comment out
# security_groups = [aws_security_group.bake.name]
I do not get any errors.
This happens because security_groups can only be used EC2-Classic (legacy instances) and a default VPC. For everything else you must use vpc_security_group_ids.
In your cause you are using custom VPC called main, thus you must be using vpc_security_group_ids, not security_groups.
Before apply please run terraform apply -refresh-only then your main problem is you can not define same rule with different terraform id.
When you apply new changes for ec2_web_ssh_test AWS will complain about
│Error: [WARN] A duplicate Security Group rule was found on (sg-xxxxxx). This may be
│ a side effect of a now-fixed Terraform issue causing two security groups with
│ identical attributes but different source_security_group_ids to overwrite each
│ other in the state
Then you will get this error from AWS api
Error: InvalidPermission.Duplicate: the specified rule "peer: xxx.xxx.xxx.xxx/32, TCP, from port: 22, to port: 22, ALLOW" already exists
With Terraform it compares the current state of your configuration with the new state which will contain the new rule you are adding. Here current state is not same as the desired state with new rule you are adding.
Hence with two different states, Terraform is trying to destroy the EC2 instances and trying to build new instances with newly added rules state.
This can be avoided with using terraform import command that will import the existing resources to your terraform state and then make changes to it.
For my high-traffic containerized app running in ECS Fargate, slow ramp-up is required for new containers, to avoid out of memory situation immediately after startup. This is especially important during the update service operation when all the containers are replaced at the same time.
How can I get this to work with ECS Fargate and ALB, making sure the old containers stay around until the slow_start period for the new containers is over?
This is my current terraform setup. I enabled slow_start, but during update service the old containers are stopped too early, so that the new containers get full traffic instantly.
resource "aws_alb_target_group" "my_target_group" {
name = "my_service"
port = 8080
protocol = "HTTP"
vpc_id = data.aws_vpc.active.id
target_type = "ip"
slow_start = 120
health_check {
enabled = true
port = 8080
path = "/healthCheck"
unhealthy_threshold = 2
healthy_threshold = 2
}
}
resource "aws_ecs_service" "my_service" {
name = "my_service"
cluster = aws_ecs_cluster.my_services.id
task_definition = aws_ecs_task_definition.my_services.arn
launch_type = "FARGATE"
desired_count = var.desired_count
deployment_maximum_percent = 400
deployment_minimum_healthy_percent = 100
enable_execute_command = true
wait_for_steady_state = true
network_configuration {
subnets = data.aws_subnets.private.ids
security_groups = [aws_security_group.my_service_container.id]
}
load_balancer {
container_name = "my-service"
container_port = 8080
target_group_arn = aws_alb_target_group.my_target_group.arn
}
lifecycle {
create_before_destroy = true
ignore_changes = [desired_count]
}
}
aws ecs usually sends sigterm to gracefully shutdown and sends sigkill if 30 second passed.
So, you can handle this sigterm signal (example to catch this signal in python) and add delay in your code. After that, you need to adjust sigkill 30 second wait with stopTimeout in ContainerDefinition to stop aws shutting down the ecs.
I am running an ECS cluster with about 20 containers. I have a big monolith application running on 1 container which requires to listen on 10 ports.
However AWS requires to have a max of 5 load balancer target group links in an ECS Service.
Any ideas how to overcome this (if possible)? Here's what I've tried:
Defining 10+ target groups with 1 listener each. Doesn't work since AWS requires a max of 5 load balancer definitions in the aws_ecs_service - for info - here: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-load-balancing.html as stated in the 2nd bullet under "Service load balancing considerations"
Defining 10+ listeners with 1 target group - however all listeners forward to a single port on the container...
Tried without specifying port in the load_balancer definition in aws_ecs_service, however AWS complains for missing argument
Tried without specifying port in the aws_lb_target_group, however AWS complains that target type is "ip", so port is required...
Here's my current code:
resource "aws_ecs_service" "service_app" {
name = "my_service_name"
cluster = var.ECS_CLUSTER_ID
task_definition = aws_ecs_task_definition.task_my_app.arn
desired_count = 1
force_new_deployment = true
...
load_balancer { # Note: I've stripped the for_each to simplify reading
target_group_arn = var.tga
container_name = var.n
container_port = var.p
}
}
resource "aws_lb_target_group" "tg_mytg" {
name = "Name"
protocol = "HTTP"
port = 3000
target_type = "ip"
vpc_id = aws_vpc.my_vpc.id
}
resource "aws_lb_listener" "ls_3303" {
load_balancer_arn = aws_lb.my_lb.id
port = "3303"
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.tg_mytg.arn
}
}
...
I am trying to provision an ECS cluster using Terraform along with an ALB. The targets come up as Unhealthy. The error code is 502 in the console Health checks failed with these codes: [502]
I checked through the AWS Troubleshooting guide and nothing helped there.
EDIT: I have no services/tasks running on the EC2 containers. Its a vanilla ECS cluster.
Here is my relevant code for the ALB:
# Target Group declaration
resource "aws_alb_target_group" "lb_target_group_somm" {
name = "${var.alb_name}-default"
port = 80
protocol = "HTTP"
vpc_id = "${var.vpc_id}"
deregistration_delay = "${var.deregistration_delay}"
health_check {
path = "/"
port = 80
protocol = "HTTP"
}
lifecycle {
create_before_destroy = true
}
tags = {
Environment = "${var.environment}"
}
depends_on = ["aws_alb.alb"]
}
# ALB Listener with default forward rule
resource "aws_alb_listener" "https_listener" {
load_balancer_arn = "${aws_alb.alb.id}"
port = "80"
protocol = "HTTP"
default_action {
target_group_arn = "${aws_alb_target_group.lb_target_group_somm.arn}"
type = "forward"
}
}
# The ALB has a security group with ingress rules on TCP port 80 and egress rules to anywhere.
# There is a security group rule for the EC2 instances that allows ingress traffic to the ECS cluster from the ALB:
resource "aws_security_group_rule" "alb_to_ecs" {
type = "ingress"
/*from_port = 32768 */
from_port = 80
to_port = 65535
protocol = "TCP"
source_security_group_id = "${module.alb.alb_security_group_id}"
security_group_id = "${module.ecs_cluster.ecs_instance_security_group_id}"
}
Has anyone hit this error and know how to debug/fix this ?
It looks like you're trying to be register the ECS cluster instances with the ALB target group. This isn't how you're meant to send traffic to an ECS service via an ALB.
Instead you should have your service join the tasks to the target group. This will mean that if you are using host networking then only the instances with the task deployed will be registered. If you are using bridge networking then it will add the ephemeral ports used by your task to your target group (including allowing for there to be multiple targets on a single instance). And if you are using awsvpc networking then it will register the ENIs of every task that the service spins up.
To do this you should use the load_balancer block in the aws_ecs_service resource. An example might look something like this:
resource "aws_ecs_service" "mongo" {
name = "mongodb"
cluster = "${aws_ecs_cluster.foo.id}"
task_definition = "${aws_ecs_task_definition.mongo.arn}"
desired_count = 3
iam_role = "${aws_iam_role.foo.arn}"
load_balancer {
target_group_arn = "${aws_lb_target_group.lb_target_group_somm.arn}"
container_name = "mongo"
container_port = 8080
}
}
If you were using bridge networking this would mean that the tasks are accessible on the ephemeral port range on the instances so your security group rule would need to look like this:
resource "aws_security_group_rule" "alb_to_ecs" {
type = "ingress"
from_port = 32768 # ephemeral port range for bridge networking tasks
to_port = 60999 # cat /proc/sys/net/ipv4/ip_local_port_range
protocol = "TCP"
source_security_group_id = "${module.alb.alb_security_group_id}"
security_group_id = "${module.ecs_cluster.ecs_instance_security_group_id}"
}
it looks like the http://ecsInstanceIp:80 is not returning HTTP 200 OK. I would check that first. It would be easy to check if the instance is public. It wont be the case most of the times. Otherwise I would create an EC2 instance and make a curl request to confirm that.
You may also check the container logs to see if its logging the health check response.
Hope this helps. good luck.
I'm following this terraform tutorial found at gruntwork.io. I can use $ terraform apply to spin up a virtual machine, which shows in the aws console with a public facing ip address and everything. Unfortunately the instance seems to be attached to a previously defined security group and doesn't seems to be responding to ssh or curl as l might expect.
I've modified the security group so that the proper ports are open, and modified the tutorials main.tf file in an attempt to add a user account that l can use to at least see what's running on the vm with.
The results of terraform apply can be seen here
When l try to ssh into the instance with the test user and the associated private key l get a response of permission denied (this also happens if l try logging in as the default user, ubuntu). What am l misunderstanding that the security groups aren't being defined properly and that the user isn't being added to the instance properly. The tutorial was written for terraform 0.7, and l'm running with 0.11.10, but l can't imagine that something so basic would change.
The modified main.tf file is as follows
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# DEPLOY A SINGLE EC2 INSTANCE
# This template uses runs a simple "Hello, World" web server on a single EC2 Instance
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ------------------------------------------------------------------------------
# CONFIGURE OUR AWS CONNECTION
# ------------------------------------------------------------------------------
provider "aws" {
region = "us-east-1"
}
# ---------------------------------------------------------------------------------------------------------------------
# DEPLOY A SINGLE EC2 INSTANCE
# ---------------------------------------------------------------------------------------------------------------------
resource "aws_instance" "example" {
# Ubuntu Server 14.04 LTS (HVM), SSD Volume Type in us-east-1
ami = "ami-2d39803a"
instance_type = "t2.micro"
vpc_security_group_ids = ["${aws_security_group.instance.id}"]
user_data = <<-EOF
#!/bin/bash
echo "Hello, World" > index.html
nohup busybox httpd -f -p "${var.server_port}" &
EOF
tags {
Name = "terraform-example"
}
}
# ---------------------------------------------------------------------------------------------------------------------
# CREATE THE SECURITY GROUP THAT'S APPLIED TO THE EC2 INSTANCE
# ---------------------------------------------------------------------------------------------------------------------
resource "aws_security_group" "instance" {
name = "terraform-example-instance"
# Inbound HTTP from anywhere
ingress {
from_port = "${var.server_port}"
to_port = "${var.server_port}"
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# Inbound SSH from anywhere
ingress {
from_port = "22"
to_port = "22"
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
variable "server_port" {
description = "The port the server will user for the HTTP requests"
default = 8080
}
# ---------------------------------------------------------------------------------------------------------------------
# Try to add a user to the spun up machine that we can ssh into the account of
# ---------------------------------------------------------------------------------------------------------------------
resource "aws_iam_user" "user" {
name = "test-user"
path = "/"
}
resource "aws_iam_user_ssh_key" "user" {
username = "${aws_iam_user.user.name}"
encoding = "SSH"
public_key = <public_key>
}
You did not specify any keypair name while creating ec2 instance.
For using ubuntu user for ssh you should specify keypair name