CI/CD - Pytania Rekrutacyjne dla DevOps Engineer [2026]

Sławomir Plamowski 21 min czytania
automatyzacja cicd deployment devops github-actions gitlab-ci jenkins pytania-rekrutacyjne

CI/CD to serce każdego nowoczesnego procesu wytwarzania oprogramowania. Na rozmowie DevOps rekruterzy sprawdzają nie tylko znajomość konkretnych narzędzi (GitHub Actions, GitLab CI, Jenkins), ale przede wszystkim zrozumienie zasad automatyzacji, strategii deploymentu i best practices. Ten przewodnik zawiera 60+ pytań rekrutacyjnych z odpowiedziami, które pomogą Ci przygotować się do rozmowy.

Podstawy CI/CD

Czym różni się Continuous Integration od Continuous Delivery i Continuous Deployment?

Odpowiedź w 30 sekund:

  • CI (Continuous Integration) - automatyczne budowanie i testowanie każdej zmiany
  • Continuous Delivery - automatyczne przygotowanie do deploymentu, ale manual approval przed produkcją
  • Continuous Deployment - pełna automatyzacja, każda zmiana przechodzi od commit do produkcji bez interwencji

Odpowiedź w 2 minuty:

Najlepiej zobrazować różnice na schemacie przepływu pracy:

CI (Continuous Integration):
commit → build → test → ✅ merge to main

Continuous Delivery:
commit → build → test → deploy staging → 🔘 manual approval → deploy prod

Continuous Deployment:
commit → build → test → deploy staging → auto tests → deploy prod

Continuous Delivery jest bezpieczniejsze - masz kontrolę przed produkcją. Continuous Deployment wymaga dojrzałych testów i monitoringu, ale przyspiesza delivery.


Jakie są główne korzyści z implementacji CI/CD?

Odpowiedź w 30 sekund:

  1. Szybsze wykrywanie błędów - feedback w minutach, nie dniach
  2. Mniejsze ryzyko wdrożeń - małe, częste zmiany zamiast wielkich release'ów
  3. Krótszy time-to-market - od commit do produkcji w godzinach
  4. Lepsza jakość kodu - automatyczne testy i review

Odpowiedź w 2 minuty:

Bez CI/CD typowy deployment wygląda tak: developer kończy feature, czeka na QA, QA testuje manualnie, deployment w piątek wieczorem, weekend on-call. Z CI/CD: merge to main → automatyczne testy → deploy staging → smoke tests → deploy prod. Całość zajmuje minuty.

Dodatkowe korzyści:

  • Reproducibility - każdy build jest deterministyczny
  • Visibility - wszyscy widzą status pipeline
  • Documentation - pipeline jako kod dokumentuje proces
  • Confidence - deweloperzy nie boją się deployować

Co to jest pipeline CI/CD i z jakich etapów się składa?

Odpowiedź w 30 sekund:

Pipeline to zdefiniowany przepływ pracy wykonywany automatycznie. Typowe etapy:

  1. Source - checkout kodu
  2. Build - kompilacja, bundling
  3. Test - unit, integration, e2e
  4. Security - SAST, dependency scan
  5. Deploy - staging, production

Odpowiedź w 2 minuty:

Poniżej znajduje się typowa struktura pipeline z wszystkimi kluczowymi etapami:

# Przykład struktury pipeline
stages:
  - build        # kompilacja, tworzenie artefaktów
  - test         # testy jednostkowe, integracyjne
  - security     # skanowanie bezpieczeństwa
  - deploy-stg   # deployment na staging
  - e2e          # testy end-to-end
  - deploy-prod  # deployment na produkcję

Każdy stage może mieć wiele jobs wykonywanych równolegle. Pipeline jest triggerowany przez:

  • Push do branch
  • Pull request
  • Schedule (cron)
  • Manual trigger
  • External webhook

Artefakty są przekazywane między stages. Pipeline kończy się sukcesem tylko gdy wszystkie kroki przejdą.


Czym są artefakty w kontekście CI/CD?

Odpowiedź w 30 sekund:

Artefakty to pliki wygenerowane podczas pipeline, które są:

  • Przekazywane między stages (build output → test input)
  • Archiwizowane do późniejszego użycia (Docker image, package)
  • Dostępne do pobrania (test reports, coverage)

Odpowiedź w 2 minuty:

Oto przykład jak w GitHub Actions przekazujemy artefakty między job'ami:

# GitHub Actions
- name: Build
  run: npm run build
- uses: actions/upload-artifact@v4
  with:
    name: dist
    path: dist/

# W następnym job
- uses: actions/download-artifact@v4
  with:
    name: dist

Typowe artefakty:

  • Docker images (pushowane do registry)
  • Pakiety npm/Maven/NuGet
  • Raporty testów i coverage
  • Binaries i executables
  • Deployment manifests

Dobre praktyki:

  • Ustawiaj retention period (nie przechowuj w nieskończoność)
  • Taguj artefakty wersją/commit SHA
  • Używaj immutable storage (Docker registry, S3)

GitHub Actions

Wyjaśnij strukturę workflow GitHub Actions

Odpowiedź w 30 sekund:

name: CI Pipeline
on: [push, pull_request]    # triggers

jobs:
  build:                     # job name
    runs-on: ubuntu-latest   # runner
    steps:                   # kroki w job
      - uses: actions/checkout@v4
      - run: npm install

Odpowiedź w 2 minuty:

Poniżej pełny przykład workflow pokazujący wszystkie kluczowe elementy:

name: Complete CI/CD Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]
  workflow_dispatch:         # manual trigger

env:
  NODE_VERSION: '20'         # global env

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node: [18, 20]       # matrix build
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm ci
      - run: npm test

  build:
    needs: test              # dependency
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm run build
      - uses: actions/upload-artifact@v4
        with:
          name: build
          path: dist/

  deploy:
    needs: build
    if: github.ref == 'refs/heads/main'  # condition
    runs-on: ubuntu-latest
    environment: production   # protected env
    steps:
      - run: echo "Deploying..."

Kluczowe koncepty:

  • Workflow - cały plik YAML
  • Job - zbiór steps na jednym runnerze
  • Step - pojedyncza akcja lub komenda
  • Action - reusable unit (marketplace lub custom)

Jak działają GitHub Actions runners i jakie są różnice między hosted a self-hosted?

Odpowiedź w 30 sekund:

  • GitHub-hosted - zarządzane przez GitHub, czyste VM, płacisz za minuty
  • Self-hosted - Twoja infrastruktura, pełna kontrola, bez limitów

Odpowiedź w 2 minuty:

Porównanie obu opcji w praktyce:

Aspekt GitHub-hosted Self-hosted
Setup Zero Wymaga instalacji
Maintenance GitHub Ty
Cost Per minute Twoja infra
Clean env Każdy run Opcjonalnie
Hardware Standardowe Custom
Network Public Prywatna sieć
# GitHub-hosted
runs-on: ubuntu-latest
runs-on: windows-2022
runs-on: macos-14

# Self-hosted
runs-on: self-hosted
runs-on: [self-hosted, linux, gpu]  # labels

Kiedy self-hosted:

  • Potrzebujesz dostępu do prywatnej sieci
  • Custom hardware (GPU, ARM)
  • Duże repo/artifacts (limity bandwidth)
  • Compliance/security requirements
  • Cost optimization przy dużym użyciu

Jak zarządzać sekretami w GitHub Actions?

Odpowiedź w 30 sekund:

steps:
  - run: docker login -u ${{ secrets.DOCKER_USER }} -p ${{ secrets.DOCKER_TOKEN }}

Sekrety definiujesz w Settings → Secrets → Actions. Są maskowane w logach.

Odpowiedź w 2 minuty:

GitHub oferuje trzy poziomy sekretów z różnym zakresem dostępu:

  1. Repository secrets - dostępne tylko w tym repo
  2. Environment secrets - dostępne tylko w określonym environment
  3. Organization secrets - współdzielone między repos
jobs:
  deploy:
    environment: production  # wymaga approval
    steps:
      - run: |
          echo "Using ${{ secrets.PROD_API_KEY }}"

Best practices:

  • Używaj environment protection rules dla prod
  • OIDC zamiast long-lived tokens do cloud:
- uses: aws-actions/configure-aws-credentials@v4
  with:
    role-to-assume: arn:aws:iam::123456:role/GitHubActions
    aws-region: eu-west-1
  • Rotuj sekrety regularnie
  • Nigdy nie loguj sekretów (są automatycznie maskowane, ale uważaj z base64)

Jak zrobić cache dependencies w GitHub Actions?

Odpowiedź w 30 sekund:

- uses: actions/cache@v4
  with:
    path: ~/.npm
    key: npm-${{ hashFiles('package-lock.json') }}

Cache przyspiesza build poprzez przechowywanie zależności między runami.

Odpowiedź w 2 minuty:

Oto różne strategie cache w GitHub Actions, od najprostszej do zaawansowanej:

# npm z automatycznym cache
- uses: actions/setup-node@v4
  with:
    node-version: '20'
    cache: 'npm'  # automatyczny cache

# Manual cache z restore-keys
- uses: actions/cache@v4
  with:
    path: |
      ~/.npm
      node_modules
    key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      npm-${{ runner.os }}-
      npm-

# Docker layer cache
- uses: docker/build-push-action@v5
  with:
    cache-from: type=gha
    cache-to: type=gha,mode=max

Strategia cache:

  • key - exact match
  • restore-keys - fallback prefix match
  • Cache jest per-branch, ale PR może używać cache z base branch

Limity:

  • 10 GB per repo
  • Cache niewykorzystany przez 7 dni jest usuwany

Jak uruchomić jobs równolegle i jak zdefiniować zależności między nimi?

Odpowiedź w 30 sekund:

jobs:
  test:
    runs-on: ubuntu-latest
  lint:
    runs-on: ubuntu-latest
  # test i lint równolegle

  build:
    needs: [test, lint]  # czeka na oba

Odpowiedź w 2 minuty:

Przykład pipeline z testami równoległymi i zależnościami między stages:

jobs:
  unit-tests:
    runs-on: ubuntu-latest
    steps:
      - run: npm test

  integration-tests:
    runs-on: ubuntu-latest
    steps:
      - run: npm run test:integration

  e2e-tests:
    runs-on: ubuntu-latest
    steps:
      - run: npm run test:e2e

  build:
    needs: [unit-tests, integration-tests, e2e-tests]
    runs-on: ubuntu-latest
    steps:
      - run: npm run build

  deploy-staging:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: deploy-staging.sh

  deploy-prod:
    needs: deploy-staging
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - run: deploy-prod.sh

Kluczowe:

  • Jobs bez needs uruchamiają się równolegle
  • needs: [a, b] czeka na wszystkie
  • Można przekazywać outputs między jobs
  • if: failure() - uruchom gdy poprzedni failed
  • if: always() - uruchom zawsze

Co to jest matrix strategy i kiedy jej używać?

Odpowiedź w 30 sekund:

Matrix tworzy wiele wariantów job'a z różnymi kombinacjami parametrów:

strategy:
  matrix:
    node: [18, 20, 22]
    os: [ubuntu-latest, windows-latest]
# = 6 jobów

Odpowiedź w 2 minuty:

Zaawansowany przykład matrix z exclude, include i kontynuacją po błędzie:

jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false  # kontynuuj pozostałe gdy jeden fail
      max-parallel: 4   # limit równoległości
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        node: [18, 20]
        include:
          - os: ubuntu-latest
            node: 22
            experimental: true
        exclude:
          - os: macos-latest
            node: 18
    steps:
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm test
        continue-on-error: ${{ matrix.experimental }}

Przypadki użycia:

  • Testowanie na wielu wersjach Node/Python/Java
  • Cross-platform builds (Linux, Windows, macOS)
  • Testowanie z różnymi bazami danych
  • Różne konfiguracje (z feature flag, bez)

GitLab CI

Wyjaśnij strukturę .gitlab-ci.yml

Odpowiedź w 30 sekund:

stages:
  - build
  - test
  - deploy

build-job:
  stage: build
  script:
    - npm install
    - npm run build

Odpowiedź w 2 minuty:

Kompletny przykład konfiguracji GitLab CI z globalnymi ustawieniami i wszystkimi etapami:

# Global configuration
default:
  image: node:20
  before_script:
    - npm ci

variables:
  NODE_ENV: production

stages:
  - build
  - test
  - deploy

# Jobs
build:
  stage: build
  script:
    - npm run build
  artifacts:
    paths:
      - dist/
    expire_in: 1 week

test:
  stage: test
  script:
    - npm test
  coverage: '/Coverage: \d+\.\d+%/'

deploy-staging:
  stage: deploy
  environment:
    name: staging
    url: https://staging.example.com
  script:
    - deploy.sh staging
  only:
    - develop

deploy-prod:
  stage: deploy
  environment:
    name: production
    url: https://example.com
  script:
    - deploy.sh production
  only:
    - main
  when: manual  # requires click

Kluczowe różnice vs GitHub Actions:

  • stages definiowane globalnie
  • only/except zamiast on
  • when: manual dla approval
  • Wbudowane Auto DevOps

Jak działają GitLab Runners i jak je skonfigurować?

Odpowiedź w 30 sekund:

GitLab Runners wykonują jobs. Typy:

  • Shared runners - dostarczane przez GitLab
  • Group runners - dla grupy projektów
  • Project runners - dedykowane dla projektu

Odpowiedź w 2 minuty:

Proces instalacji i konfiguracji self-hosted runnera w GitLab:

# Instalacja self-hosted runner
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
sudo apt install gitlab-runner

# Rejestracja
sudo gitlab-runner register \
  --url https://gitlab.com \
  --registration-token $TOKEN \
  --executor docker \
  --docker-image node:20

Executors:

  • Shell - bezpośrednio na hoście
  • Docker - każdy job w kontenerze
  • Kubernetes - job jako Pod
  • Docker Machine - auto-scaling
# Wybór runnera przez tagi
deploy:
  tags:
    - production
    - aws
  script:
    - deploy.sh

Best practices:

  • Docker executor dla izolacji
  • Tagi do routingu jobs
  • Autoscaling dla zmiennego load

Jak używać cache i artifacts w GitLab CI?

Odpowiedź w 30 sekund:

  • Cache - przyspiesza jobs (dependencies)
  • Artifacts - przekazuje pliki między stages
cache:
  paths:
    - node_modules/

artifacts:
  paths:
    - dist/

Odpowiedź w 2 minuty:

Przykłady konfiguracji cache i artifacts w GitLab CI pokazujące różne strategie:

# Cache per-branch
cache:
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - node_modules/
  policy: pull-push  # lub pull, push

# Artifacts między stages
build:
  stage: build
  script:
    - npm run build
  artifacts:
    paths:
      - dist/
    expire_in: 1 hour

test:
  stage: test
  dependencies:
    - build  # pobiera artifacts z build
  script:
    - npm test -- --coverage
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura.xml

Różnice:

Aspekt Cache Artifacts
Cel Speedup Data passing
Dostępność Ten sam job Między jobs
Retention LRU expire_in
Download Automatyczny Opcjonalny

Co to jest GitLab Auto DevOps?

Odpowiedź w 30 sekund:

Auto DevOps to predefiniowany pipeline, który automatycznie:

  • Builduje aplikację (autodetect języka)
  • Uruchamia testy
  • Skanuje bezpieczeństwo
  • Deployuje do Kubernetes

Odpowiedź w 2 minuty:

Auto DevOps można włączyć na dwa sposoby - przez konfigurację lub ustawienia projektu:

# .gitlab-ci.yml
include:
  - template: Auto-DevOps.gitlab-ci.yml

Albo w Settings → CI/CD → Auto DevOps.

Co zawiera:

  • Auto Build - buduje Docker image
  • Auto Test - uruchamia testy (Herokuish)
  • Auto Code Quality - Code Climate
  • Auto SAST - Static security testing
  • Auto Dependency Scanning - CVE check
  • Auto Container Scanning - skan obrazu
  • Auto Review Apps - preview per MR
  • Auto Deploy - do Kubernetes

Customizacja:

variables:
  AUTO_DEVOPS_BUILD_IMAGE_CNB_ENABLED: "true"
  POSTGRES_ENABLED: "true"
  TEST_DISABLED: "true"  # wyłącz testy

Dobre dla: szybki start, standardowe aplikacje Złe dla: custom workflows, nietypowe stacki


Jenkins

Wyjaśnij różnicę między Declarative i Scripted Pipeline w Jenkins

Odpowiedź w 30 sekund:

  • Declarative - prostszy, strukturalny, recommended
  • Scripted - pełna moc Groovy, legacy
// Declarative
pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh 'npm build'
            }
        }
    }
}

Odpowiedź w 2 minuty:

Oto kompletny przykład obu stylów pipeline w porównaniu:

// Declarative Pipeline (recommended)
pipeline {
    agent any

    environment {
        NODE_ENV = 'production'
    }

    stages {
        stage('Build') {
            steps {
                sh 'npm ci'
                sh 'npm run build'
            }
        }
        stage('Test') {
            parallel {
                stage('Unit') {
                    steps { sh 'npm test' }
                }
                stage('E2E') {
                    steps { sh 'npm run e2e' }
                }
            }
        }
        stage('Deploy') {
            when {
                branch 'main'
            }
            steps {
                sh './deploy.sh'
            }
        }
    }

    post {
        always { cleanWs() }
        failure { slackSend "Build failed!" }
    }
}
// Scripted Pipeline (Groovy)
node {
    stage('Build') {
        checkout scm
        sh 'npm ci'
        sh 'npm run build'
    }

    stage('Test') {
        try {
            sh 'npm test'
        } catch (e) {
            currentBuild.result = 'UNSTABLE'
        }
    }

    if (env.BRANCH_NAME == 'main') {
        stage('Deploy') {
            sh './deploy.sh'
        }
    }
}

Różnice:

  • Declarative ma walidację składni
  • Scripted daje pełną kontrolę (pętle, warunki)
  • Declarative: when {}, Scripted: if {}

Jak zarządzać credentials w Jenkins?

Odpowiedź w 30 sekund:

pipeline {
    environment {
        DOCKER_CREDS = credentials('docker-hub')
    }
    stages {
        stage('Push') {
            steps {
                sh 'docker login -u $DOCKER_CREDS_USR -p $DOCKER_CREDS_PSW'
            }
        }
    }
}

Odpowiedź w 2 minuty:

Jenkins obsługuje pięć głównych typów credentials dla różnych zastosowań:

  • Username/Password
  • Secret text
  • Secret file
  • SSH key
  • Certificate
// W pipeline
pipeline {
    stages {
        stage('Deploy') {
            steps {
                withCredentials([
                    usernamePassword(
                        credentialsId: 'aws-creds',
                        usernameVariable: 'AWS_ACCESS_KEY',
                        passwordVariable: 'AWS_SECRET_KEY'
                    ),
                    string(
                        credentialsId: 'slack-token',
                        variable: 'SLACK_TOKEN'
                    ),
                    file(
                        credentialsId: 'kubeconfig',
                        variable: 'KUBECONFIG'
                    )
                ]) {
                    sh 'kubectl apply -f deployment.yaml'
                }
            }
        }
    }
}

Zarządzanie:

  • Manage Jenkins → Credentials
  • Folders dla izolacji
  • Credentials Binding Plugin
  • HashiCorp Vault plugin dla external secrets

Co to jest Jenkins Shared Library?

Odpowiedź w 30 sekund:

Shared Library to reusable Groovy code współdzielony między pipelines:

@Library('my-shared-lib') _

pipeline {
    stages {
        stage('Deploy') {
            steps {
                deployToKubernetes(env: 'production')
            }
        }
    }
}

Odpowiedź w 2 minuty:

Shared Library ma określoną strukturę katalogów z trzema głównymi folderami:

(root)
├── vars/
│   └── deployToKubernetes.groovy
├── src/
│   └── org/example/Utils.groovy
└── resources/
    └── templates/deployment.yaml
// vars/deployToKubernetes.groovy
def call(Map config = [:]) {
    def env = config.env ?: 'staging'

    sh """
        kubectl config use-context ${env}
        kubectl apply -f k8s/
    """
}

Konfiguracja:

  • Manage Jenkins → Configure System → Global Pipeline Libraries
  • Lub w Jenkinsfile: @Library('lib@main')

Korzyści:

  • DRY - jedna definicja, wiele pipelines
  • Wersjonowanie (tag/branch)
  • Testowanie biblioteki osobno
  • Standaryzacja praktyk w organizacji

Strategie Deploymentu

Wyjaśnij różnice między Rolling, Blue-Green i Canary deployment

Odpowiedź w 30 sekund:

Strategia Opis Rollback
Rolling Stopniowa wymiana instancji Wolny
Blue-Green Dwa środowiska, switch Instant
Canary % ruchu na nową wersję Szybki

Odpowiedź w 2 minuty:

Zobaczmy każdą strategię na przykładach, zaczynając od Rolling Update:

Rolling Update:

t0: [v1] [v1] [v1] [v1]
t1: [v2] [v1] [v1] [v1]
t2: [v2] [v2] [v1] [v1]
t3: [v2] [v2] [v2] [v1]
t4: [v2] [v2] [v2] [v2]
# Kubernetes
strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 1
    maxUnavailable: 0

Blue-Green:

Blue (active):  [v1] [v1] [v1] ← traffic
Green (idle):   [v2] [v2] [v2]

# switch
Blue (idle):    [v1] [v1] [v1]
Green (active): [v2] [v2] [v2] ← traffic

Wymaga podwójnych zasobów, ale instant rollback.

Canary:

t0: 100% → [v1] [v1] [v1] [v1]
t1:  90% → [v1] [v1] [v1]
     10% → [v2]
t2:  50% → [v1] [v1]
     50% → [v2] [v2]
t3: 100% → [v2] [v2] [v2] [v2]
# Istio VirtualService
http:
  - route:
    - destination:
        host: myapp
        subset: v1
      weight: 90
    - destination:
        host: myapp
        subset: v2
      weight: 10

Wybór:

  • Rolling: prosty, domyślny
  • Blue-Green: krytyczne systemy, instant rollback
  • Canary: testowanie na produkcji, feature flags

Jak zaimplementować Blue-Green deployment?

Odpowiedź w 30 sekund:

  1. Masz dwa identyczne środowiska (Blue i Green)
  2. Blue jest active, Green idle
  3. Deploy nowej wersji na Green
  4. Testuj Green
  5. Switch traffic na Green
  6. Blue staje się idle (backup)

Odpowiedź w 2 minuty:

Implementacja Blue-Green w Kubernetes wykorzystuje dwa deployment i przełączanie Service selector:

# Kubernetes z Service selector
# blue-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-blue
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      version: blue
  template:
    metadata:
      labels:
        app: myapp
        version: blue
# ...

# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  selector:
    app: myapp
    version: blue  # ← switch to green
  ports:
    - port: 80
# Deploy green
kubectl apply -f green-deployment.yaml

# Test green
kubectl run test --rm -it --image=curlimages/curl -- curl http://app-green

# Switch traffic
kubectl patch service myapp -p '{"spec":{"selector":{"version":"green"}}}'

# Rollback if needed
kubectl patch service myapp -p '{"spec":{"selector":{"version":"blue"}}}'

Z AWS ALB:

# Zmień target group weight
aws elbv2 modify-listener --listener-arn $ARN \
  --default-actions Type=forward,ForwardConfig='{
    "TargetGroups": [
      {"TargetGroupArn": "'$GREEN_TG'", "Weight": 100},
      {"TargetGroupArn": "'$BLUE_TG'", "Weight": 0}
    ]
  }'

Jak zaimplementować Canary deployment?

Odpowiedź w 30 sekund:

Canary to stopniowe kierowanie coraz większego % ruchu na nową wersję, monitorując metryki. Przy problemach - rollback.

Odpowiedź w 2 minuty:

Canary deployment z Istio pozwala kontrolować routing ruchu między wersjami aplikacji:

# Z Istio
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: myapp
spec:
  hosts:
    - myapp
  http:
    - route:
        - destination:
            host: myapp
            subset: stable
          weight: 90
        - destination:
            host: myapp
            subset: canary
          weight: 10

---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: myapp
spec:
  host: myapp
  subsets:
    - name: stable
      labels:
        version: v1
    - name: canary
      labels:
        version: v2

Automatyczny Canary z Flagger:

apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: myapp
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myapp
  progressDeadlineSeconds: 600
  service:
    port: 80
  analysis:
    interval: 1m
    threshold: 5
    maxWeight: 50
    stepWeight: 10
    metrics:
      - name: request-success-rate
        threshold: 99
      - name: request-duration
        threshold: 500

Flagger automatycznie:

  • Zwiększa traffic co 1 min o 10%
  • Monitoruje success rate i latency
  • Rollback gdy metryki poniżej threshold

Co to jest GitOps i jak się różni od tradycyjnego CI/CD?

Odpowiedź w 30 sekund:

GitOps to praktyka gdzie Git jest single source of truth dla infrastruktury. Operator (ArgoCD, Flux) ciągle synchronizuje klaster z repozytorium.

Odpowiedź w 2 minuty:

Porównajmy oba podejścia na schematach przepływu deploymentu:

Traditional CI/CD (Push):
Code repo → CI build → CI push → Deploy to cluster
                         ↓
                    CD pushuje

GitOps (Pull):
Code repo → CI build → Push to config repo
                              ↓
Config repo ← ArgoCD pulls ← Cluster

Kluczowe różnice:

Aspekt Traditional GitOps
Trigger CI push Git commit
State Cluster Git repo
Rollback Re-deploy Git revert
Audit CI logs Git history
Access CI needs kubectl Operator only

ArgoCD example:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp
spec:
  source:
    repoURL: https://github.com/org/config
    path: apps/myapp
    targetRevision: HEAD
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Korzyści GitOps:

  • Git jako audit log
  • Declarative, reproducible
  • Mniejsza powierzchnia ataku (operator wewnątrz klastra)
  • Łatwiejszy rollback (git revert)

Security w CI/CD

Jak skanować bezpieczeństwo w pipeline CI/CD?

Odpowiedź w 30 sekund:

Typy skanowania:

  • SAST - Static Application Security Testing (kod)
  • DAST - Dynamic Testing (running app)
  • Dependency scanning - CVE w bibliotekach
  • Container scanning - CVE w obrazach

Odpowiedź w 2 minuty:

Kompletny pipeline security scanningów w GitHub Actions obejmuje cztery rodzaje testów:

# GitHub Actions z security scanning
name: Security Pipeline

on: [push, pull_request]

jobs:
  sast:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Semgrep SAST
        uses: semgrep/semgrep-action@v1
        with:
          config: auto

  dependency-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: npm audit
        run: npm audit --audit-level=high
      - name: Snyk check
        uses: snyk/actions/node@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

  container-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build image
        run: docker build -t myapp:${{ github.sha }} .
      - name: Trivy scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: myapp:${{ github.sha }}
          exit-code: '1'
          severity: 'HIGH,CRITICAL'

  secrets-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Gitleaks
        uses: gitleaks/gitleaks-action@v2

Best practices:

  • Fail pipeline przy HIGH/CRITICAL
  • Scan na każdy PR (shift left)
  • Regularny scan produkcji
  • Integracja z ticket system

Jak bezpiecznie przechowywać i używać sekretów w CI/CD?

Odpowiedź w 30 sekund:

  1. Nigdy w kodzie
  2. Używaj wbudowanych secret managers (GitHub Secrets, GitLab CI Variables)
  3. Dla zaawansowanych: HashiCorp Vault, AWS Secrets Manager
  4. OIDC zamiast long-lived credentials

Odpowiedź w 2 minuty:

Najlepszą praktyką jest używanie OIDC zamiast long-lived credentials - oto przykład dla AWS:

# GitHub Actions + OIDC (bez sekretów!)
jobs:
  deploy:
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456:role/GitHubActionsRole
          aws-region: eu-west-1
      # Teraz masz AWS credentials bez żadnych sekretów!

HashiCorp Vault:

steps:
  - uses: hashicorp/vault-action@v2
    with:
      url: https://vault.example.com
      method: jwt
      role: ci-role
      secrets: |
        secret/data/prod DB_PASSWORD | DB_PASSWORD
  - run: psql -h db -U app -c "SELECT 1"
    env:
      PGPASSWORD: ${{ steps.vault.outputs.DB_PASSWORD }}

Zasady:

  • Minimalne uprawnienia (least privilege)
  • Krótki czas życia tokenów
  • Rotacja sekretów
  • Audit log dostępu
  • Osobne sekrety per environment
  • Masked w logach

Jak zabezpieczyć deployment na produkcję?

Odpowiedź w 30 sekund:

  1. Protected branches
  2. Required reviews
  3. Environment protection rules
  4. Manual approval gates
  5. Deployment windows

Odpowiedź w 2 minuty:

W GitHub Actions używamy protected environments z approval gates dla deploymentów produkcyjnych:

# GitHub Actions - protected environment
jobs:
  deploy-prod:
    environment:
      name: production
      url: https://example.com
    steps:
      - run: deploy.sh

GitHub Environment protection:

  • Required reviewers
  • Wait timer (e.g., 30 min delay)
  • Deployment branches (only main)

GitLab:

deploy-prod:
  stage: deploy
  environment:
    name: production
  when: manual
  only:
    - main
  allow_failure: false

Protected environments w GitLab:

  • Settings → CI/CD → Protected Environments
  • Wymagaj approval od maintainers

Dodatkowe zabezpieczenia:

  • Deployment windows (nie w piątek!)
  • Feature flags dla gradual rollout
  • Automated rollback przy alertach
  • Smoke tests po deployment
  • Canary analysis przed full rollout

Troubleshooting i Best Practices

Pipeline jest wolny - jak go przyspieszyć?

Odpowiedź w 30 sekund:

  1. Cache dependencies
  2. Parallel jobs
  3. Skip unnecessary steps
  4. Smaller Docker images
  5. Selective triggers

Odpowiedź w 2 minuty:

Oto pięć konkretnych technik optymalizacji pipeline z przykładami kodu:

# 1. Aggressive caching
- uses: actions/cache@v4
  with:
    path: |
      ~/.npm
      ~/.cache
      node_modules
    key: deps-${{ hashFiles('**/package-lock.json') }}

# 2. Parallelization
jobs:
  test:
    strategy:
      matrix:
        shard: [1, 2, 3, 4]
    steps:
      - run: npm test -- --shard=${{ matrix.shard }}/4

# 3. Conditional execution
on:
  push:
    paths:
      - 'src/**'
      - 'tests/**'
    paths-ignore:
      - '*.md'
      - 'docs/**'

# 4. Skip CI for docs
# [skip ci] w commit message

# 5. Smaller images
FROM node:20-alpine  # zamiast node:20

# 6. Docker layer cache
- uses: docker/build-push-action@v5
  with:
    cache-from: type=gha
    cache-to: type=gha,mode=max

Metryki do monitorowania:

  • Total pipeline time
  • Time per stage
  • Queue wait time
  • Cache hit rate

Jak debugować failing pipeline?

Odpowiedź w 30 sekund:

  1. Czytaj logi (od końca!)
  2. Sprawdź exit codes
  3. Reprodukuj lokalnie
  4. SSH do runner (jeśli dostępne)
  5. Dodaj debug output

Odpowiedź w 2 minuty:

Techniki debugowania pipeline w GitHub Actions z pełnym logowaniem i możliwością SSH:

# GitHub Actions debug
env:
  ACTIONS_STEP_DEBUG: true
  ACTIONS_RUNNER_DEBUG: true

# Verbose output
steps:
  - run: |
      set -x  # bash debug mode
      npm test 2>&1 | tee test.log
  - uses: actions/upload-artifact@v4
    if: failure()
    with:
      name: logs
      path: test.log

# Tmate for SSH access
- uses: mxschmitt/action-tmate@v3
  if: failure()

GitLab:

test:
  script:
    - npm test
  after_script:
    - cat npm-debug.log || true
  artifacts:
    when: on_failure
    paths:
      - npm-debug.log

Checklist:

  1. Czy działa lokalnie?
  2. Czy dependencies są aktualne?
  3. Czy environment variables ustawione?
  4. Czy secrets nie wygasły?
  5. Czy runner ma dostęp do external services?
  6. Czy jest rate limiting?

Jakie są best practices dla pipeline CI/CD?

Odpowiedź w 30 sekund:

  1. Fast feedback (fail fast)
  2. Reproducible builds
  3. Security scanning
  4. Infrastructure as Code
  5. Monitoring i alerting

Odpowiedź w 2 minuty:

Poniżej kompletny przykład pipeline implementujący wszystkie kluczowe best practices:

# Best practices in action
name: Production Pipeline

on:
  push:
    branches: [main]

env:
  # Pin versions
  NODE_VERSION: '20.10.0'
  DOCKER_BUILDKIT: 1

jobs:
  # 1. Fast feedback - lint first
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm run lint

  # 2. Parallel tests
  test:
    needs: lint  # fail fast
    strategy:
      fail-fast: true
      matrix:
        shard: [1, 2, 3]
    steps:
      - run: npm test -- --shard=${{ matrix.shard }}/3

  # 3. Security scan
  security:
    needs: lint
    steps:
      - uses: snyk/actions/node@master

  # 4. Reproducible build
  build:
    needs: [test, security]
    steps:
      - run: |
          docker build \
            --build-arg VERSION=${{ github.sha }} \
            --label git-commit=${{ github.sha }} \
            -t app:${{ github.sha }} .

  # 5. Staged deployment
  deploy-staging:
    needs: build
    environment: staging
    steps:
      - run: deploy.sh staging

  # 6. E2E on staging
  e2e:
    needs: deploy-staging
    steps:
      - run: npm run test:e2e

  # 7. Production with approval
  deploy-prod:
    needs: e2e
    environment:
      name: production
      url: https://example.com
    steps:
      - run: deploy.sh production

  # 8. Post-deploy verification
  smoke-test:
    needs: deploy-prod
    steps:
      - run: curl -f https://example.com/health

Dodatkowe:

  • Wersjonuj pipeline (jako kod)
  • Dokumentuj custom steps
  • Regularny przegląd i cleanup
  • Monitoring pipeline metrics

Zobacz też


Ten artykuł jest częścią serii przygotowującej do rozmów rekrutacyjnych na stanowisko DevOps Engineer. Sprawdź nasze fiszki z pytaniami rekrutacyjnymi: DevOps Interview Questions.

Chcesz więcej pytań rekrutacyjnych?

To tylko jeden temat z naszego kompletnego przewodnika po rozmowach rekrutacyjnych. Uzyskaj dostęp do 800+ pytań z 13 technologii.

Kup pełny dostęp Zobacz bezpłatny podgląd
Powrót do blogu

Zostaw komentarz

Pamiętaj, że komentarze muszą zostać zatwierdzone przed ich opublikowaniem.