No description
  • HCL 58.9%
  • Python 27.6%
  • HTML 7.8%
  • Shell 3.9%
  • Dockerfile 1.8%
Find a file
jwerwinski a887e0ec89
Some checks are pending
Deploy prod / test (3.12) (push) Successful in 45s
Deploy prod / test (3.13) (push) Successful in 44s
Deploy prod / build-and-deploy (push) Successful in 3m38s
Deploy prod / smoke-test (push) Waiting to run
Merge pull request 'develop' (#5) from develop into main
Reviewed-on: #5
2026-06-23 15:36:26 +00:00
.forgejo/workflows first release 2026-06-23 14:14:39 +02:00
ansible first release 2026-06-23 14:14:39 +02:00
app first release 2026-06-23 14:14:39 +02:00
docker first release 2026-06-23 14:14:39 +02:00
frontend first release 2026-06-23 14:14:39 +02:00
terraform first release 2026-06-23 14:14:39 +02:00
tests first release 2026-06-23 14:14:39 +02:00
.gitignore first release 2026-06-23 14:14:39 +02:00
Dockerfile first release 2026-06-23 14:14:39 +02:00
pyproject.toml first release 2026-06-23 14:14:39 +02:00
README.md fix: change links for testing 2026-06-23 14:24:41 +02:00
renovate.json first release 2026-06-23 14:14:39 +02:00
VERSION bump version to 1.0.3 2026-06-23 17:25:30 +02:00

Calculator API - DevOps Project

Prosta REST API kalkulatora zbudowana w FastAPI, wdrożona na AWS ECS Fargate przy użyciu w pełni zautomatyzowanego pipeline CI/CD opartego na Forgejo Actions.

Opis projektu

Aplikacja udostępnia trzy endpointy:

  • GET /health - status aplikacji (liveness check), zawiera hostname kontenera
  • GET /version - wersja aktualnie wdrożonego obrazu, też z hostname
  • POST /calculate - operacje arytmetyczne (add, subtract, multiply, divide)

Pole hostname w /health//version pozwala zobaczyć High Availability w akcji - prod działa jako 2 zadania ECS za jednym ALB (desired_count = 2), więc kolejne odświeżenia curl prod_url/health powinny pokazywać różne wartości hostname (różne kontenery odpowiadające przez round-robin).

Architektura

flowchart TD
    A[Push -> develop] --> B[pytest + Ruff + Bandit]
    B --> C[docker build + Trivy CVE/SBOM]
    C --> D["ECR push :preprod"]
    D --> E[ECS preprod deploy]
    E --> F[Playwright e2e]
    F --> G["PR develop -> main<br/>code review"]
    G --> H[Merge do main]
    H --> I[pytest + Ruff + Bandit]
    I --> J[docker build + Trivy CVE/SBOM]
    J --> K["ECR push :latest"]
    K --> L[ECS prod deploy]
    L --> M[Playwright smoke]
flowchart LR
    ECR[("Amazon ECR<br/>:preprod / :latest / :sha")]
    subgraph Cluster["ECS Fargate - jeden klaster"]
        Prod["calculator-api-prod<br/>2x task (HA)"]
        Preprod["calculator-api-preprod<br/>1x task"]
    end
    ECR --> Prod
    ECR --> Preprod
    ALB["Application Load Balancer"]
    ALB -->|":80"| Prod
    ALB -->|":8080"| Preprod
    S3[("S3 - statyczny frontend")] -. fetch API .-> ALB
flowchart TB
    subgraph AWS["AWS"]
        EC2["EC2 t3.micro (free tier)"]
        DinD["docker-in-docker"]
        Runner1["Forgejo Runner<br/>label aws:host"]
        EC2 --- DinD
        EC2 --- Runner1
    end
    subgraph External["Poza AWS - self-hosted"]
        Forgejo["Forgejo<br/>git.jwerwinski.pl"]
        Runner2["Forgejo Runner<br/>label aws:host"]
        Renovate["Renovate<br/>cron: poniedzialek"]
    end
    Runner1 -. rejestracja .-> Forgejo
    Runner2 -. lokalnie .-> Forgejo

Definicje pipeline'u: .forgejo/workflows/ci.yml (PR → main/develop), deploy-preprod.yml (push → develop), deploy-prod.yml (push → main).

Postawienie projektu od zera

  1. Self-hosted Forgejo musi już działać - patrz Forgejo. Wymagane: Actions, Runners, Secrets.

  2. Wypchnij kod do Forgejo - w Forgejo: + → New Repository (nazwa calculator-api, bez "Initialize Repository"). Lokalnie:

    git init
    git add -A && git commit -m "Initial commit"
    git remote add origin https://<TWOJ_FORGEJO>/<USER>/calculator-api.git
    git branch -M main
    git push -u origin main
    git checkout -b develop && git push -u origin develop
    
  3. tofu apply - patrz Infrastruktura (OpenTofu). Stawia VPC, ECR (pusty), ECS+ALB, EC2 dla runnera, bucket S3 (pusty). Zapisz tofu output - będzie potrzebny w punktach 5 i 7.

  4. Zarejestruj runner(y) w Forgejo - Site Administration → Actions → Runners → Create new runner. Zapisz uuid i token.

  5. Skonfiguruj runner(y) Ansiblem - sekcja Rejestracja Forgejo Runnera, podsekcja "Automatyczna konfiguracja (Ansible)". Po tym kroku Manage runners w Forgejo powinno pokazywać status Idle/Online, nie Offline.

  6. Dodaj sekrety w repo Forgejo - patrz Secrets w Forgejo. Wartości AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY z tofu output ci_access_key_id / tofu output -raw ci_secret_access_key, PREPROD_URL/PROD_URL/FRONTEND_BUCKET z odpowiednich tofu output.

  7. Pierwszy push - git push origin develop odpala deploy-preprod.yml (build → ECR :preprod → ECS preprod → e2e). Jeśli przejdzie, PR develop → main → po merge deploy-prod.yml (→ ECS prod → upload frontendu na S3 → smoke testy). Przed tym pierwszym pushem ECR jest pusty, więc ECS będzie zwracać 503 - to oczekiwane, mija po pierwszym udanym przebiegu.

  8. Zweryfikuj - curl <prod_url>/health, /version, otwórz <frontend_url> w przeglądarce.

Wymagania lokalne

  • Docker
  • Python 3.12+
  • OpenTofu >= 1.6
  • AWS CLI v2

Uruchomienie lokalne

docker build -t calculator-api .
docker run -p 8000:8000 calculator-api

curl http://localhost:8000/health
curl http://localhost:8000/version
curl -X POST http://localhost:8000/calculate \
  -H "Content-Type: application/json" \
  -d '{"a": 10, "b": 5, "operation": "add"}'

Testy

pip install -r tests/requirements-test.txt

# Testy jednostkowe
pytest tests/test_main.py -v

# Lint + SAST
ruff check app tests
bandit -r app

# Testy e2e na preprodzie
APP_URL=http://<ALB_DNS>:8080 pytest tests/test_e2e.py -v

# Smoke testy na prodzie
APP_URL=http://<ALB_DNS> pytest tests/test_e2e.py -v -k "health or version"

Demo High Availability

for i in $(seq 1 10); do curl -s http://<ALB_DNS>/health | jq .hostname; done

Przy 2 zadaniach ECS za ALB powinny się tu przewijać dwie różne wartości hostname.

Infrastruktura (OpenTofu)

cd terraform/environments/prod

tofu init
tofu plan
tofu apply

tofu output

Flow pracy z branchami

# Praca na develop
git checkout develop
# ... zmiany ...
git push origin develop
# → pipeline: build → preprod deploy → e2e testy

# Po przejściu testów - PR do main w Forgejo
# → code review → merge
# → pipeline: build → prod deploy → smoke testy

Secrets w Forgejo

Settings → Secrets → Actions:

Secret Opis
AWS_ACCESS_KEY_ID Klucz AWS
AWS_SECRET_ACCESS_KEY Secret AWS
PREPROD_URL URL preprod (http://ALB:8080)
PROD_URL URL prod (http://ALB)
FRONTEND_BUCKET Nazwa bucketu S3 z frontendem (tofu output frontend_bucket_name)
RENOVATE_TOKEN Token Forgejo dla Renovate bota

Rejestracja Forgejo Runnera

Runner działa jako kontener Docker (wg dokumentacji Forgejo): osobny kontener docker:dind jako silnik Docker, runner łączy się z nim po TCP. Obraz runnera (docker/Dockerfile.runner) ma wbudowane docker, aws i trivy, więc joby z labelem aws:host (czyli odpalane bezpośrednio w kontenerze runnera, bez zagnieżdżonego kontenera na job) mają od razu dostęp do tych narzędzi.

Automatyczna konfiguracja (Ansible) - zalecane

Terraform stawia maszynę EC2; cała konfiguracja runnera (build obrazu, wpisanie tokenu rejestracyjnego, start daemona) jest w ansible/playbook.yml - idempotentny, bezpieczny do wielokrotnego odpalenia (np. po tofu destroy + tofu apply).

cd ansible
cp group_vars/all.yml.example group_vars/all.yml
./generate-inventory.sh  # czyta IP z `tofu output runner_ips`
ansible-playbook -i inventory.ini playbook.yml

group_vars/all.yml i inventory.ini są w .gitignore (zawierają token i IP) - commitowany jest tylko .example.

Konfiguracja Renovate

Renovate działa razem z Forgejo na własnym serwerze (poza tym Terraformem). Reguły (harmonogram, automerge patchy) są już zdefiniowane w renovate.json w korzeniu repo - Renovate odczytuje je automatycznie przy skanowaniu repozytorium, nie trzeba ich osobno montować do kontenera. Renovate otwiera PR-y codziennie w poniedzialek. Patch releases - automerge, minor/major - wymagają zatwierdzenia.

Wazne informacje:

Reguła main:

Disable push - nikt nie może pushować bezpośrednio na main Zmiany na main mogą trafić tylko przez Pull Request

Reguła develop:

Enable push - można pushować i tworzyć nowe branche od develop Mergeowanie do develop działa normalnie przez PR

Linki

Środowisko URL
Prod tofu output prod_url
Preprod tofu output preprod_url
Frontend (kalkulator) tofu output frontend_url
Forgejo https://git.jwerwinski.pl

Demo linki

ecr_repo = "445606684565.dkr.ecr.us-west-2.amazonaws.com/calculator-api"

frontend_bucket_name = "calculator-api-frontend-445606684565"

frontend_url = "http://calculator-api-frontend-445606684565.s3-website-us-west-2.amazonaws.com"

preprod_url = "http://calculator-api-alb-3370378.us-west-2.elb.amazonaws.com:8080"

prod_url = "http://calculator-api-alb-3370378.us-west-2.elb.amazonaws.com"

runner_ips = [ "44.248.16.224", ]