├── .editorconfig ├── .github └── workflows │ └── image.yml ├── .gitignore ├── .terraform.lock.hcl ├── Dockerfile ├── LICENSE ├── README.md ├── config.tf ├── ecs.tf ├── go.mod ├── go.sum ├── main.go └── network.tf /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | indent_size = 4 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.tf] 11 | indent_style = space 12 | indent_size = 2 13 | 14 | [*.yml] 15 | indent_size = 2 16 | indent_style = space 17 | -------------------------------------------------------------------------------- /.github/workflows/image.yml: -------------------------------------------------------------------------------- 1 | name: Release new version 2 | on: 3 | - push 4 | jobs: 5 | build_image: 6 | name: Build image 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v4 11 | - name: Build sun-api Docker image 12 | run: | 13 | docker build \ 14 | -t ghcr.io/jimmysawczuk/sun-api:latest . 15 | - name: Push sun-api Docker image 16 | env: 17 | GH_PAT: ${{ secrets.GH_PAT }} 18 | run: | 19 | echo $GH_PAT | docker login ghcr.io -u jimmysawczuk --password-stdin 20 | docker push ghcr.io/jimmysawczuk/sun-api:latest 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.terraform 2 | /vendor 3 | -------------------------------------------------------------------------------- /.terraform.lock.hcl: -------------------------------------------------------------------------------- 1 | # This file is maintained automatically by "terraform init". 2 | # Manual edits may be lost in future updates. 3 | 4 | provider "registry.terraform.io/hashicorp/aws" { 5 | version = "3.69.0" 6 | constraints = "~> 3.69.0" 7 | hashes = [ 8 | "h1:DFUb87/IK9l6anGAagwkDZ3x62p18JCljU8he5SfLrM=", 9 | "zh:0cedd84ba908ba7190052b16cd7f70c41b0e2c2e914e54eecf2e3dae193f47fa", 10 | "zh:14b89bac6412e20d415fe67d5f2eaa1414d9bbf75a5bd8fc963f6ab8e3b8b1a0", 11 | "zh:159131129edab7ea118dee7d6daf1bfe4615f200a2d5120deb8369cbd2c4b598", 12 | "zh:32a3a35964c9becb167180df905f34eb0cae7c30e00452527a0e600ee95c033f", 13 | "zh:5330374066ca27d9a00ca667c81183c1dbfa0fcfdd5c1797a6185b76bc7c13bc", 14 | "zh:78b75c45b7c660efaf89428ca988a77a4f55eba359f95ed7a54efe87fad1ab8b", 15 | "zh:81f723c3f33dc0761ed12b025c1f411fe22f2c6a97e22f4adeb10f7668a5df8f", 16 | "zh:98053adb091233fea8c1a82768dfce994e8407e2cb948d28ff88865d2d9a4dcd", 17 | "zh:a52866826b51c0b4cb6b970cb3328542846e108c8f4d24c090d7ca0ffa341e44", 18 | "zh:a9923cbdf30e9b66f889fef22e1f4b657d9ac1a48812f476ef841405a3c11525", 19 | "zh:c079f98be9b8456e6eae6c07c5dcb84ecbcbb70b2f361f1c6f9c3ba90366d905", 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.24 AS builder 2 | WORKDIR /app 3 | COPY main.go go.mod go.sum ./ 4 | RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -installsuffix cgo -o app . 5 | 6 | FROM alpine:latest 7 | LABEL org.opencontainers.image.source=https://github.com/jimmysawczuk/terraform-fargate-tutorial 8 | LABEL maintainer="me@jimmysawczuk.com" 9 | 10 | RUN apk update \ 11 | && apk add ca-certificates tzdata \ 12 | && update-ca-certificates \ 13 | && apk add shadow \ 14 | && groupadd -r app \ 15 | && useradd -r -g app -s /sbin/nologin -c "Docker image user" app 16 | 17 | USER app 18 | WORKDIR /app 19 | 20 | COPY --from=builder /app/app ./app 21 | EXPOSE 3000 22 | CMD ["./app"] 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2021 Jimmy Sawczuk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # terraform-fargate-tutorial 2 | 3 | This repository contains a working example of setting up a minimal Fargate ECS service on AWS using Terraform. It was last updated in September 2021 to use Terraform 1.0.5. 4 | 5 | See the post [at Section 411](https://section411.com/2019/07/hello-world/). 6 | 7 | ## Diagram 8 | 9 | ![sun-api](https://user-images.githubusercontent.com/590736/171856164-70c98307-c847-455e-ab28-2b5badf97d14.png) 10 | -------------------------------------------------------------------------------- /config.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | profile = "tfuser" 4 | } 5 | 6 | terraform { 7 | required_version = ">= 1.0" 8 | 9 | backend "s3" { 10 | bucket = "terraform" 11 | key = "terraform.tfstate" 12 | region = "us-east-1" 13 | profile = "tfuser" 14 | } 15 | 16 | required_providers { 17 | aws = { 18 | source = "hashicorp/aws" 19 | version = "~> 3.69.0" 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ecs.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | repository_url = "ghcr.io/jimmysawczuk/sun-api" 3 | } 4 | 5 | # We need a cluster in which to put our service. 6 | resource "aws_ecs_cluster" "app" { 7 | name = "app" 8 | } 9 | 10 | # An ECR repository is a private alternative to Docker Hub. 11 | resource "aws_ecr_repository" "sun_api" { 12 | name = "sun-api" 13 | } 14 | 15 | # Log groups hold logs from our app. 16 | resource "aws_cloudwatch_log_group" "sun_api" { 17 | name = "/ecs/sun-api" 18 | } 19 | 20 | # The main service. 21 | resource "aws_ecs_service" "sun_api" { 22 | name = "sun-api" 23 | task_definition = aws_ecs_task_definition.sun_api.arn 24 | cluster = aws_ecs_cluster.app.id 25 | launch_type = "FARGATE" 26 | 27 | desired_count = 1 28 | 29 | load_balancer { 30 | target_group_arn = aws_lb_target_group.sun_api.arn 31 | container_name = "sun-api" 32 | container_port = "3000" 33 | } 34 | 35 | network_configuration { 36 | assign_public_ip = false 37 | 38 | security_groups = [ 39 | aws_security_group.egress_all.id, 40 | aws_security_group.ingress_api.id, 41 | ] 42 | 43 | subnets = [ 44 | aws_subnet.private_d.id, 45 | aws_subnet.private_e.id, 46 | ] 47 | } 48 | } 49 | 50 | # The task definition for our app. 51 | resource "aws_ecs_task_definition" "sun_api" { 52 | family = "sun-api" 53 | 54 | container_definitions = <