Przejdź do treści
← wszystkie przedmioty

Cloud i DevOps

Fundamenty chmury i DevOps dla pracującego inżyniera: Docker, CI/CD, Kubernetes, Infrastructure as Code, twelve-factor app, wdrożenia blue-green/canary oraz trzy filary observability.

TEMATY EGZAMINACYJNE W TYM PRZEDMIOCIE
  • Multi-stage buildy Dockera i wpływ warstw na rozmiar oraz cache builda
  • Rdzeniowe obiekty Kubernetes: Pod, Deployment, Service, ConfigMap/Secret i ich wzajemne role
  • Deklaratywne Infrastructure as Code (Terraform): init/plan/apply, dryf stanu, przewaga nad ręcznym provisioningiem
  • Dwanaście czynników aplikacji, zwłaszcza config w zmiennych środowiskowych i bezstanowe procesy
  • Blue-green vs canary: mechanizm przełączania ruchu i pułapki migracji bazy danych
  • Trzy filary observability (logi, metryki, trace'y) i korelacja przez trace_id

1 · Docker: obrazy, warstwy i multi-stage buildy

★ egzamin

Kontener nie jest lekką maszyną wirtualną: dzieli jądro systemu hosta i izoluje procesy przez namespaces oraz cgroups. Obraz Docker to niezmienny szablon zbudowany z warstw; kontener to jego uruchomiona instancja z własną, zapisywalną warstwą na wierzchu.

Termin kluczowy
Obraz (image) - Niezmienny, wielowarstwowy szablon plikowy plus metadane (ENTRYPOINT, ENV, EXPOSE); budowany raz, uruchamiany wielokrotnie jako kontener.
Termin kluczowy
Warstwa (layer) - Każda instrukcja Dockerfile (FROM, RUN, COPY...) tworzy osobną, cache'owalną warstwę tylko-do-odczytu; obraz to stos tych warstw połączony przez union filesystem (np. overlay2).
Cache warstw
Docker cache'uje warstwy między buildami: jeśli instrukcja i jej wejścia się nie zmieniły, warstwa jest reużywana. Zmiana warstwy unieważnia cache tej i wszystkich kolejnych warstw, dlatego kolejność instrukcji w Dockerfile bezpośrednio wpływa na czas builda.
Dockerfile jednoetapowy (działa, ale nieoptymalny) dockerfile
FROM node:22
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
CMD ["node", "dist/server.js"]
Pułapka
COPY . . przed RUN npm install unieważnia cache zależności przy KAŻDEJ zmianie w kodzie źródłowym, bo cache warstwy COPY zależy od zawartości katalogu. Najpierw kopiuj pliki manifestu zależności (package.json), instaluj, dopiero potem kopiuj resztę kodu.
Multi-stage build: etap builder + lekki runtime dockerfile
# --- Etap budowania ---
FROM node:22 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# --- Etap uruchomieniowy ---
FROM node:22-slim AS runtime
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist
USER node
EXPOSE 3000
CMD ["node", "dist/server.js"]
Dlaczego mniejszy obraz się liczy
Mniej zainstalowanych pakietów systemowych to mniejsza powierzchnia ataku: mniej CVE do skanowania i łatania. Mniejszy rozmiar to szybszy pull przy skalowaniu/deployu i szybszy cold start w środowiskach serverless czy Kubernetes.
Obraz bazowyRozmiar względem alternatywKompromis
ubuntu:24.04 / debian:bookwormDuży, pełny system pakietówWygodny do debugowania (shell, apt), ale duża powierzchnia ataku
node:22-slim / python:3.13-slimŚredniMniej pakietów niż pełny obraz, wciąż ma shell i podstawowe narzędzia
gcr.io/distroless/*Mały, brak shella i menedżera pakietówNajmniejsza powierzchnia ataku, trudniejszy debugging (brak sh do exec)
Mnemonik
Warstwy Dockera jak commity w Gicie: każda kolejna to diff na poprzedniej, a Docker (jak Git) potrafi reużyć niezmieniony fragment historii zamiast przeliczać wszystko od nowa.
  • Sortuj instrukcje od najrzadziej do najczęściej zmienianych (zależności przed kodem źródłowym)
  • Używaj .dockerignore, by nie kopiować node_modules/.git do kontekstu builda
  • Pinuj wersję obrazu bazowego (node:22.14-slim, nie node:latest) dla powtarzalnych buildów
  • Uruchamiaj proces jako użytkownik nie-root (USER) w finalnym etapie
  • Łącz RUN apt-get update && apt-get install w jedną instrukcję, by nie zostawiać cache'u pakietów w osobnej warstwie

Build jednoetapowy

  • Finalny obraz zawiera kompilator/dev-dependencies, których produkcja nie potrzebuje
  • Większa powierzchnia ataku (więcej pakietów = więcej CVE)
  • Wolniejszy pull i dłuższy cold start przez zbędny balast

Multi-stage build

  • Etap builder zawiera narzędzia, ale nigdy nie trafia do finalnego obrazu
  • Do warstwy runtime kopiowane są tylko gotowe artefakty (np. /dist)
  • Mniejszy, szczuplejszy obraz gotowy na produkcję

2 · Pipeline CI/CD: etapy i przyczyny porażek

★ egzamin

Pipeline CI/CD to automatyzacja ścieżki od commitu do działającego kodu na środowisku. Celem jest wykryć problem jak najwcześniej (fail-fast) i sprawić, że wdrożenie jest nudną, powtarzalną czynnością, nie wydarzeniem wysokiego ryzyka.

Termin kluczowy
Continuous Integration (CI) - Częste, wielokrotnie dzienne scalanie zmian do wspólnej gałęzi, każdorazowo weryfikowane automatycznym buildem i testami, by wykryć konflikty i regresje szybko.
Termin kluczowy
Continuous Delivery vs Continuous Deployment - Delivery: każdy zielony build jest gotowym do wdrożenia artefaktem, ale wymaga ręcznej decyzji o wypuszczeniu. Deployment: idzie krok dalej i wdraża automatycznie na produkcję bez interwencji człowieka.
  1. 1 Build: kompilacja/pakowanie kodu do artefaktu (obraz Docker, binarka, paczka)
  2. 2 Test: testy jednostkowe, integracyjne, czasem bezpieczeństwa (SAST, skan zależności)
  3. 3 Deploy: wypchnięcie artefaktu na środowisko (staging, potem produkcja), zwykle z bramką jakości między etapami
Minimalny pipeline w GitHub Actions yaml
name: CI
on:
  push:
    branches: [main]
  pull_request:

jobs:
  build-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm run build
      - run: npm test

  deploy:
    needs: build-test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: echo "deploy do produkcji po zielonym build-test"
Dlaczego pipeline'y zawodzą
Najczęstsze realne przyczyny: testy zależne od współdzielonego, niezaizolowanego stanu (flaky), niepinowane wersje zależności (build dziś różni się od builda jutro), brak parytetu między środowiskiem CI a produkcją, oraz sekrety/uprawnienia skonfigurowane inaczej niż lokalnie.
Pułapka
'Działa u mnie na laptopie' zwykle oznacza brak reprodukowalności builda: niepinowane wersje w package.json, różne wersje runtime, albo poleganie na stanie lokalnego cache, którego CI nie ma.
EtapPyta oTypowe narzędzie
BuildCzy kod się kompiluje/pakuje?docker build, npm run build
TestCzy zachowanie jest poprawne?npm test, pytest, testy kontraktowe
DeployCzy artefakt działa na docelowym środowisku?kubectl apply, terraform apply, helm upgrade
Mnemonik
Bramka jakości pipeline'u działa jak sito: im wcześniej (build), tym grubsze oczka i tańszy koszt błędu; im później (produkcja), tym drobniejsze oczka i drożej kosztuje przepuszczenie defektu.
  1. 1 Trigger Push lub pull request uruchamia pipeline automatycznie
  2. 2 Build Kod kompilowany/pakowany do artefaktu (np. obraz Docker z tagiem commit SHA)
  3. 3 Test Automatyczne testy blokują dalsze etapy przy pierwszym czerwonym wyniku
  4. 4 Deploy do staging Artefakt trafia na środowisko zbliżone do produkcji
  5. 5 Bramka (opcjonalna) Ręczna akceptacja lub automatyczne kryteria przed produkcją
  6. 6 Deploy do produkcji Ten sam, niezmieniony artefakt z wcześniejszych etapów trafia na produkcję
Ten sam artefakt
Kluczowa zasada: artefakt zbudowany raz na początku pipeline'u wędruje przez wszystkie środowiska bez ponownego budowania. Inaczej testujesz jedną rzecz, a wdrażasz inną.

3 · Fundamentalne obiekty Kubernetes

★ egzamin

Kubernetes orkiestruje kontenery przez deklaratywne obiekty API: deklarujesz pożądany stan, a control plane (scheduler, kontrolery) nieustannie dąży do zgodności rzeczywistego stanu z zadeklarowanym (reconciliation loop).

Termin kluczowy
Pod - Najmniejsza jednostka wdrożeniowa w Kubernetes: jeden lub więcej kontenerów współdzielących namespace sieciowy (jeden IP) i opcjonalnie wolumeny, zawsze planowanych razem na tym samym węźle.
Termin kluczowy
Deployment - Obiekt wyższego poziomu zarządzający ReplicaSetami: deklaruje pożądaną liczbę replik Poda, wykonuje rolling update przy zmianie obrazu/konfiguracji i pozwala na rollback do poprzedniej wersji.
Termin kluczowy
Service - Stabilny punkt dostępu (wirtualny IP + DNS) do dynamicznego zestawu Podów wybieranych przez selektor etykiet; rozwiązuje problem efemeryczności Podów, których adresy IP zmieniają się przy każdym restarcie.
Termin kluczowy
ConfigMap / Secret - Obiekty przechowujące konfigurację poza obrazem kontenera. ConfigMap dla danych jawnych (np. LOG_LEVEL), Secret dla wrażliwych (hasła, tokeny), domyślnie tylko zakodowanych base64, nie zaszyfrowanych.
Deployment + Service dla prostego API yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-server
  labels:
    app: api-server
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api-server
  template:
    metadata:
      labels:
        app: api-server
    spec:
      containers:
        - name: api-server
          image: registry.example.com/api-server:1.4.2
          ports:
            - containerPort: 8080
          envFrom:
            - configMapRef:
                name: api-server-config
            - secretRef:
                name: api-server-secrets
---
apiVersion: v1
kind: Service
metadata:
  name: api-server
spec:
  type: ClusterIP
  selector:
    app: api-server
  ports:
    - port: 80
      targetPort: 8080
ConfigMap i Secret wstrzykiwane jako zmienne środowiskowe yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: api-server-config
data:
  LOG_LEVEL: "info"
  FEATURE_FLAG_NEW_CHECKOUT: "true"
---
apiVersion: v1
kind: Secret
metadata:
  name: api-server-secrets
type: Opaque
stringData:
  DATABASE_URL: postgres://app:changeme@db.internal:5432/app
Dlaczego nie gołe Pody
Pod bez nadzorującego kontrolera (Deployment/ReplicaSet/StatefulSet) nie ma self-healing: jeśli węzeł padnie albo proces się wysypie, nikt automatycznie go nie odtworzy. Deployment dodaje deklaratywne rolling update, rollback i utrzymanie zadanej liczby replik.
Pułapka
Secret w Kubernetes to nie 'szyfrowany sejf' z automatu: dane są tylko zakodowane base64 (trywialnie odwracalne), a w etcd leżą w postaci czytelnej, dopóki administrator klastra nie włączy encryption-at-rest. Traktuj RBAC do Secretów równie poważnie jak dostęp do produkcyjnej bazy danych.
ObiektOdpowiada zaAnalogia
PodUruchomienie kontenera(-ów) jako jednej jednostkiProces systemowy
DeploymentUtrzymanie N replik Poda + rolling update/rollbackSystemd unit z auto-restartem i wersjonowaniem
ServiceStabilny adres do zmiennego zestawu PodówLoad balancer + wewnętrzny DNS
ConfigMap/SecretKonfiguracja i dane wrażliwe poza obrazemPlik .env zamontowany z zewnątrz
Mnemonik
Pod to 'co działa', Deployment to 'ile i jak to utrzymać', Service to 'jak się do tego dostać' - trzy różne, ortogonalne pytania, trzy różne obiekty API.

4 · Infrastructure as Code: deklaratywne provisioning

★ egzamin

Infrastructure as Code zamienia klikanie w konsoli chmurowej na kod: infrastrukturę opisuje się w plikach, wersjonuje w Git i stosuje przez narzędzie, które oblicza różnicę między stanem zadeklarowanym a rzeczywistym.

Termin kluczowy
IaC (Infrastructure as Code) - Zarządzanie infrastrukturą (serwery, sieci, DNS, uprawnienia) przez pliki konfiguracyjne przetwarzane maszynowo, a nie przez ręczne operacje w konsoli/UI.
Termin kluczowy
Deklaratywne vs imperatywne provisioning - Deklaratywne (Terraform): opisujesz pożądany stan końcowy, narzędzie samo ustala różnicę i kroki dojścia. Imperatywne (skrypt bash z aws-cli): opisujesz dokładną sekwencję komend do wykonania.
Terraform: provider AWS + zasób EC2 z dynamicznym lookupem AMI hcl
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }
}

provider "aws" {
  region = "eu-central-1"
}

data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["al2023-ami-*-x86_64"]
  }
}

resource "aws_instance" "web" {
  ami           = data.aws_ami.amazon_linux.id
  instance_type = "t3.micro"

  tags = {
    Name = "web-server"
  }
}
  1. 1 terraform init Pobiera providery (np. hashicorp/aws) i inicjalizuje backend stanu
  2. 2 terraform plan Pokazuje różnicę między kodem a bieżącym stanem (co zostanie dodane/zmienione/usunięte)
  3. 3 terraform apply Wykonuje zmiany z planu i zapisuje nowy stan
  4. 4 terraform destroy Usuwa zasoby zarządzane przez ten kod, zgodnie z zapisanym stanem
Stan (state)
Terraform trzyma plik stanu mapujący zasoby w kodzie na rzeczywiste zasoby w chmurze. To źródło prawdy do obliczania różnicy przy kolejnym plan/apply, dlatego stan współdzielony przez zespół trzyma się zdalnie (np. S3 + blokada), nie lokalnie na laptopie.
Pułapka
Ręczna zmiana zasobu w konsoli chmurowej po tym, jak zaczął nim zarządzać Terraform, powoduje drift: stan w pliku przestaje odpowiadać rzeczywistości, a kolejny apply może nieoczekiwanie cofnąć ręczną zmianę albo zgłosić konflikt.
  • Każda zmiana infrastruktury przechodzi code review jak zmiana w aplikacji (pull request z terraform plan w opisie)
  • Infrastruktura jest odtwarzalna 1:1 w innym regionie/koncie (disaster recovery, nowe środowisko)
  • Historia zmian jest w Git, nie w pamięci osoby, która kiedyś kliknęła w konsoli
  • Ten sam kod (moduł) da się sparametryzować i użyć dla dev/staging/prod
PodejściePrzykładRyzyko
Ręczne klikanie w konsoliAWS/GCP/Azure ConsoleBrak historii zmian, nieodtwarzalne 1:1, wiedza 'w głowie' jednej osoby
Imperatywne skryptyaws-cli/gcloud w bashDziała, ale trzeba samemu obsłużyć idempotencję i błędy częściowego wykonania
Deklaratywne IaCTerraform, PulumiIdempotentne z założenia, ale wymaga zarządzania plikiem stanu
Mnemonik
Terraform jak Git dla infrastruktury: kod to źródło prawdy, plan to diff, apply to commit do rzeczywistości.

5 · Dwanaście czynników aplikacji (Twelve-Factor App)

★ egzamin

Twelve-Factor App (Heroku, 2011) to zestaw dwunastu praktyk budowania aplikacji SaaS łatwych do skalowania, przenoszenia między środowiskami i utrzymania bez ręcznej ingerencji. Mimo wieku, każdy punkt wprost mapuje się na dzisiejsze kontenery i Kubernetes.

  1. 1 I. Codebase - jedna baza kodu w kontroli wersji, wiele wdrożeń z niej wynikających
  2. 2 II. Dependencies - jawnie zadeklarowane zależności (package.json), nigdy 'zainstalowane ręcznie na serwerze'
  3. 3 III. Config - konfiguracja różniąca się między środowiskami trzymana w zmiennych środowiskowych, nie w kodzie
  4. 4 IV. Backing services - baza danych, kolejka, cache traktowane jako podłączane zasoby wymienne bez zmiany kodu
  5. 5 V. Build, release, run - ścisłe rozdzielenie etapu budowy, złożenia z configiem i uruchomienia
  6. 6 VI. Processes - procesy aplikacji bezstanowe, trwały stan żyje w backing service
  7. 7 VII. Port binding - aplikacja sama nasłuchuje na porcie, nie wymaga wstrzykniętego web serwera
  8. 8 VIII. Concurrency - skalowanie przez uruchamianie kolejnych instancji procesu (horyzontalnie), nie przez grubszy proces
  9. 9 IX. Disposability - szybki start i graceful shutdown, procesy jednorazowe do zabicia/odtworzenia w każdej chwili
  10. 10 X. Dev/prod parity - środowiska deweloperskie, staging i produkcja maksymalnie zbliżone
  11. 11 XI. Logs - logi jako strumień zdarzeń na stdout, nie zarządzane przez aplikację pliki
  12. 12 XII. Admin processes - zadania administracyjne (migracje, konsola) uruchamiane jako jednorazowe procesy w tym samym środowisku co aplikacja
Termin kluczowy
Config (czynnik III) - Wszystko, co różni się między środowiskami (URL bazy danych, klucze API, feature flagi), musi być w zmiennych środowiskowych, nigdy zahardkodowane, tak by ten sam zbudowany artefakt działał identycznie na dev/staging/prod.
Odczyt konfiguracji ze środowiska z fail-fast przy braku wymaganej wartości javascript
// Factor III: Config - wartości środowiskowe, nie zahardkodowane w kodzie
const config = {
  port: process.env.PORT ?? 3000,
  databaseUrl: process.env.DATABASE_URL,
  logLevel: process.env.LOG_LEVEL ?? 'info',
};

if (!config.databaseUrl) {
  throw new Error('DATABASE_URL is required');
}
Pułapka
Zahardkodowany connection string do bazy w kodzie albo w commitowanym pliku config.json łamie czynnik III i zwykle kończy się wyciekiem sekretu do historii Gita. Sekrety trzymaj w zmiennych środowiskowych wstrzykiwanych przez platformę (Vercel env, Kubernetes Secret), nie w repo.
Backing services jako zasoby podłączalne (IV)
Baza danych, broker kolejki, cache Redis to zasoby dołączane przez URL/connection string, wymienialne bez zmiany kodu aplikacji, np. przełączenie z lokalnego Postgresa na zarządzaną instancję wymaga tylko zmiany DATABASE_URL.
Dlaczego procesy bezstanowe (VI, IX)
Bezstanowy proces, bez trwałego stanu w pamięci czy na dysku lokalnym, można swobodnie skalować horyzontalnie, restartować i zabijać w dowolnym momencie (disposability), bo utrata jednej instancji nie traci danych - stan żyje w backing service.
Logi jako strumień (XI)
Aplikacja pisze zdarzenia na stdout/stderr i nie decyduje, gdzie trafiają docelowo; agregacja, rotacja i przechowywanie logów to odpowiedzialność platformy (np. kolektor w Kubernetes), nie kodu aplikacji.
Mnemonik
Test czynnika III: gdybyś skopiował zbudowany artefakt 1:1 na inne środowisko i podmienił tylko zmienne środowiskowe, czy zadziała bez przebudowy? Jeśli nie, konfiguracja przecieka do kodu.
CzynnikSkrót myślowy
I. CodebaseJedno repo, wiele deployów
III. ConfigEnv vars, nie kod
VI. ProcessesBez stanu w pamięci
IX. DisposabilityMożna zabić w każdej chwili
XI. Logsstdout, nie własny plik

6 · Strategie wdrożeń: blue-green i canary

Blue-green i canary to dwie odpowiedzi na to samo pytanie: jak wdrożyć nową wersję bez przestoju i bez ryzykowania całego ruchu produkcyjnego na raz.

Termin kluczowy
Blue-green deployment - Dwa pełne, identyczne środowiska: blue (obecnie obsługuje ruch) i green (nowa wersja). Po weryfikacji green ruch przełącza się niemal natychmiastowo (np. zmiana selektora load balancera/Service), a blue zostaje jako natychmiastowa ścieżka rollbacku.
Termin kluczowy
Canary deployment - Nowa wersja trafia najpierw do małego podzbioru ruchu (np. 5-10%); jeśli metryki (błędy, latencja) pozostają zdrowe, udział ruchu stopniowo rośnie aż do 100%, minimalizując blast radius ewentualnego błędu.
Blue-green: Service wskazuje na wersję blue yaml
apiVersion: v1
kind: Service
metadata:
  name: api-server
spec:
  selector:
    app: api-server
    version: blue
  ports:
    - port: 80
      targetPort: 8080
Przełączenie produkcyjnego ruchu z blue na green jedną komendą bash
kubectl patch service api-server -p '{"spec":{"selector":{"version":"green"}}}'
Rollback w blue-green
Rollback to dokładnie ta sama operacja co przełączenie w drugą stronę: zmiana selektora z powrotem na blue. Ponieważ stare środowisko wciąż działa (nie zostało jeszcze usunięte), czas przywrócenia liczy się w sekundach.
Canary bez service mesh: proporcja replik jako przybliżony procent ruchu yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-server-stable
spec:
  replicas: 9
  selector:
    matchLabels:
      app: api-server
      track: stable
  template:
    metadata:
      labels:
        app: api-server
        track: stable
    spec:
      containers:
        - name: api-server
          image: registry.example.com/api-server:1.4.2
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-server-canary
spec:
  replicas: 1
  selector:
    matchLabels:
      app: api-server
      track: canary
  template:
    metadata:
      labels:
        app: api-server
        track: canary
    spec:
      containers:
        - name: api-server
          image: registry.example.com/api-server:1.5.0-rc1
Canary przez proporcję replik
Bez service mesh (Istio/Linkerd) czy Argo Rollouts, najprostszy canary w czystym Kubernetes to dwa Deploymenty, każdy z własnym unikalnym selektorem (track: stable / track: canary), ale oba pasujące do wspólnego selektora Service (app: api-server): 9 replik stabilnej wersji i 1 replika canary daje w przybliżeniu 10% ruchu na nową wersję, bo Service load-balansuje między wszystkimi pasującymi Podami niezależnie od tego, który Deployment je stworzył.
Pułapka
Blue-green przy współdzielonej bazie danych wymaga, by migracja schematu była wstecznie kompatybilna: stara wersja (blue) i nowa (green) muszą poprawnie działać na tym samym schemacie w trakcie przełączania, inaczej przełączenie ruchu psuje jedną z wersji.
Blue-greenCanary
Ryzyko na start0% ruchu na nowej wersji przed przełączeniemMały procent ruchu od razu na nowej wersji
Szybkość rollbackuNatychmiastowa (przełącz selektor z powrotem)Szybka, ale wymaga też cofnięcia proporcji ruchu
Koszt infrastruktury2x zasobów przez czas przejściaNieznacznie większy (dodatkowe repliki canary)
WymaganiaLoad balancer/Service z łatwo przełączalnym targetemMożliwość precyzyjnego podziału ruchu (mesh lub proporcja replik)
  • Health checki (readiness/liveness) - bez nich orkiestrator nie wie, czy nowa wersja jest gotowa na ruch
  • Metryki błędów i latencji dostępne w czasie rzeczywistym jako podstawa decyzji o zwiększeniu ruchu canary lub rollbacku
  • Automatyczny trigger rollbacku po przekroczeniu progu błędów, nie tylko ręczna obserwacja
  • Kompatybilność wsteczna schematu bazy danych i kontraktów API między starą a nową wersją
Mnemonik
Blue-green: przełącznik światła (całość albo nic, ale masz zapasową żarówkę). Canary: kanarek w kopalni (mały sygnał ostrzegawczy, zanim zaszkodzi wszystkim).

7 · Observability: logi, metryki, trace'y

★ egzamin

Observability to zdolność zadawania systemowi pytań, których nie przewidziałeś przy jego budowie, opierając się na trzech uzupełniających się źródłach sygnału: logach, metrykach i trace'ach.

Termin kluczowy
Logi - Dyskretne, ustrukturyzowane zdarzenia z timestampem opisujące co się stało w konkretnym momencie; najbogatsze w kontekst, ale najdroższe w przechowywaniu przy wysokim wolumenie.
Termin kluczowy
Metryki - Zagregowane, numeryczne szeregi czasowe (liczniki, gauge'y, histogramy) o niskiej kardynalności; tanie w przechowywaniu, idealne do alertowania i dashboardów trendów.
Termin kluczowy
Trace'y (distributed tracing) - Ścieżka pojedynczego żądania przez wiele usług, złożona ze spanów połączonych wspólnym trace_id; kluczowe do debugowania mikroserwisów.
Ustrukturyzowany log (JSON), łatwy do parsowania i korelacji json
{"timestamp":"2026-07-05T10:32:14Z","level":"error","service":"checkout-api","trace_id":"4bf92f3577b34da6a3ce929d0e0e4736","message":"payment gateway timeout","order_id":"ord_88213"}
Prometheus: format ekspozycji metryk text
# HELP http_requests_total Total number of HTTP requests
# TYPE http_requests_total counter
http_requests_total{method="GET",status="200"} 182933
http_requests_total{method="GET",status="500"} 12

# HELP http_request_duration_seconds Histogram of request duration
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{le="0.1"} 15234
http_request_duration_seconds_bucket{le="0.5"} 18211
http_request_duration_seconds_bucket{le="+Inf"} 18220
OpenTelemetry: prosty span z atrybutem python
from opentelemetry import trace

tracer = trace.get_tracer("checkout-service")

def process_order(order_id: str) -> None:
    with tracer.start_as_current_span("process_order") as span:
        span.set_attribute("order.id", order_id)
        charge_payment(order_id)
FilarKardynalność/kosztTypowe pytanie
LogiWysoki koszt przy dużym wolumenie, bogaty kontekstCo dokładnie się stało w tym jednym żądaniu o 10:32?
MetrykiNiski koszt, niska kardynalnośćCzy p99 latencji rośnie w ostatniej godzinie?
Trace'yŚredni koszt, często samplowaneKtóra usługa w łańcuchu wywołań spowalnia to żądanie?
Pułapka
Logowanie na poziomie DEBUG w produkcji dla całego ruchu generuje koszt (storage, indeksowanie) i szum nieproporcjonalny do wartości; loguj na poziomie INFO/WARN/ERROR w produkcji, DEBUG włączaj punktowo, na żądanie.
Korelacja przez trace_id
W systemie rozproszonym pojedyncze żądanie użytkownika przechodzi przez wiele usług; trace_id propagowany w nagłówkach requestu pozwala połączyć logi i spany z każdej z tych usług w jedną spójną oś czasu.
Mnemonik
Metryki mówią CZY jest problem (dashboard, alert). Trace mówi GDZIE w łańcuchu usług. Log mówi DLACZEGO dokładnie, ze szczegółami tego jednego żądania.

8 · Świadomość kosztów w chmurze

Chmura rozlicza za zarezerwowaną pojemność, nie za realne wykorzystanie: uruchomiona instancja, przypięty wolumen czy działający load balancer kosztują identycznie, czy obsługują milion żądań, czy zero.

Idle nie znaczy darmowe
Instancja compute jest wynajęta 24/7 od momentu startu do zatrzymania/usunięcia, niezależnie od CPU utilization. To samo dotyczy load balancerów, adresów IP czy wolumenów dyskowych.
  • Nieodpięte wolumeny dyskowe (EBS/Persistent Disk) po usunięciu instancji, która ich używała
  • Środowiska dev/staging działające 24/7, mimo że są używane tylko w godzinach pracy
  • Przewymiarowane instancje wybrane 'na zapas' zamiast na podstawie realnego profilu obciążenia
  • Zapomniane zasoby testowe/PoC, których nikt nie posprzątał po zakończeniu eksperymentu
  • Nieużywane elastic/static IP przypisane, ale niepodłączone do żadnego zasobu
AWS CLI: znajdź nieodpięte (idle) wolumeny EBS bash
aws ec2 describe-volumes \
  --filters Name=status,Values=available \
  --query 'Volumes[].{ID:VolumeId,Size:Size,AZ:AvailabilityZone}' \
  --output table
Pułapka
Środowisko staging/dev pozostawione włączone na weekend czy noc to czysty koszt bez żadnej wartości: nikt go nie używa, a rachunek chmurowy nalicza się identycznie jak w godzinach pracy.
Terraform: zaplanowane skalowanie do zera poza godzinami pracy hcl
resource "aws_autoscaling_schedule" "scale_down_nightly" {
  scheduled_action_name  = "scale-down-nightly"
  autoscaling_group_name = aws_autoscaling_group.app.name
  recurrence             = "0 20 * * MON-FRI"
  min_size               = 0
  max_size               = 0
  desired_capacity       = 0
}
Autoscaling i right-sizing
Autoscaling dopasowuje liczbę instancji do realnego obciążenia w czasie rzeczywistym (skaluje w górę pod ruchem, w dół gdy ruch spada), a right-sizing dobiera typ/rozmiar instancji na podstawie faktycznego zużycia CPU/RAM zamiast domyślnego 'dużego zapasu'.
Koszt transferu danych
Transfer danych między strefami dostępności (AZ) lub regionami zwykle kosztuje osobno i bywa pomijany przy szacowaniu budżetu; architektura ignorująca lokalność danych potrafi wygenerować niepozorny, ale realny koszt sieciowy.
Mnemonik
Zasób w chmurze to jak wynajęte mieszkanie: płacisz czynsz, dopóki nie wypowiesz umowy, niezależnie od tego, czy w nim mieszkasz.
Model rozliczeniaKiedy ma sensKompromis
On-demandNieprzewidywalne/krótkotrwałe obciążenieNajwyższa cena jednostkowa, zero zobowiązań
Reserved/Savings PlanStabilne, przewidywalne obciążenie bazoweNiższa cena za zobowiązanie 1-3 lata
Spot/PreemptibleObciążenia odporne na przerwanie (batch, CI)Znacznie taniej, ale instancja może zostać odebrana
Fiszki - aktywne przypominanie

Sprawdź się - testowanie to nauka

24 pytań w losowej kolejności. Twoje wyniki zapisują się lokalnie.

Rozpocznij quiz
Zbudowane przez Tenzan Logic