Spis treści 11 sekcji
  1. CI/CD - dlaczego ręczne deploymenty to przepis na katastrofę
  2. AWS CodePipeline - natywne CI/CD w ekosystemie AWS
  3. GitHub Actions - CI/CD z ekosystemem marketplace
  4. Porównanie: CodePipeline vs GitHub Actions
  5. Koszty CI/CD - co jest tańsze?
  6. Pipeline dla statycznej strony na S3 + CloudFront
  7. Pipeline dla Lambda (serverless)
  8. Best practices CI/CD na AWS
  9. Monitoring pipeline - bo pipeline też się psuje
  10. FAQ - najczęstsze pytania o CI/CD na AWS
  11. Co dalej?
TL;DR: CodePipeline to natywne CI/CD AWS - pełna integracja, ale stroma krzywa uczenia. GitHub Actions to prostota i ekosystem marketplace, ale wymaga ręcznej konfiguracji AWS credentials. Dla małych zespołów (<5 osób) rekomendacja: GitHub Actions. Dla dużych wdrożeń AWS z wieloma środowiskami: CodePipeline. W tym artykule pokażę oba podejścia z działającymi pipeline.
Dwa sposoby, ten sam efekt: Każdy krok poniżej możesz wykonać na dwa sposoby - klikając w panelu webowym AWS albo wpisując komendy w terminalu. Wybierz jedną metodę i trzymaj się jej. Jeśli dopiero zaczynasz, polecam Panel AWS.

CI/CD - dlaczego ręczne deploymenty to przepis na katastrofę

Wyobraź sobie: piątek, 16:00. Klient prosi o pilny fix. Wchodzisz na serwer, edytujesz plik, restartujesz Apache. Działa! Do poniedziałku, gdy okazuje się, że nadpisałeś zmiany kolegi. Albo gorzej - deploy poszedł na produkcję bez testów i teraz połowa użytkowników widzi błąd 500.

CI/CD (Continuous Integration / Continuous Deployment) eliminuje te problemy:

  • CI - każdy push do repozytorium automatycznie uruchamia testy
  • CD - kod, który przejdzie testy, automatycznie trafia na serwer

Na AWS masz dwa główne podejścia: natywne narzędzia (CodePipeline + CodeBuild + CodeDeploy) lub zewnętrzne CI/CD (GitHub Actions, GitLab CI, Jenkins). Porównam dwa najpopularniejsze.

AWS CodePipeline - natywne CI/CD w ekosystemie AWS

Jak działa CodePipeline?

CodePipeline to orkiestrator pipeline, który łączy etapy w sekwencję:

  1. Source - pobiera kod z GitHub, S3, Bitbucket lub CodeCommit (uwaga: od lipca 2024 CodeCommit nie przyjmuje nowych klientów)
  2. Build - CodeBuild uruchamia testy, buduje artefakty (Docker image, ZIP)
  3. Deploy - CodeDeploy, ECS, Lambda, S3, CloudFormation wdraża kod
  4. Approval (opcjonalnie) - ręczna aprobata przed deploy na produkcję

Tworzenie pipeline w CodePipeline

  1. Wejdź w CodePipeline → Create pipeline
  2. Podaj nazwę: moja-apka-pipeline
  3. W Source wybierz GitHub (Version 2) i połącz konto GitHub
  4. Wybierz repozytorium i branch (np. main)
  5. W Build wybierz AWS CodeBuild → Create project
  6. Skonfiguruj CodeBuild: Environment Amazon Linux 2023, Runtime Standard 5.0
  7. W Buildspec wybierz Use a buildspec file (plik buildspec.yml z repozytorium)
  8. W Deploy wybierz target (np. ECS, S3, CodeDeploy)
  9. Kliknij Create pipeline - pipeline uruchomi się natychmiast
Screenshot: CodePipeline - kreator nowego pipeline z GitHub source
# 1. Utwórz rolę IAM dla CodeBuild
aws iam create-role \
  --role-name codebuild-moja-apka-role \
  --assume-role-policy-document '{
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Allow",
      "Principal": {"Service": "codebuild.amazonaws.com"},
      "Action": "sts:AssumeRole"
    }]
  }'

# 2. Dołącz polityki
aws iam attach-role-policy \
  --role-name codebuild-moja-apka-role \
  --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser

aws iam put-role-policy \
  --role-name codebuild-moja-apka-role \
  --policy-name CloudWatchLogs \
  --policy-document '{
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Allow",
      "Action": ["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],
      "Resource": "*"
    }]
  }'

# 3. Utwórz projekt CodeBuild
aws codebuild create-project \
  --name "moja-apka-build" \
  --source type=GITHUB,location=https://github.com/user/repo \
  --environment type=LINUX_CONTAINER,computeType=BUILD_GENERAL1_SMALL,image=aws/codebuild/amazonlinux2-x86_64-standard:5.0 \
  --service-role arn:aws:iam::123456789:role/codebuild-moja-apka-role \
  --artifacts type=NO_ARTIFACTS

# 4. Utwórz pipeline (wymaga pliku JSON z definicją)
aws codepipeline create-pipeline \
  --cli-input-json file://pipeline-definition.json

Plik buildspec.yml - serce CodeBuild

buildspec.yml to plik w katalogu głównym repozytorium, który mówi CodeBuild co ma robić:

# buildspec.yml - przykład dla aplikacji Node.js + Docker
version: 0.2

env:
  variables:
    ECR_REPO: 123456789.dkr.ecr.eu-central-1.amazonaws.com/moja-apka
    AWS_DEFAULT_REGION: eu-central-1

phases:
  install:
    runtime-versions:
      nodejs: 20
    commands:
      - echo "Instalacja zależności..."
      - npm ci

  pre_build:
    commands:
      - echo "Uruchamianie testów..."
      - npm test
      - echo "Logowanie do ECR..."
      - aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_REPO

  build:
    commands:
      - echo "Budowanie Docker image..."
      - docker build -t $ECR_REPO:$CODEBUILD_RESOLVED_SOURCE_VERSION .
      - docker tag $ECR_REPO:$CODEBUILD_RESOLVED_SOURCE_VERSION $ECR_REPO:latest

  post_build:
    commands:
      - echo "Pushowanie image do ECR..."
      - docker push $ECR_REPO:$CODEBUILD_RESOLVED_SOURCE_VERSION
      - docker push $ECR_REPO:latest
      - echo "Generowanie definicji ECS..."
      - printf '[{"name":"app","imageUri":"%s"}]' $ECR_REPO:$CODEBUILD_RESOLVED_SOURCE_VERSION > imagedefinitions.json

artifacts:
  files:
    - imagedefinitions.json

cache:
  paths:
    - node_modules/**/*

GitHub Actions - CI/CD z ekosystemem marketplace

Dlaczego GitHub Actions jest tak popularne?

GitHub Actions ma trzy przewagi: jest tam, gdzie już jest Twój kod (GitHub), ma ogromny marketplace gotowych actions, i konfiguracja YAML jest prostsza niż buildspec + pipeline JSON.

Konfiguracja OIDC - bezpieczne połączenie z AWS

Zanim GitHub Actions może wdrażać na AWS, musisz skonfigurować uwierzytelnianie. Zapomnij o kluczach API w secrets - w 2026 standard to OIDC (OpenID Connect):

  1. Wejdź w IAM → Identity providers → Add provider
  2. Typ: OpenID Connect
  3. Provider URL: https://token.actions.githubusercontent.com
  4. Audience: sts.amazonaws.com
  5. Kliknij Add provider
  6. Utwórz rolę IAM z trust policy:
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "Federated": "arn:aws:iam::123456789:oidc-provider/token.actions.githubusercontent.com"
    },
    "Action": "sts:AssumeRoleWithWebIdentity",
    "Condition": {
      "StringEquals": {
        "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
      },
      "StringLike": {
        "token.actions.githubusercontent.com:sub": "repo:your-org/your-repo:ref:refs/heads/main"
      }
    }
  }]
}
Screenshot: IAM Identity Provider - konfiguracja OIDC dla GitHub
# 1. Dodaj GitHub jako Identity Provider
aws iam create-open-id-connect-provider \
  --url https://token.actions.githubusercontent.com \
  --client-id-list sts.amazonaws.com \
  --thumbprint-list 6938fd4d98bab03faadb97b34396831e3780aea1
# Uwaga: od lipca 2023 AWS ignoruje thumbprint dla GitHub OIDC
# (weryfikacja przez zaufane root CA) - w nowszych wersjach CLI
# parametr jest opcjonalny i możesz go pominąć

# 2. Utwórz rolę z trust policy dla GitHub
aws iam create-role \
  --role-name github-actions-deploy \
  --assume-role-policy-document '{
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::123456789:oidc-provider/token.actions.githubusercontent.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
        },
        "StringLike": {
          "token.actions.githubusercontent.com:sub": "repo:your-org/your-repo:ref:refs/heads/main"
        }
      }
    }]
  }'

# 3. Dołącz potrzebne polityki
aws iam attach-role-policy \
  --role-name github-actions-deploy \
  --policy-arn arn:aws:iam::aws:policy/AmazonECS_FullAccess

aws iam attach-role-policy \
  --role-name github-actions-deploy \
  --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser
Bezpieczeństwo: Condition StringLike na sub ogranicza rolę do konkretnego repozytorium i brancha. Bez tego warunku każde publiczne repozytorium GitHub mogłoby assumować Twoją rolę! Więcej o bezpieczeństwie IAM.

Gotowy workflow GitHub Actions - deploy na ECS

# .github/workflows/deploy.yml
name: Deploy to AWS ECS

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

permissions:
  id-token: write   # wymagane dla OIDC
  contents: read

env:
  AWS_REGION: eu-central-1
  ECR_REPOSITORY: moja-apka
  ECS_CLUSTER: prod-cluster
  ECS_SERVICE: moja-apka-service
  ECS_TASK_DEFINITION: task-definition.json
  CONTAINER_NAME: app

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm

      - run: npm ci
      - run: npm test
      - run: npm run lint

  deploy:
    needs: test
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      # Authenticate via OIDC (no secrets needed!)
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789:role/github-actions-deploy
          aws-region: ${{ env.AWS_REGION }}

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      - name: Build, tag, and push image to ECR
        id: build-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT

      - name: Update ECS task definition
        id: task-def
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: ${{ env.ECS_TASK_DEFINITION }}
          container-name: ${{ env.CONTAINER_NAME }}
          image: ${{ steps.build-image.outputs.image }}

      - name: Deploy to ECS
        uses: aws-actions/amazon-ecs-deploy-task-definition@v2
        with:
          task-definition: ${{ steps.task-def.outputs.task-definition }}
          service: ${{ env.ECS_SERVICE }}
          cluster: ${{ env.ECS_CLUSTER }}
          wait-for-service-stability: true

Porównanie: CodePipeline vs GitHub Actions

AspektAWS CodePipelineGitHub Actions
Krzywa uczeniaStroma (IAM roles, buildspec, pipeline stages)Łagodna (YAML, marketplace actions)
Konfiguracjabuildspec.yml + pipeline JSON/ConsoleJeden plik .yml w repozytorium
Integracja z AWSNatywna - zero konfiguracji authWymaga OIDC lub access keys
MarketplaceBrak19,000+ gotowych actions
WizualizacjaPipeline view z etapamiWorkflow graph
Manual approvalWbudowane (SNS notification)Environments + protection rules
Secrets managementParameter Store / Secrets ManagerGitHub Secrets + OIDC (lepiej)
Self-hosted runnersNie (managed only)Tak (self-hosted runners)
Parallel jobsOgraniczone (parallel actions w stage)Matrix strategy + parallel jobs
CacheS3 (konfiguracja ręczna)actions/cache (jedna linia)
Vendor lock-inWysoki (wszystko w AWS)Niski (przenośne workflowy)

Koszty CI/CD - co jest tańsze?

KomponentCodePipeline + CodeBuildGitHub Actions
Pipeline/WorkflowV2 (domyślny): $0.002/min akcji, 100 min free/mc; V1: $1/pipeline/mc (1 free)Free (publiczne repo) / 2000 min/mc (prywatne)
Build minutes$0.005/min (small), $0.01/min (medium)$0.008/min (Linux) po wyczerpaniu free
100 buildów × 5 min/mc~$3.50/mc$0 (mieści się w free tier)
500 buildów × 5 min/mc~$13.50/mc~$4/mc (500 min ponad free tier × $0.008)
CodeDeployFree dla EC2/Lambda-
Artifact storageS3 ($0.023/GB)500 MB free / $0.25/GB
Oszczędność: GitHub Actions jest zazwyczaj tańszy dla małych-średnich projektów. CodePipeline wygrywa gdy już płacisz za ekosystem AWS i potrzebujesz natywnych integracji (CodeDeploy blue/green, approval gates z SNS).

Pipeline dla statycznej strony na S3 + CloudFront

Nie każdy projekt wymaga Dockera i ECS. Jeśli masz stronę statyczną (React, Next.js, Hugo), deploy na S3 + CloudFront jest prostszy i tańszy:

# .github/workflows/deploy-static.yml
name: Deploy Static Site

on:
  push:
    branches: [main]

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm

      - run: npm ci
      - run: npm run build

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789:role/github-actions-deploy
          aws-region: eu-central-1

      - name: Sync to S3
        run: |
          aws s3 sync ./dist s3://moja-strona-bucket \
            --delete \
            --cache-control "public, max-age=31536000" \
            --exclude "index.html"

          # index.html bez cache (zawsze najnowszy)
          aws s3 cp ./dist/index.html s3://moja-strona-bucket/index.html \
            --cache-control "public, max-age=0, must-revalidate"

      - name: Invalidate CloudFront cache
        run: |
          aws cloudfront create-invalidation \
            --distribution-id E1234567890 \
            --paths "/*"

Pipeline dla Lambda (serverless)

Deploy funkcji Lambda jest jeszcze prostszy:

# .github/workflows/deploy-lambda.yml
name: Deploy Lambda

on:
  push:
    branches: [main]
    paths:
      - 'src/lambda/**'  # trigger tylko gdy zmienia się kod Lambda

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789:role/github-actions-deploy
          aws-region: eu-central-1

      - name: Install dependencies & package
        run: |
          cd src/lambda
          pip install -r requirements.txt -t ./package
          cd package && zip -r ../../../function.zip .
          cd .. && zip -g ../../function.zip handler.py

      - name: Deploy to Lambda
        run: |
          aws lambda update-function-code \
            --function-name moja-funkcja \
            --zip-file fileb://function.zip \
            --publish

      - name: Wait for update
        run: |
          aws lambda wait function-updated \
            --function-name moja-funkcja
          echo "Deploy successful!"

Best practices CI/CD na AWS

1. Środowiska (environments)

Nigdy nie deployuj bezpośrednio na produkcję. Minimum to:

  • dev - deploy automatyczny po każdym pushu
  • staging - deploy automatyczny z brancha main, testy E2E
  • production - deploy po manual approval lub po merge do brancha release

2. Rollback strategy

Zawsze miej plan B:

  • ECS - rolling update z automatycznym rollbackiem (circuit breaker)
  • Lambda - versioning + alias, rollback = przestaw alias na poprzednią wersję
  • EC2 (CodeDeploy) - blue/green deployment, rollback = przełącz na starą grupę
  • S3 (statyczne) - versioning na bucket, rollback = przywróć poprzedni index.html

3. Secrets w pipeline

Jak bezpiecznie przechowywać klucze API, hasła do bazy i tokeny:

PodejścieCodePipelineGitHub Actions
Klucze AWSIAM Role (automatyczne)OIDC (rekomendowane) lub Secrets
Hasła DBSecrets Manager → CodeBuild envGitHub Secrets → env variables
API keysParameter Store (SecureString)GitHub Secrets
RotacjaAutomatyczna (Secrets Manager)Ręczna
Nigdy nie rób tego: Nie commituj kluczy AWS, haseł ani tokenów do repozytorium. Nawet jeśli repo jest prywatne. Nawet "na chwilę". Git pamięta wszystko. Przeczytaj poradnik bezpieczeństwa IAM.

Monitoring pipeline - bo pipeline też się psuje

CI/CD bez monitoringu to kolejny single point of failure. Skonfiguruj:

  • Powiadomienia o failed deployach - SNS + Slack/email
  • Metryki pipeline - czas budowania, success rate, częstotliwość deployów
  • Post-deploy health checks - po deployu sprawdź czy aplikacja odpowiada HTTP 200

Konfigurację monitoringu opisałem szczegółowo w poradniku CloudWatch i X-Ray.

# Post-deploy health check w GitHub Actions
- name: Health check
  run: |
    for i in {1..10}; do
      STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://moja-apka.pl/health)
      if [ "$STATUS" = "200" ]; then
        echo "Health check passed!"
        exit 0
      fi
      echo "Attempt $i: HTTP $STATUS, retrying in 15s..."
      sleep 15
    done
    echo "Health check failed after 10 attempts!"
    exit 1

FAQ - najczęstsze pytania o CI/CD na AWS

Czy mogę użyć GitHub Actions z CodeDeploy?

Tak! To popularne combo. GitHub Actions buduje i testuje kod, a CodeDeploy obsługuje deployment (blue/green, rolling). AWS nie publikuje oficjalnego action do CodeDeploy - po uwierzytelnieniu przez configure-aws-credentials wywołaj w kroku workflow AWS CLI: aws deploy create-deployment. Dostajesz prostotę GitHub + zaawansowane strategie deploymentu AWS.

Ile pipeline mogę mieć w CodePipeline za darmo?

Zależy od typu. Nowe pipeline to domyślnie typ V2 - płacisz $0.002 za minutę wykonania akcji, a Free Tier daje 100 darmowych minut akcji miesięcznie na całe konto (reset co miesiąc). Starszy typ V1 to $1/mc za aktywny pipeline, pierwszy za darmo; nieaktywny pipeline V1 nie generuje kosztów.

Co jest bezpieczniejsze - OIDC czy AWS Access Keys w GitHub Secrets?

OIDC jest zdecydowanie bezpieczniejsze. Access Keys to stałe credentials - jeśli wyciekną, atakujący ma dostęp do końca. OIDC generuje tymczasowe tokeny (15 min-1h) ograniczone do konkretnego repo i brancha. W 2026 nie ma powodu używać access keys w CI/CD.

Jak zrobić deploy na wiele środowisk (dev/staging/prod)?

W GitHub Actions: użyj environments z protection rules. Dev deployuje się automatycznie, staging po merge do main, produkcja po manual approval. W CodePipeline: dodaj Manual Approval stage między staging a production, z powiadomieniem SNS do odpowiedniej osoby.

Czy warto używać Terraform w pipeline CI/CD?

Absolutnie tak! Infrastructure as Code w pipeline to gold standard. Pipeline uruchamia terraform plan na PR (jako komentarz), a terraform apply po merge. Opisałem to dokładniej w artykule o Terraform + AWS.

Co dalej?

  1. Wybierz podejście: GitHub Actions (prostsze) lub CodePipeline (natywne AWS).
  2. Skonfiguruj OIDC dla GitHub Actions lub rolę IAM dla CodePipeline.
  3. Zacznij od prostego pipeline (test → deploy na dev) i rozbudowuj stopniowo.
  4. Dodaj manual approval gate przed produkcją.
  5. Skonfiguruj monitoring i alarmy na pipeline failures.

CI/CD to inwestycja, która zwraca się przy pierwszym "hotfixie w piątek o 17:00". Zamiast stresu i ręcznych kroków - jeden merge i pipeline robi resztę. Jeśli dopiero zaczynasz z AWS, sprawdź najpierw co jest za darmo w AWS Free Tier. A jeśli planujesz pełną architekturę - przeczytaj o architekturze aplikacji webowej na AWS.

Emil Kowalczyk

Pasjonat chmury i twórca CloudManiak.pl. Na co dzień MSP Engineer w amerykańskiej firmie ClearScale (AWS Premier Tier Partner). Pomagam osobom wchodzącym do świata chmury zdobywać wiedzę i certyfikaty.