user-microservice

Mikroserwis REST do zarządzania kontami użytkowników, zbudowany w celu porównania narzędzi CI/CD do automatycznego budowania i wdrażania aplikacji skonteneryzowanych. Projekt powstał w ramach pracy magisterskiej.

To repozytorium zawiera kod aplikacji oraz potoki CI (budowanie, testy, publikacja obrazu, aktualizacja repozytorium GitOps). Manifesty Kubernetes i konfiguracje narzędzi CD znajdują się w drugim repozytorium: user-microservice-deploy.


Spis treści


Cel projektu

Zaprojektowano jednolity proces CI/CD (build → test → publikacja obrazu → wdrożenie na Kubernetes) i zaimplementowano go w pięciu narzędziach, a następnie zmierzono czas dostarczenia zmiany (od commita do działającej aplikacji) dla różnych kombinacji narzędzi CI i CD. Celem była obiektywna, ilościowa i jakościowa charakterystyka tych narzędzi.

Proces jest identyczny funkcjonalnie w każdym narzędziu:

  1. Uruchomienie po zdarzeniu push do repozytorium aplikacji.
  2. Uruchomienie testów jednostkowych (pytest).
  3. Zbudowanie obrazu kontenera i opublikowanie go w rejestrze (Azure Container Registry), z tagiem równym SHA commita.
  4. Zaktualizowanie manifestu wdrożenia w repozytorium GitOps (user-microservice-deploy) — podmiana taga obrazu na nowy SHA.
  5. Wdrożenie nowej wersji na klaster Kubernetes (Azure AKS) przez narzędzie CD.

Architektura rozwiązania

        ┌──────────────────────────┐         push          ┌───────────────────────────┐
        │  user-microservice (Git) │ ────────────────────▶ │        Potok CI           │
        │  kod aplikacji + potoki  │                       │  Jenkins / Woodpecker /   │
        └──────────────────────────┘                       │      Argo Workflows       │
                                                            └────────────┬──────────────┘
                                                                         │
                          ┌──────────────────────────────────┬──────────┴───────┐
                          │ 1. pytest                         │                  │
                          │ 2. docker build + push            ▼                  ▼
                          │                       ┌────────────────────┐  ┌───────────────┐
                          │                       │  Azure Container   │  │  commit taga  │
                          │                       │  Registry (ACR)    │  │  do repo      │
                          │                       └────────────────────┘  │  GitOps       │
                          │                                                └───────┬───────┘
                          ▼                                                        │
                                                                                   ▼
        ┌──────────────────────────┐        obserwuje / webhook       ┌───────────────────────────┐
        │ user-microservice-deploy │ ◀──────────────────────────────▶│         Potok CD          │
        │  manifesty K8s (GitOps)  │                                  │  kubectl / ArgoCD / Flux  │
        └──────────────────────────┘                                  └────────────┬──────────────┘
                                                                                    │ apply / sync
                                                                                    ▼
                                                                        ┌───────────────────────────┐
                                                                        │   Azure Kubernetes (AKS)  │
                                                                        │   namespace: user-...     │
                                                                        └───────────────────────────┘

Porównywane narzędzia (5)

Rola Narzędzie Model działania
CI (build/test/push) Jenkins Potok deklaratywny (Jenkinsfile), agent w Kubernetes (pod z wieloma kontenerami)
CI Woodpecker CI Potok YAML (.woodpecker/build.yaml), backend Kubernetes
CI Argo Workflows Sterowany zdarzeniami (Argo Events: EventSource + SensorWorkflow)
CD (deploy) ArgoCD GitOps typu pull — synchronizuje stan klastra z repo deploymentowym
CD FluxCD GitOps typu pullGitRepository + Kustomization + Receiver

Dodatkowo każde narzędzie CI potrafi też pełnić rolę CD w wariancie „to samo narzędzie": wdrożenie realizowane jest wtedy imperatywnie przez kubectl apply (potok wyzwalany commitem do repo GitOps).

Scenariusze pomiarowe

Pełna macierz to 3 narzędzia CI × 3 warianty CD = 9 scenariuszy:

# CI CD
Scenariusz 1 Jenkins Jenkins (kubectl apply)
Scenariusz 2 Jenkins ArgoCD
Scenariusz 3 Jenkins FluxCD
Scenariusz 4 Woodpecker Woodpecker (kubectl apply)
Scenariusz 5 Woodpecker ArgoCD
Scenariusz 6 Woodpecker FluxCD
Scenariusz 7 Argo Workflows Argo Workflows
Scenariusz 8 Argo Workflows ArgoCD
Scenariusz 9 Argo Workflows FluxCD

Scenariusze 13 obejmują Jenkinsa, 46 Woodpeckera, a 79 Argo Workflows — w każdej trójce kolejno: to samo narzędzie do CD, ArgoCD oraz FluxCD.

Mapa branchy

Każda kombinacja narzędzi ma osobny branch — w obu repozytoriach. Poniżej odwzorowanie scenariuszy na branche.

Repozytorium aplikacji (user-microservice) — definicje CI:

Branch Zawartość
main Kod aplikacji (bazowy), ten README, skrypty analizy
dev Gałąź rozwojowa aplikacji
jenkins-pipeline CI w Jenkins (.jenkins/Jenkinsfile, podTemplate.yaml)
woodpecker CI w Woodpecker (.woodpecker/build.yaml)
argo-workflows CI w Argo Workflows / Argo Events (argo-workflows/*)
jenkins-fluxcd, woodpecker-argocd, woodpecker-fluxcd, argoworkflow-argocd, argoworkflow-fluxcd Warianty CI dostrojone do konkretnego narzędzia CD (np. docelowy branch repo GitOps)

Repozytorium deploymentowe (user-microservice-deploy) — manifesty i CD:

Branch Scenariusz
master Baza manifestów
jenkins-kubernetes Sc 1 — Jenkins wdraża przez kubectl
jenkins-argocd-deploy Sc 2 — ArgoCD
jenkins-fluxcd-deploy Sc 3 — FluxCD
woodpecker-deploy Sc 4 — Woodpecker wdraża przez kubectl
woodpecker-argocd-deploy Sc 5 — ArgoCD
woodpecker-fluxcd-deploy Sc 6 — FluxCD
argo-deploy Sc 7 — Argo Workflows
argoworkflow-argocd Sc 8 — ArgoCD
argoworkflow-fluxcd / fluxcd Sc 9 — FluxCD

Uwaga: warianty FluxCD używają układu katalogów apps/ + clusters/prod/ wymaganego przez Flux, pozostałe warianty trzymają manifesty w katalogu głównym repo GitOps.


Aplikacja

Mikroserwis udostępnia API REST do zarządzania kontami użytkowników wraz z uwierzytelnianiem JWT (tokeny w ciasteczkach), rolami oraz mechanizmem wylogowania (unieważnianie tokenów).

Stos technologiczny

  • Python 3.11, Flask 3
  • Flask-JWT-Extended — uwierzytelnianie JWT
  • Flask-SQLAlchemy / SQLAlchemy 2 — ORM
  • MySQL (produkcyjnie), SQLite in-memory (testy)
  • waitress — produkcyjny serwer WSGI
  • pytest — testy jednostkowe
  • Docker — konteneryzacja (obraz bazowy python:3.11.7-slim-bookworm)

API

Metoda Ścieżka Opis Autoryzacja
POST /users Utworzenie użytkownika brak (konto Administrator wymaga tokena admina)
GET /users Lista wszystkich użytkowników tylko Administrator
GET /users/<id> Szczegóły użytkownika właściciel lub Administrator
PUT/PATCH /users/<id> Edycja użytkownika (PUT wymaga wszystkich pól) właściciel lub Administrator
DELETE /users/<id> Usunięcie użytkownika właściciel lub Administrator
POST /login Logowanie, ustawia token JWT w ciasteczku brak
GET /logout Wylogowanie (unieważnienie tokena) zalogowany
GET /health Sprawdzenie stanu aplikacji i połączenia z bazą brak (dostępne na branchach z potokami CI/CD)

Przy pierwszym uruchomieniu, jeśli baza jest pusta, tworzone jest domyślne konto administratora (zob. zmienne ADMIN_*).

Model danych

  • Userid, username (unikalny), email (unikalny), role (Administrator/User), password (hash).
  • RevokedTokenjti unieważnionych tokenów JWT (blocklist przy wylogowaniu).

Konfiguracja (zmienne środowiskowe)

Zmienna Opis Domyślna
SQLALCHEMY_DATABASE_URI Połączenie do bazy MySQL — (wymagana poza testami)
JWT_SECRET_KEY Klucz podpisujący tokeny JWT changeme
APP_PORT Port serwera 80
ADMIN_USERNAME Login domyślnego admina admin
ADMIN_EMAIL E-mail domyślnego admina [email protected]
ADMIN_PASSWORD Hasło domyślnego admina admin

Produkcyjnie sekrety (SQLALCHEMY_DATABASE_URI, hasła MySQL) są dostarczane z Azure Key Vault przez sterownik CSI secrets-store — zob. repozytorium deploymentowe.

Uruchomienie lokalne

Za pomocą Docker Compose (uruchamia API + MySQL):

# przygotuj pliki api/.env oraz db/.env ze zmiennymi środowiskowymi
docker compose up --build

Bez konteneryzacji:

cd api
python3 -m venv env && source env/bin/activate
pip install -r requirements.txt
python3 app.py

Aplikacja czeka na gotowość bazy danych przy starcie (wait_for_db, do 100 prób co 3 s).

Testy

cd api
python3 -m venv env && source env/bin/activate
pip install -r requirements.txt pytest
python3 -m pytest

Testy używają bazy SQLite w pamięci (konfiguracja testing) i pokrywają operacje CRUD oraz uwierzytelnianie. Ten sam zestaw testów jest uruchamiany w każdym potoku CI.

Wcześniejsze wersje potoków korzystały dodatkowo z testów kontenera Goss — zostały one ostatecznie usunięte z potoków (por. historia commitów), a walidację przejęły testy pytest oraz health check po wdrożeniu.


Potoki CI

Definicje potoków znajdują się na branchach poszczególnych narzędzi. Wszystkie realizują ten sam trzyetapowy proces: testy → build&push → commit do GitOps.

Jenkins

Branch jenkins-pipeline, plik .jenkins/Jenkinsfile. Potok deklaratywny uruchamiany na agencie w Kubernetes — pod z osobnymi kontenerami do każdego etapu (podTemplate.yaml):

  • python — uruchomienie pytest (wyniki jako JUnit XML),
  • dockerdocker build + logowanie do ACR (Azure managed identity) + docker push,
  • git — sklonowanie repo GitOps, podmiana taga obrazu (awk) i commit na branch jenkins-kubernetes.

Build kontenera działa bez uprawnień roota dzięki sysbox (runtimeClassName: sysbox-runc).

Woodpecker CI

Branch woodpecker, plik .woodpecker/build.yaml. Trzy kroki (code-tests, build-and-push, gitops-commit) na backendzie Kubernetes. Docker-in-Docker uruchamiany lokalnie (dockerd &) w kontenerze z sysbox. Sekrety (klucz deploy do Gitea, known hosts) pobierane z sekretów Woodpeckera.

Argo Workflows

Branch argo-workflows, katalog argo-workflows/. Podejście sterowane zdarzeniami przez Argo Events:

  • source.yamlEventSource (webhook, dwa endpointy: dla repo aplikacji i deploymentowego),
  • sensor.yamlSensor reagujący na push i tworzący Workflow budujący (etapy: checkouttestsbuild-and-push-imagegitops-commit),
  • eventbus-default.yaml — szyna zdarzeń (NATS),
  • permissions.yamlServiceAccount + Role/RoleBinding,
  • secret-store.yaml — dostęp do sekretów z Key Vault.

Wspólny schemat potoku CI

Wszystkie trzy narzędzia wykonują tę samą logikę, różniąc się jedynie składnią i modelem uruchamiania:

push → [pytest] → [docker build → az acr login → docker push (tag = SHA)] → [clone repo GitOps → awk: podmiana tagu → commit → push]

Aktualizacja manifestu w repo GitOps jest realizowana identycznym skryptem awk, który znajduje kontener api i podmienia w nim tag obrazu na SHA nowego commita.

Infrastruktura

Element Zastosowanie
Azure Kubernetes Service (AKS) Klaster docelowy; działają na nim także agenci CI oraz kontrolery CD
Azure Container Registry (marcin00.azurecr.io) Rejestr obrazów
Azure Key Vault + CSI secrets-store Dostarczanie sekretów do podów
Managed Identity Bezhasłowe uwierzytelnianie do ACR / AKS / Key Vault
Gitea (self-hosted, gitea.marcin00.pl) Repozytoria Git + webhooki wyzwalające potoki
sysbox (sysbox-runc) Budowanie obrazów bez uprawnień roota (rootless DinD)
NGINX Ingress Wystawienie aplikacji (user-microservice.marcin00.pl)

Pomiar dostarczenia zmiany

Metryką porównawczą jest czas dostarczenia zmiany (od commita do działającej aplikacji na klastrze), rozbity na składowe:

  • trigger_time — czas od startu potoku CI do faktycznego rozpoczęcia budowania,
  • build_time — czas budowania i publikacji obrazu,
  • deploy_time — czas wdrożenia na klaster,
  • full_time — całkowity czas dostarczenia.

Pomiar wykonywany jest osobno dla każdego z 9 scenariuszy na podstawie znaczników czasu z potoków CI/CD, co pozwala porównać narzędzia zarówno pod kątem całkowitego czasu, jak i wkładu poszczególnych etapów.

Struktura repozytorium

user-microservice/
├── api/
│   ├── app.py               # fabryka aplikacji Flask, konfiguracja, start serwera waitress
│   ├── views.py             # endpointy API (użytkownicy, login/logout)
│   ├── models.py            # modele SQLAlchemy: User, RevokedToken
│   ├── utils.py             # autoryzacja, oczekiwanie na bazę, inicjalizacja admina
│   ├── requirements.txt     # zależności aplikacji
│   └── tests/               # testy pytest (conftest.py, test_users.py)
├── Dockerfile               # obraz aplikacji
└── docker-compose.yml       # lokalne uruchomienie API + MySQL

Definicje potoków CI (Jenkinsfile, .woodpecker/, argo-workflows/) znajdują się na odpowiednich branchach — zob. Mapa branchy.

S
Description
No description provided
Readme
416 KiB
Languages
Python 99.4%
Dockerfile 0.6%