From fadfd2fe55f8fb9fd9752099f8dcf00e039ae0f2 Mon Sep 17 00:00:00 2001 From: IrezD Date: Thu, 28 Dec 2023 01:20:37 +0100 Subject: [PATCH] New: Initial deployment of resources --- .github/workflows/Production.yml | 98 ++++++++++++++++++++++++++++++++ .github/workflows/Release.yml | 23 ++++++++ .github/workflows/Staging.yml | 93 ++++++++++++++++++++++++++++++ .gitignore | 28 +++++++++ Dockerfile | 12 ++++ README.md | 3 +- main.py | 26 +++++++++ terraform/alb.tf | 26 +++++++++ terraform/ecr.tf | 10 ++++ terraform/ecs.tf | 67 ++++++++++++++++++++++ terraform/env/dev.tfbackend | 5 ++ terraform/env/dev.tfvars | 6 ++ terraform/env/prod.tfbackend | 5 ++ terraform/env/prod.tfvars | 6 ++ terraform/main.tf | 33 +++++++++++ terraform/networking.tf | 45 +++++++++++++++ terraform/outputs.tf | 8 +++ terraform/variables.tf | 41 +++++++++++++ 18 files changed, 534 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/Production.yml create mode 100644 .github/workflows/Release.yml create mode 100644 .github/workflows/Staging.yml create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 main.py create mode 100644 terraform/alb.tf create mode 100644 terraform/ecr.tf create mode 100644 terraform/ecs.tf create mode 100644 terraform/env/dev.tfbackend create mode 100644 terraform/env/dev.tfvars create mode 100644 terraform/env/prod.tfbackend create mode 100644 terraform/env/prod.tfvars create mode 100644 terraform/main.tf create mode 100644 terraform/networking.tf create mode 100644 terraform/outputs.tf create mode 100644 terraform/variables.tf diff --git a/.github/workflows/Production.yml b/.github/workflows/Production.yml new file mode 100644 index 0000000..8e8b324 --- /dev/null +++ b/.github/workflows/Production.yml @@ -0,0 +1,98 @@ +name: Production Deployment + +on: + release: + types: [ published] + + workflow_dispatch: + inputs: + version: + required: true + description: "What is the new version?" + type: string + +permissions: + pull-requests: write + contents: read + id-token: write + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + Tag: ${{ github.event.release.tag_name|| inputs.version }} + +jobs: + + Terraform: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: arn:aws:iam::806066816337:role/fastapi-image-IAM-role + role-session-name: fastapi-image-IAM-role + aws-region: eu-central-1 + + - name: Terraform plan + uses: dflook/terraform-plan@v1 + with: + path: ./terraform + label: Staging + backend_config_file: ./terraform/env/prod.tfbackend + var_file: ./terraform/env/prod.tfvars + variables: | + image_tag = "${{ env.Tag }}" + vpc_id = "${{ secrets.VPC_ID }}" + + - name: Terraform apply + uses: dflook/terraform-apply@v1 + with: + path: ./terraform + label: Staging + backend_config_file: ./terraform/env/prod.tfbackend + var_file: ./terraform/env/prod.tfvars + variables: | + image_tag = "${{ env.Tag }}" + vpc_id = "${{ secrets.VPC_ID }}" + auto_approve: true + + + Image-Build: + + needs: Terraform + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: arn:aws:iam::806066816337:role/fastapi-image-IAM-role + role-session-name: fastapi-image-IAM-role + aws-region: us-east-1 + + - name: Registry Alias Output + uses: dflook/terraform-output@v1 + id: my-outputs + with: + path: ./terraform + backend_config_file: ./terraform/env/prod.tfbackend + + - name: Login to Amazon ECR Public + id: login-ecr-public + uses: aws-actions/amazon-ecr-login@v2 + with: + registry-type: public + + - name: Build, tag, and push docker image to Amazon ECR Public + env: + REGISTRY: ${{ steps.login-ecr-public.outputs.registry }} + REGISTRY_ALIAS: ${{ steps.my-outputs.outputs.ecr_registry_id }} + REPOSITORY: ${{ steps.my-outputs.outputs.ecr_repository_name }} + IMAGE_TAG: ${{ env.Tag }} + run: | + docker build -t $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:$IMAGE_TAG . + docker push $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:$IMAGE_TAG diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml new file mode 100644 index 0000000..a9931c3 --- /dev/null +++ b/.github/workflows/Release.yml @@ -0,0 +1,23 @@ +name: New Release + +on: + push: + branches: + - main + +jobs: + Release: + runs-on: ubuntu-latest + permissions: + pull-requests: write + contents: write + issues: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Creating Release + uses: chiemerieezechukwu/semantic-release@main + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/Staging.yml b/.github/workflows/Staging.yml new file mode 100644 index 0000000..da45b12 --- /dev/null +++ b/.github/workflows/Staging.yml @@ -0,0 +1,93 @@ +name: Staging Image Build & Push + +on: + pull_request: + branches: [ "main" ] + +permissions: + pull-requests: write + contents: read + id-token: write + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +jobs: + + + Terraform: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: arn:aws:iam::806066816337:role/fastapi-image-IAM-role + role-session-name: fastapi-image-IAM-role + aws-region: eu-central-1 + + - name: Terraform plan + uses: dflook/terraform-plan@v1 + with: + path: ./terraform + label: Staging + backend_config_file: ./terraform/env/dev.tfbackend + var_file: ./terraform/env/dev.tfvars + variables: | + vpc_id = "${{ secrets.VPC_ID }}" + + - name: Terraform apply + uses: dflook/terraform-apply@v1 + with: + path: ./terraform + label: Staging + backend_config_file: ./terraform/env/dev.tfbackend + var_file: ./terraform/env/dev.tfvars + variables: | + vpc_id = "${{ secrets.VPC_ID }}" + auto_approve: true + + + + Build_Image: + + needs: Terraform + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: arn:aws:iam::806066816337:role/fastapi-image-IAM-role + role-session-name: fastapi-image-IAM-role + aws-region: us-east-1 + + - name: Registry Alias Output + uses: dflook/terraform-output@v1 + id: my-outputs + with: + path: ./terraform + backend_config_file: ./terraform/env/dev.tfbackend + + - name: Login to Amazon ECR Public + id: login-ecr-public + uses: aws-actions/amazon-ecr-login@v2 + with: + registry-type: public + + - name: Build, tag, and push docker image to Amazon ECR Public + env: + REGISTRY: ${{ steps.login-ecr-public.outputs.registry }} + REGISTRY_ALIAS: ${{ steps.my-outputs.outputs.ecr_registry_id }} + REPOSITORY: ${{ steps.my-outputs.outputs.ecr_repository_name }} + IMAGE_TAG: ${{ github.sha }} + run: | + docker build -t $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:$IMAGE_TAG . + docker build -t $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:latest . + + docker push $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:$IMAGE_TAG + docker push $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:latest diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..631dae7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log +crash.*.log + + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Include override files you do wish to add to version control using negated pattern +# !example_override.tf + +# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan +# example: *tfplan* + +# Ignore CLI configuration files +.terraformrc +terraform.rc diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..94cb280 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM python:3.9 + +WORKDIR /app/ + +COPY main.py /app/ + +EXPOSE 5000 + +RUN pip install fastapi && \ + pip install "uvicorn[standard]" + +CMD [ "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "5000" ] \ No newline at end of file diff --git a/README.md b/README.md index e15d5df..1d56b9e 100644 --- a/README.md +++ b/README.md @@ -1 +1,2 @@ -# python-fastAPI-docker-image-v2 \ No newline at end of file +# python-fastAPI-docker-image-v2 +Containerizing a simple FastAPI diff --git a/main.py b/main.py new file mode 100644 index 0000000..9ec8485 --- /dev/null +++ b/main.py @@ -0,0 +1,26 @@ +from typing import Union + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + price: float + is_offer: Union[bool, None] = None + +@app.get("/") +def read_root(): + return {"Hello World": "Merry Christmas to everyone and a happy new year!!!"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Union[str, None] = None): + return {"item_id": item_id, "q": q} + + +@app.put("/items/{item_id}") +def update_item(item_id: int, item: Item): + return {"item_name": item.name, "item_id": item_id} \ No newline at end of file diff --git a/terraform/alb.tf b/terraform/alb.tf new file mode 100644 index 0000000..18300ee --- /dev/null +++ b/terraform/alb.tf @@ -0,0 +1,26 @@ +resource "aws_lb" "alb" { + name = "fastapi-lb-${var.env}" + internal = false + load_balancer_type = "application" + security_groups = [aws_security_group.internet_to_ALB] + subnets = var.subnets_for_ecs +} + +resource "aws_lb_listener" "front_end" { + load_balancer_arn = aws_lb.alb.arn + port = "80" + protocol = "HTTP" + + default_action { + type = "forward" + target_group_arn = aws_lb_target_group.target_group_P-5000.arn + } +} + +resource "aws_lb_target_group" "target_group_P-5000" { + name = "alb-target-group" + port = 5000 + protocol = "HTTP" + target_type = "ip" + vpc_id = var.vpc_id +} \ No newline at end of file diff --git a/terraform/ecr.tf b/terraform/ecr.tf new file mode 100644 index 0000000..dbf4837 --- /dev/null +++ b/terraform/ecr.tf @@ -0,0 +1,10 @@ +resource "aws_ecrpublic_repository" "fastapi-ecr-public" { + provider = aws.ecr_region + + repository_name = var.repo_name + + catalog_data { + about_text = "A FastAPI docker image" + description = "This is a containerized images of FastAPI stored on ECR ${var.env} environment" + } +} \ No newline at end of file diff --git a/terraform/ecs.tf b/terraform/ecs.tf new file mode 100644 index 0000000..48acae0 --- /dev/null +++ b/terraform/ecs.tf @@ -0,0 +1,67 @@ +# ------ ECS Cluster ------- * + +resource "aws_ecs_cluster" "fastapi-cluster" { + name = "fastapi-cluster" + + setting { + name = "containerInsights" + value = "enabled" + } +} + +# ------ Task definition ------- * + +resource "aws_ecs_task_definition" "task_definition" { + family = "${var.env}-fastapi-container" + requires_compatibilities = ["FARGATE"] + network_mode = "awsvpc" + cpu = 1024 + memory = 2048 + container_definitions = <