This repository includes Docker configuration for both local development and production deployment to AWS ECS, acontainer-based infrastructure system.
- Docker installed
- Docker Compose installed (usually included with Docker Desktop)
Run the development environment with live file watching:
deno task docker-devAccess the site at http://localhost:8000
The development container:
- Mounts your source code for live editing
- Rebuilds the site when started
- Serves the static site on port 8000
- Persists Deno cache for faster rebuilds
Test the production build locally:
deno task docker-prodAccess the site at http://localhost:8080
# Build development image (from project root)
docker build -f docker/Dockerfile --target development -t murty-site:dev .
# Build production image (from project root)
docker build -f docker/Dockerfile --target production -t murty-site:prod .# Run development container
docker run -p 8000:8000 -v $(pwd):/app murty-site:dev
# Run production container
docker run -p 8000:8000 murty-site:prod# Run tests
docker compose -f docker/docker-compose.yaml run dev deno task test
# Lint code
docker compose -f docker/docker-compose.yaml run dev deno task lint
# Build site manually
docker compose -f docker/docker-compose.yaml run dev deno task build
# Access shell
docker compose -f docker/docker-compose.yaml run dev shFor auto-scaling configuration, see infra/aws-ecs/README.md.
# Build production image (from project root)
docker build -f docker/Dockerfile --target production -t murty-site:latest .
# Tag for ECR (replace with your AWS account ID and region)
docker tag murty-site:latest <aws-account-id>.dkr.ecr.<region>.amazonaws.com/murty-site:latest# Login to ECR
aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin <aws-account-id>.dkr.ecr.<region>.amazonaws.com
# Create ECR repository (first time only)
aws ecr create-repository --repository-name murty-site --region <region>
# Push image
docker push <aws-account-id>.dkr.ecr.<region>.amazonaws.com/murty-site:latestCreate a copy of the sample ECS Task Definitions file:
cp --update=none "infra/aws-ecs/ecs-task-definition.example.json" "infra/aws-ecs/ecs-task-definition.json"Fill out your AWS credentials in the new Git Ignored file at infra/aws-ecs/ecs-task-definition.json
aws ecs register-task-definition --cli-input-json file://infra/aws-ecs/ecs-task-definition.json# Create service (first time)
aws ecs create-service \
--cluster <your-cluster-name> \
--service-name murty-site \
--task-definition murty-site \
--desired-count 1 \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={subnets=[<subnet-id>],securityGroups=[<security-group-id>],assignPublicIp=ENABLED}"
# Update service (for deployments)
aws ecs update-service \
--cluster <your-cluster-name> \
--service murty-site \
--force-new-deploymentThe container uses the environment variables from .env file. In production:
- Copy
config/.env.exampleto.envand update values - For ECS, use task definition environment variables or AWS Secrets Manager
Example for ECS task definition:
"environment": [
{
"name": "GOOGLE_ANALYTICS_SITE_CODE",
"value": "G-XXXXXXXXXX"
}
]name: Build and Deploy to ECS
on:
push:
tags:
- '[0-9]*'
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Build and push image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY: murty-site
IMAGE_TAG: ${{ github.sha }}
run: |
docker build --target production -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
- name: Deploy to ECS
run: |
aws ecs update-service --cluster <cluster> --service murty-site --force-new-deployment