Skip to content

Latest commit

 

History

49 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Python AWS ECS App

Template for a Python 3.14 app running on AWS ECS (Fargate). The app is packaged as a Docker image (ECR) and can run in one of these modes, selected by trigger_type:

  • ecs_eventbridge – Scheduled task: EventBridge cron runs the ECS task (with optional SQS DLQ).
  • ecs_api_service (legacy alias ecs_service) – Always-on service: ECS Service behind a public Application Load Balancer (optional HTTPS + Route53 when API_DOMAIN / API_ROOT_DOMAIN are set).
  • ecs_internal_api_service – Internal API: same as above, but the ALB is internal, placed in private subnets, and only reachable from inside the VPC (service-to-service calls from ECS, EC2, or VPC-attached Lambda).
  • ecs_background_service – Always-on worker: ECS Service with no ALB.

Technology stack

  • Python 3.14, Poetry
  • Docker
  • Terraform (bootstrap + main; state in S3)
  • GitHub Actions (test, deploy staging/prod, destroy via tags)

Local development

Prerequisites

  • Python 3.14 and Poetry
# macOS
brew install python@3.14 poetry
poetry config virtualenvs.in-project true

One-time setup

poetry env use python3.14
poetry install

Create .env in the project root with at least:

PYTHONPATH=app

Run app locally

Default (basic task):

poetry run python app/main.py

If using the FastAPI option (uncomment in app/main.py and Dockerfile):

poetry run uvicorn app.main:app --host 0.0.0.0 --port 8080 --reload

Run tests

poetry run pytest tests/unit

AWS deployment

Prerequisites

  • AWS account with OIDC role and S3 bucket for Terraform state (e.g. NRD-Tech Terraform Bootstrap).
  • VPC with separate public and private subnets (detected via map-public-ip-on-launch; resources fall back to all VPC subnets when one side is empty, e.g. the default VPC).
  • Docker running (for local deploys; image is built and pushed by Terraform).

Configure

Run python3 setup.py (recommended), or edit config.global by hand. At minimum set:

  • APP_IDENT_WITHOUT_ENV – Short app name (e.g. my-app).
  • TERRAFORM_STATE_BUCKET – S3 bucket for Terraform state.
  • AWS_DEFAULT_REGION – e.g. us-west-2.
  • AWS_ROLE_ARN – OIDC role ARN for the pipeline.
  • LAUNCH_TYPE – FARGATE or FARGATE_SPOT.
  • trigger_type – ecs_eventbridge (scheduled), ecs_api_service (public ALB + service), ecs_internal_api_service (internal ALB + service, VPC-only), or ecs_background_service (service, no ALB).
  • APP_CPU / APP_MEMORY – Task size (e.g. 256 / 512).
  • CPU_ARCHITECTURE – X86_64 or ARM64.
  • Optional: VPC_NAME – tag:Name of a custom VPC; leave unset for the default VPC.

In config.staging and config.prod set MIN_COUNT / MAX_COUNT (service task counts for auto-scaling) and API_DOMAIN / API_ROOT_DOMAIN when using a custom domain with an API trigger.

Trigger type is controlled only by trigger_type; no need to comment or uncomment Terraform files.

Deploy from your machine

  • Staging: ENVIRONMENT=staging ./deploy.sh
  • Production: ENVIRONMENT=prod ./deploy.sh
  • Destroy: ENVIRONMENT=staging ./deploy.sh -d or ENVIRONMENT=prod ./deploy.sh -d

Deploy via GitHub Actions

  • Staging: Push to main → workflow runs tests then deploys staging.
  • Production: Push a tag v* (e.g. git tag v1.0.0 && git push origin v1.0.0) → deploys production.
  • Destroy staging: Push tag destroy-staging-* (e.g. destroy-staging-1).
  • Destroy production: Push tag destroy-prod-* (e.g. destroy-prod-1).

In .github/workflows/github_flow.yml the workflow loads role-to-assume and aws-region from config.global (via the "Load configuration" step). Ensure those are set in config.global; no hardcoded role in the workflow file.


Run Docker image locally (ECS-style)

Build and run the same image that ECS uses (replace with your ECR URL and region):

aws ecr get-login-password --region us-west-2 | \
  docker login --username AWS --password-stdin <account>.dkr.ecr.us-west-2.amazonaws.com

docker run --rm -p 8080:8080 <account>.dkr.ecr.us-west-2.amazonaws.com/<app_ident>_repository:latest

For the default task image: container runs and exits. For FastAPI: curl http://localhost:8080/ping.

Inspect Docker image

docker inspect <account>.dkr.ecr.<region>.amazonaws.com/<app_ident>_repository:latest

Poetry cheat sheet

Action Command
Install dependencies poetry install
Run script poetry run python app/main.py
Run tests poetry run pytest tests/unit
Add dependency poetry add <package>
Add dev dependency poetry add --group dev <package>
Export requirements poetry export -f requirements.txt --output requirements.txt

Misc

Proprietary use

This project is under the MIT License. You may use it as a base for proprietary work; replace the LICENSE file and optionally add a NOTICE file as needed.

CodeArtifact (private Python packages)

One-time: add the CodeArtifact source to pyproject.toml (see Poetry docs).

Daily: obtain token and configure auth:

export CODEARTIFACT_TOKEN=$(aws codeartifact get-authorization-token --domain <domain> --domain-owner <account> --query authorizationToken --output text)
poetry config http-basic.<domain> aws $CODEARTIFACT_TOKEN

Uncomment the CodeArtifact block in config.global and the Dockerfile if the image build needs private packages.

Architecture

See architecture.md in the repo root for diagrams and a short architecture description.

About

No description or website provided.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages