zkt26/sk1/README.md

236 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Notes App — AWS Cloud Deployment
## What the application does
A **Notes** web application where users can create, view, and delete short text notes via a web browser. Notes are stored persistently in a PostgreSQL database. The app is publicly accessible over HTTPS at the configured domain.
---
## Cloud services and architecture
**Cloud provider:** Amazon Web Services (AWS), region `eu-central-1` (Frankfurt)
| Service | Purpose |
|---|---|
| **Amazon ECS Fargate** | Runs the frontend and backend containers serverlessly. Automatically restarts containers on failure. |
| **Amazon RDS (PostgreSQL 16)** | Managed relational database. Provides persistent storage, automated backups (7-day retention). |
| **Application Load Balancer (ALB)** | Receives all internet traffic. Routes `/api/*` to the backend, everything else to the frontend. Redirects HTTP → HTTPS. |
| **AWS Certificate Manager (ACM)** | Issues and renews a free TLS/HTTPS certificate for the domain. |
| **Amazon ECR** | Private Docker image registry. Stores the backend and frontend images. |
| **AWS Secrets Manager** | Stores the database password securely. Never stored in code or Git. |
| **Amazon CloudWatch Logs** | Collects access logs and application logs from both containers. |
| **Amazon VPC + Security Groups** | Network isolation. ALB SG allows 80/443 from internet. ECS SG allows traffic only from ALB. RDS SG allows 5432 only from ECS. |
### Architecture
```
Browser (HTTPS)
Application Load Balancer (port 443, ACM certificate, HTTP→HTTPS redirect)
├── /api/* ──▶ ECS Fargate: Backend (Flask, port 5000)
│ │
│ ▼
│ RDS PostgreSQL (port 5432, private subnet)
└── /* ──▶ ECS Fargate: Frontend (Nginx, port 80)
```
The browser loads the static frontend from the ALB. All API calls (`/api/*`) are made by the browser directly to the ALB, which forwards them to the backend. The frontend container serves only static files — it does not proxy to the backend. The backend connects to RDS using the `DATABASE_URL` environment variable.
---
## Cost analysis — 1,000 users/day, 50 GB database
Estimated for **eu-central-1 (Frankfurt)**, 1 year of operation.
| Resource | Specification | Unit price | Monthly | Annual |
|---|---|---|---|---|
| ECS Fargate — Backend | 0.25 vCPU, 0.5 GB RAM, 730 h/mo | $0.04048/vCPU-h + $0.004445/GB-h | ~$8.30 | ~$99.60 |
| ECS Fargate — Frontend | 0.25 vCPU, 0.5 GB RAM, 730 h/mo | same | ~$8.30 | ~$99.60 |
| RDS db.t3.micro | PostgreSQL, 1 vCPU, 1 GB RAM, 730 h/mo | ~$0.022/h | ~$16.10 | ~$193.20 |
| RDS Storage | 50 GB gp2 | $0.138/GB-mo | ~$6.90 | ~$82.80 |
| RDS Automated Backups | 50 GB (free up to DB size) | $0.00 | $0.00 | $0.00 |
| ALB | 1 ALB + ~1,000 req/day (~30k/mo) | $0.0252/h + LCU | ~$18.50 | ~$222.00 |
| ECR | ~500 MB images stored | $0.10/GB-mo | ~$0.05 | ~$0.60 |
| CloudWatch Logs | ~5 GB/mo ingestion | $0.57/GB | ~$2.85 | ~$34.20 |
| Data Transfer Out | ~10 GB/mo (1,000 users × ~330 KB) | $0.09/GB | ~$0.90 | ~$10.80 |
| Secrets Manager | 1 secret | $0.40/secret/mo | $0.40 | $4.80 |
| **Total** | | | **~$62.30** | **~$747.60** |
> Prices are estimates based on AWS public pricing (2025). Actual costs depend on traffic patterns. Use the [AWS Pricing Calculator](https://calculator.aws) for exact quotes.
---
## Files and their content
```
sk1/
├── prepare-app.sh # Creates all AWS resources and deploys the app
├── remove-app.sh # Tears down all AWS resources
├── backup.sh # Creates a manual RDS snapshot
├── .env.example # Template for required environment variables
├── .gitignore # Excludes .env from Git
├── backend/
│ ├── app.py # Flask REST API: GET/POST/DELETE /api/notes, /health
│ ├── requirements.txt # Python dependencies: flask, psycopg2-binary
│ └── Dockerfile # python:3.12-slim, runs app.py on port 5000
├── frontend/
│ ├── index.html # Single-page app: dark UI, fetch() calls to /api/
│ ├── nginx.conf # Nginx: serves index.html for all paths
│ └── Dockerfile # nginx:1.27-alpine, serves static files
└── db/
└── init.sql # Creates notes table, inserts sample rows
```
---
## Configuration description
All secrets and environment-specific values are passed via environment variables, never hardcoded in source files:
- **`DATABASE_URL`** — injected into the backend ECS task definition at deploy time. Constructed from `DB_USERNAME`, `DB_PASSWORD`, `DB_HOST`, `DB_NAME`.
- **`DB_PASSWORD`** — stored in AWS Secrets Manager under `notes-app/db-password`. Set via `.env` before running the script.
- **`DOMAIN_NAME`** — the public domain for the app (e.g. `notes.example.com`). Used to request the ACM certificate and configure the ALB.
- **`AWS_REGION`** / **`AWS_ACCOUNT_ID`** — target AWS account and region.
The `.env` file is listed in `.gitignore` and must never be committed to Git.
---
## How to run and use the application
### Prerequisites
- AWS CLI installed and configured (`aws configure`) with permissions for: ECS, ECR, RDS, ELB, ACM, IAM, EC2, Secrets Manager, CloudWatch Logs
- Docker installed and running
- A domain name you control (to add DNS CNAME records)
### Deploy
```bash
cd sk1
cp .env.example .env
# Edit .env — fill in AWS_REGION, AWS_ACCOUNT_ID, DOMAIN_NAME, DB_PASSWORD
source .env
chmod +x prepare-app.sh remove-app.sh
./prepare-app.sh
```
During deployment the script will print two DNS records to add:
1. A CNAME for ACM certificate validation
2. A CNAME pointing your domain to the ALB
Once DNS propagates and the certificate is validated, open **https://your-domain.com** in a browser.
### Use the app
- Type a note in the text box and click **+ Add Note**
- Notes appear below, newest first
- Click **✕ Delete** to remove a note
### Remove everything
```bash
source .env
./remove-app.sh
```
> The ACM certificate is not deleted automatically. Delete it manually if no longer needed:
> `aws acm delete-certificate --certificate-arn <ARN> --region $AWS_REGION`
---
## How to perform a data backup
RDS automated backups are enabled with a **7-day retention period** and run automatically every day.
**Manual snapshot using the provided script:**
```bash
source .env
./backup.sh
```
This creates a timestamped RDS snapshot (e.g. `notes-app-manual-20260520-120000`) and waits for it to complete.
**Restore from snapshot:**
```bash
aws rds restore-db-instance-from-db-snapshot \
--db-instance-identifier notes-app-db-restored \
--db-snapshot-identifier <snapshot-id> \
--region $AWS_REGION
```
**Export data as SQL dump** (requires `psql` and RDS publicly accessible or VPN):
```bash
PGPASSWORD=$DB_PASSWORD pg_dump \
-h <RDS_ENDPOINT> -U $DB_USERNAME -d $DB_NAME \
> backup_$(date +%Y%m%d).sql
```
---
## How to view access logs from the internet
Container logs (including Nginx access logs) are streamed to **Amazon CloudWatch Logs**.
**Live tail — frontend (Nginx access log):**
```bash
aws logs tail /ecs/notes-app/frontend --follow --region $AWS_REGION
```
**Live tail — backend:**
```bash
aws logs tail /ecs/notes-app/backend --follow --region $AWS_REGION
```
**Query last 100 log events:**
```bash
aws logs get-log-events \
--log-group-name /ecs/notes-app/frontend \
--log-stream-name $(aws logs describe-log-streams \
--log-group-name /ecs/notes-app/frontend \
--order-by LastEventTime --descending \
--query "logStreams[0].logStreamName" --output text --region $AWS_REGION) \
--limit 100 \
--region $AWS_REGION
```
---
## Conditions for running prepare-app.sh and remove-app.sh
**prepare-app.sh:**
- AWS CLI must be installed and configured with credentials that have permissions for: ECS, ECR, RDS, ELB, ACM, IAM, EC2, Secrets Manager, CloudWatch Logs
- Docker must be running locally
- `.env` must exist with all required variables set (`AWS_REGION`, `AWS_ACCOUNT_ID`, `DOMAIN_NAME`, `DB_PASSWORD`)
- The domain in `DOMAIN_NAME` must be one you can add DNS CNAME records to
- Run from the `sk1/` directory: `source .env && ./prepare-app.sh`
- The script is idempotent — safe to run multiple times
**remove-app.sh:**
- Same AWS CLI and `.env` requirements as above
- All deletions are idempotent — safe to run multiple times
- Run from the `sk1/` directory: `source .env && ./remove-app.sh`
**backup.sh:**
- Same AWS CLI and `.env` requirements as above (`AWS_REGION` is sufficient)
- RDS instance `notes-app-db` must be running
- Run from the `sk1/` directory: `source .env && ./backup.sh`
---
## Use of artificial intelligence
This project was developed with the assistance of **Kiro AI** (`kiro-cli chat` agent, Claude Sonnet model).
| What | How AI was used |
|---|---|
| `prepare-app.sh`, `remove-app.sh`, `backup.sh` | Generated by AI, reviewed and verified by the author against AWS documentation |
| `README.md` | Generated by AI based on assignment requirements, reviewed and corrected by the author |
| `backend/app.py`, `frontend/index.html` | Originally written for a previous assignment, adapted with AI assistance |
| `nginx.conf`, `Dockerfiles`, `init.sql` | Generated by AI, reviewed by the author |
The AI was used as a coding assistant. All generated content was reviewed, understood, and verified by the author before submission.