CI/CD ํŒŒ์ดํ”„๋ผ์ธ ๋ฉด์ ‘ ์งˆ๋ฌธ 2026: GitHub Actions, GitLab CI, Jenkins ์™„๋ฒฝ ๊ฐ€์ด๋“œ

2026๋…„ DevOps ๋ฉด์ ‘์—์„œ ์ž์ฃผ ์ถœ์ œ๋˜๋Š” CI/CD ํŒŒ์ดํ”„๋ผ์ธ ์งˆ๋ฌธ๊ณผ ๋‹ต๋ณ€์„ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค. GitHub Actions, GitLab CI, Jenkins์˜ ์‹ค์ „ ์ฝ”๋“œ ์˜ˆ์ œ์™€ ๋ณด์•ˆ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

CI/CD ํŒŒ์ดํ”„๋ผ์ธ ๋ฉด์ ‘ ์งˆ๋ฌธ: GitHub Actions, GitLab CI, Jenkins ๋น„๊ต ๋‹ค์ด์–ด๊ทธ๋žจ

2026๋…„ ํ˜„์žฌ, CI/CD ํŒŒ์ดํ”„๋ผ์ธ์€ ํ˜„๋Œ€ ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ์˜ ํ•ต์‹ฌ ์ธํ”„๋ผ๋กœ ์ž๋ฆฌ์žก์•˜์Šต๋‹ˆ๋‹ค. GitHub Actions๋Š” GitHub ์ €์žฅ์†Œ์™€์˜ ์›ํ™œํ•œ ํ†ตํ•ฉ์œผ๋กœ ๋น ๋ฅด๊ฒŒ ํ™•์‚ฐ๋˜์—ˆ๊ณ , GitLab CI๋Š” ํ”Œ๋žซํผ ๋‚ด ํ†ตํ•ฉ ์†”๋ฃจ์…˜์œผ๋กœ์„œ ํ™•๊ณ ํ•œ ์ž…์ง€๋ฅผ ๊ตฌ์ถ•ํ–ˆ์Šต๋‹ˆ๋‹ค. Jenkins๋Š” ํ’๋ถ€ํ•œ ํ”Œ๋Ÿฌ๊ทธ์ธ ์ƒํƒœ๊ณ„๋ฅผ ๊ฐ–์ถ˜ ์˜คํ”ˆ์†Œ์Šค ๋„๊ตฌ๋กœ์„œ ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ํ™˜๊ฒฝ์—์„œ ์—ฌ์ „ํžˆ ์ค‘์š”ํ•œ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. DevOps ์ง๋ฌด ๊ธฐ์ˆ  ๋ฉด์ ‘์—์„œ๋Š” ์ด ์„ธ ๊ฐ€์ง€ ํ”Œ๋žซํผ์— ๋Œ€ํ•œ ์‹ค๋ฌด ์ง€์‹์ด ํ•„์ˆ˜์ ์œผ๋กœ ์š”๊ตฌ๋ฉ๋‹ˆ๋‹ค. ์ด๋ก ์  ๊ฐœ๋…๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๊ตฌ์ฒด์ ์ธ ๊ตฌํ˜„ ํŒจํ„ด, ๋ณด์•ˆ ๋ชจ๋ฒ” ์‚ฌ๋ก€, ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ธฐ๋ฒ•๊นŒ์ง€ ํญ๋„“์€ ์ดํ•ด๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธ€์—์„œ๋Š” 2026๋…„ ๋ฉด์ ‘์—์„œ ์‹ค์ œ๋กœ ์ถœ์ œ๋˜๊ณ  ์žˆ๋Š” ์งˆ๋ฌธ๊ณผ ๋‹ต๋ณ€์„ ์ฒด๊ณ„์ ์œผ๋กœ ์ •๋ฆฌํ•˜๊ณ , ํšจ๊ณผ์ ์ธ ์ค€๋น„ ๋ฐฉ๋ฒ•์„ ์ œ์‹œํ•ฉ๋‹ˆ๋‹ค.

2026๋…„ ๋ฉด์ ‘ ๋Œ€๋น„ ํ•ต์‹ฌ ํฌ์ธํŠธ

ํ˜„์žฌ ์ฑ„์šฉ ์‹œ์žฅ์—์„œ๋Š” ๋‹จ์ผ CI/CD ๋„๊ตฌ์— ๋Œ€ํ•œ ์ˆ™๋ จ๋„๋งŒ์œผ๋กœ๋Š” ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. GitHub Actions, GitLab CI, Jenkins์˜ ์•„ํ‚คํ…์ฒ˜์  ์ฐจ์ด๋ฅผ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๋ฉฐ, ํŠน์ • ์‹œ๋‚˜๋ฆฌ์˜ค์— ์ตœ์ ์ธ ๋„๊ตฌ๋ฅผ ๊ทผ๊ฑฐ๋ฅผ ๋“ค์–ด ์ถ”์ฒœํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์†Œ ๋‘ ๊ฐœ ์ด์ƒ์˜ ํ”Œ๋žซํผ์—์„œ ์‹ค๋ฌด ๊ฒฝํ—˜์ด ์žˆ์œผ๋ฉด ์„ ๋ฐœ ๊ณผ์ •์—์„œ ์ƒ๋‹นํ•œ ๊ฒฝ์Ÿ ์šฐ์œ„๋ฅผ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

GitHub Actions: ์›Œํฌํ”Œ๋กœ ์„ค๊ณ„์™€ Matrix Builds

GitHub Actions๋Š” ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์›Œํฌํ”Œ๋กœ ๋ชจ๋ธ์„ ์ฑ„ํƒํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. Git ์ด๋ฒคํŠธ, ์Šค์ผ€์ค„, ์™ธ๋ถ€ Webhook ๋“ฑ ๋‹ค์–‘ํ•œ ํŠธ๋ฆฌ๊ฑฐ์— ์˜ํ•ด ์›Œํฌํ”Œ๋กœ๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ๊ฐ ์ž‘์—…(Job)์€ ๋…๋ฆฝ๋œ VM ๋˜๋Š” ์ปจํ…Œ์ด๋„ˆ์—์„œ ์‹คํ–‰๋˜๋ฉฐ, ์—ฌ๋Ÿฌ ๋‹จ๊ณ„(Step)๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค. ๋ฉด์ ‘์—์„œ๋Š” ์ž‘์—… ๊ฐ„ ์˜์กด์„ฑ ์ œ์–ด, ๋งคํŠธ๋ฆญ์Šค ๋นŒ๋“œ, ํ™˜๊ฒฝ ๋ณดํ˜ธ ๋ฉ”์ปค๋‹ˆ์ฆ˜์— ๋Œ€ํ•œ ๊นŠ์€ ์ดํ•ด๊ฐ€ ํ‰๊ฐ€๋ฉ๋‹ˆ๋‹ค.

yaml
# .github/workflows/ci.yml
name: CI Pipeline

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

jobs:
  lint:
    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 lint

  test:
    needs: lint              # waits for lint to pass
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node: [20, 22]       # runs tests on both versions
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
          cache: npm
      - run: npm ci
      - run: npm test

  deploy:
    needs: test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production  # requires approval
    steps:
      - uses: actions/checkout@v4
      - run: ./deploy.sh

์ด ๊ตฌ์„ฑ์—์„œ ์ฃผ๋ชฉํ•ด์•ผ ํ•  ํ•ต์‹ฌ ์š”์†Œ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์žˆ์Šต๋‹ˆ๋‹ค. needs ํ‚ค์›Œ๋“œ๋Š” ์ž‘์—… ๊ฐ„ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ์ œ์–ดํ•˜๋ฉฐ, lint ์ž‘์—…์ด ์„ฑ๊ณตํ•œ ํ›„์—๋งŒ test ์ž‘์—…์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. strategy.matrix๋Š” ์„œ๋กœ ๋‹ค๋ฅธ Node.js ๋ฒ„์ „์—์„œ ๋ณ‘๋ ฌ ํ…Œ์ŠคํŠธ๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜์—ฌ ํ˜ธํ™˜์„ฑ ๊ฒ€์ฆ์„ ์ž๋™ํ™”ํ•ฉ๋‹ˆ๋‹ค. environment: production ์„ค์ •์„ ํ†ตํ•ด ๋ฐฐํฌ ์ „ ์ˆ˜๋™ ์Šน์ธ ํ”„๋กœ์„ธ์Šค๋ฅผ ์š”๊ตฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฉด์ ‘์—์„œ ์ž์ฃผ ์ถœ์ œ๋˜๋Š” ์งˆ๋ฌธ ์ค‘ ํ•˜๋‚˜๋Š” if: github.ref == 'refs/heads/main'๊ณผ if: github.ref == 'main'์˜ ์ฐจ์ด์ž…๋‹ˆ๋‹ค. github.ref๋Š” ์™„์ „ํ•œ ๋ธŒ๋žœ์น˜ ๊ฒฝ๋กœ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ refs/heads/ ์ ‘๋‘์‚ฌ๋ฅผ ํฌํ•จํ•œ ์ „์ฒด ํ˜•์‹์œผ๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ถ€๋ถ„์„ ๊ฐ„๊ณผํ•˜๋ฉด ์กฐ๊ฑด ๋ถ„๊ธฐ๊ฐ€ ์˜๋„๋Œ€๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Reusable Workflows๋„ ๋นˆ์ถœ ํ† ํ”ฝ์ž…๋‹ˆ๋‹ค. ์กฐ์ง ์ „์ฒด์—์„œ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋Š” ์›Œํฌํ”Œ๋กœ ํ…œํ”Œ๋ฆฟ์„ ์ •์˜ํ•˜๊ณ , ์—ฌ๋Ÿฌ ์ €์žฅ์†Œ์—์„œ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณด์•ˆ ์Šค์บ”์ด๋‚˜ ๋ฐฐํฌ ๊ฒŒ์ดํŠธ๋ฅผ ์ค‘์•™์—์„œ ๊ด€๋ฆฌํ•จ์œผ๋กœ์จ ์ฝ”๋“œ ์ค‘๋ณต์„ ์ค„์ด๊ณ  ์ปดํ”Œ๋ผ์ด์–ธ์Šค ์š”๊ตฌ์‚ฌํ•ญ ๋Œ€์‘์„ ํšจ์œจํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. actions/setup-node์˜ cache ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ ์บ์‹ฑ์€ node_modules๋ฅผ ์›Œํฌํ”Œ๋กœ ์‹คํ–‰ ๊ฐ„์— ์žฌ์‚ฌ์šฉํ•˜์—ฌ ๋นŒ๋“œ ์‹œ๊ฐ„์„ ํฌ๊ฒŒ ๋‹จ์ถ•ํ•ฉ๋‹ˆ๋‹ค.

์‹คํ–‰ ์ปจํ…์ŠคํŠธ(github, env, secrets, steps)์—๋Š” ์›Œํฌํ”Œ๋กœ ์‹คํ–‰ ์‹œ์ ์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. Expression ๋ฌธ๋ฒ• ${{ }}๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋™์  ๊ฐ’ ๊ณ„์‚ฐ๊ณผ ์กฐ๊ฑด ๋กœ์ง ์ž‘์„ฑ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

GitLab CI: ์Šคํ…Œ์ด์ง€ ๊ธฐ๋ฐ˜ ํŒŒ์ดํ”„๋ผ์ธ๊ณผ Artifact ๊ด€๋ฆฌ

GitLab CI๋Š” ์Šคํ…Œ์ด์ง€ ๊ธฐ๋ฐ˜ ํŒŒ์ดํ”„๋ผ์ธ ๋ชจ๋ธ์„ ์ฑ„ํƒํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋™์ผ ์Šคํ…Œ์ด์ง€ ๋‚ด์˜ ์ž‘์—…์€ ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰๋˜์ง€๋งŒ, ์Šคํ…Œ์ด์ง€ ๊ฐ„์—๋Š” ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” "๊ธฐ๋ณธ์ ์œผ๋กœ ๋ณ‘๋ ฌ ์‹คํ–‰, needs๋กœ ์ œ์–ด"ํ•˜๋Š” GitHub Actions ๋ชจ๋ธ๊ณผ ๊ทผ๋ณธ์ ์œผ๋กœ ๋‹ค๋ฅธ ์ ‘๊ทผ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

yaml
# .gitlab-ci.yml
stages:
  - validate
  - test
  - deploy

variables:
  NODE_VERSION: "22"

lint:
  stage: validate
  image: node:${NODE_VERSION}
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - node_modules/
  script:
    - npm ci
    - npm run lint

unit-tests:
  stage: test
  image: node:${NODE_VERSION}
  parallel:
    matrix:
      - NODE_VERSION: ["20", "22"]
  script:
    - npm ci
    - npm test
  artifacts:
    reports:
      junit: coverage/junit.xml
    expire_in: 7 days

deploy-production:
  stage: deploy
  image: alpine:latest
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      when: manual                   # manual gate
  environment:
    name: production
    url: https://app.example.com
  script:
    - ./deploy.sh

rules ํ‚ค์›Œ๋“œ๋Š” GitLab CI 14 ์ดํ›„ ๊ธฐ์กด์˜ only/except ๋ชจ๋ธ์„ ๋Œ€์ฒดํ•˜๋Š” ๊ถŒ์žฅ ๊ตฌ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋ธŒ๋žœ์น˜๋ช…, ํƒœ๊ทธ, ๋จธ์ง€ ๋ฆฌํ€˜์ŠคํŠธ ์ƒํƒœ, ์‚ฌ์šฉ์ž ์ •์˜ ๋ณ€์ˆ˜๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž‘์—… ์‹คํ–‰์„ ์„ธ๋ฐ€ํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. when: manual๊ณผ rules์˜ ์กฐํ•ฉ์œผ๋กœ ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ์— ๋Œ€ํ•œ ์Šน์ธ ๊ฒŒ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Artifact์™€ Cache์˜ ์ฐจ์ด๋Š” ๋ฉด์ ‘์—์„œ ํŠนํžˆ ์ฃผ๋ชฉ๋ฐ›๋Š” ๋…ผ์ ์ž…๋‹ˆ๋‹ค. Cache๋Š” node_modules ๊ฐ™์€ ์˜์กด์„ฑ์„ ์žฌ์‚ฌ์šฉํ•˜์—ฌ ๋ฆฌ๋นŒ๋“œ ์‹œ๊ฐ„์„ ์ตœ์ ํ™”ํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ž…๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด Artifact๋Š” ์Šคํ…Œ์ด์ง€ ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•œ ๋ช…์‹œ์ ์ธ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ž…๋‹ˆ๋‹ค. reports ๋ธ”๋ก์„ ์‚ฌ์šฉํ•˜๋ฉด ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€๋‚˜ SAST ์Šค์บ” ๊ฒฐ๊ณผ๋ฅผ GitLab UI์— ์ง์ ‘ ํ†ตํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. expire_in ๋””๋ ‰ํ‹ฐ๋ธŒ๋Š” ๋Œ€๊ทœ๋ชจ ์ฝ”๋“œ๋ฒ ์ด์Šค์—์„œ Artifact ์Šคํ† ๋ฆฌ์ง€์˜ ๋ฌดํ•œ ์ฆ๊ฐ€๋ฅผ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.

์บ์‹œ ํ‚ค์—๋Š” ๋ธŒ๋žœ์น˜๋ณ„ ๊ณ ์œ  ๊ฐ’(${CI_COMMIT_REF_SLUG})์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค. ์„œ๋กœ ๋‹ค๋ฅธ ๋ธŒ๋žœ์น˜์—์„œ ๋™์‹œ์— ์‹คํ–‰๋˜๋Š” ํŒŒ์ดํ”„๋ผ์ธ ๊ฐ„์˜ ๊ฒฝ์Ÿ ์ƒํƒœ(race condition)๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•จ์ž…๋‹ˆ๋‹ค. GitLab CI ๋ฒ„์ „ 16 ์ดํ›„์—๋Š” needs ํ‚ค์›Œ๋“œ๋ฅผ ํ†ตํ•œ DAG(๋ฐฉํ–ฅ ๋น„์ˆœํ™˜ ๊ทธ๋ž˜ํ”„) ํŒŒ์ดํ”„๋ผ์ธ์ด ์ง€์›๋˜์–ด, ์ง์ ‘ ์˜์กด์„ฑ์ด ์ถฉ์กฑ๋˜๋ฉด ์ด์ „ ์Šคํ…Œ์ด์ง€ ์ „์ฒด์˜ ์™„๋ฃŒ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ์ž‘์—…์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์ „๋žต์€ ์Šคํ…Œ์ด์ง€ ๊ธฐ๋ฐ˜ ํŒŒ์ดํ”„๋ผ์ธ์˜ ๊ฐ€๋…์„ฑ๊ณผ ์„ธ๋ฐ€ํ•œ ๋ณ‘๋ ฌํ™”๋ฅผ ํ†ตํ•œ ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ๋™์‹œ์— ๋‹ฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

Jenkins: Declarative Pipeline๊ณผ Plugin ์ƒํƒœ๊ณ„

2026๋…„์—๋„ Jenkins๋Š” ๋ณต์žกํ•œ ์˜จํ”„๋ ˆ๋ฏธ์Šค ์š”๊ตฌ์‚ฌํ•ญ์„ ๊ฐ€์ง„ ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ํ™˜๊ฒฝ์—์„œ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. Declarative Pipeline ๊ตฌ๋ฌธ์€ Scripted Pipeline๋ณด๋‹ค ๊ตฌ์กฐ์ ์ด๊ณ  ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์šฉ์ดํ•˜์—ฌ ํ˜„์žฌ์˜ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋กœ ์ •์ฐฉํ–ˆ์Šต๋‹ˆ๋‹ค.

groovy
// Jenkinsfile
pipeline {
    agent any

    tools {
        nodejs 'node-22'       // configured in Jenkins Global Tool
    }

    environment {
        CI = 'true'
        DEPLOY_ENV = credentials('deploy-env-secret')
    }

    stages {
        stage('Install') {
            steps {
                sh 'npm ci'
            }
        }

        stage('Lint & Test') {
            parallel {             // parallel execution
                stage('Lint') {
                    steps {
                        sh 'npm run lint'
                    }
                }
                stage('Test') {
                    steps {
                        sh 'npm test'
                    }
                    post {
                        always {
                            junit 'coverage/junit.xml'
                        }
                    }
                }
            }
        }

        stage('Deploy') {
            when {
                branch 'main'
            }
            input {
                message 'Deploy to production?'
            }
            steps {
                sh './deploy.sh'
            }
        }
    }

    post {
        failure {
            mail to: 'team@example.com',
                 subject: "Build failed: ${env.JOB_NAME}",
                 body: "Check ${env.BUILD_URL}"
        }
    }
}

agent ๋””๋ ‰ํ‹ฐ๋ธŒ๋Š” ํŒŒ์ดํ”„๋ผ์ธ์˜ ์‹คํ–‰ ํ™˜๊ฒฝ์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. agent any๋Š” ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ž„์˜์˜ ์—์ด์ „ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , agent { label 'linux' }๋Š” ํŠน์ • ๋ ˆ์ด๋ธ”์„ ๊ฐ€์ง„ ์—์ด์ „ํŠธ๋กœ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค. ์ปจํ…Œ์ด๋„ˆ ๊ธฐ๋ฐ˜ ๋นŒ๋“œ์—๋Š” agent { docker 'node:22' }๊ฐ€ ์ ํ•ฉํ•˜๋ฉฐ, Jenkins ์„œ๋ฒ„์— ๋„๊ตฌ๋ฅผ ์˜๊ตฌ ์„ค์น˜ํ•˜์ง€ ์•Š๊ณ ๋„ ๊ฒฉ๋ฆฌ๋œ ํ™˜๊ฒฝ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

tools ๋ธ”๋ก์€ Jenkins์— ๋“ฑ๋ก๋œ ๋„๊ตฌ ์„ค์น˜๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ํŒŒ์ดํ”„๋ผ์ธ ์ •์˜๊ฐ€ ๊ตฌ์ฒด์ ์ธ ๊ฒฝ๋กœ์—์„œ ๋ถ„๋ฆฌ๋˜๊ณ , Node.js, Maven, JDK ๋“ฑ์˜ ๋ฒ„์ „์„ ์ค‘์•™์—์„œ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. environment ๋ธ”๋ก ๋‚ด์˜ credentials ํ‚ค์›Œ๋“œ๋Š” Jenkinsfile์— ์‹œํฌ๋ฆฟ์„ ๋…ธ์ถœํ•˜์ง€ ์•Š์œผ๋ฉด์„œ Jenkins Credentials๋ฅผ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ๋ฐ”์ธ๋”ฉํ•ฉ๋‹ˆ๋‹ค.

๋ณ‘๋ ฌ ์‹คํ–‰์€ ์Šคํ…Œ์ด์ง€ ๋‚ด์˜ parallel ๋ธ”๋ก์œผ๋กœ ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค. GitHub Actions๋‚˜ GitLab CI์˜ Matrix Builds์™€ ๋‹ฌ๋ฆฌ, ๊ฐ ๋ณ‘๋ ฌ ๋ถ„๊ธฐ์— ๋Œ€ํ•ด ๋ช…์‹œ์ ์ธ ์Šคํ…Œ์ด์ง€ ์ •์˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. post ๋””๋ ‰ํ‹ฐ๋ธŒ๋Š” ๋นŒ๋“œ ๊ฒฐ๊ณผ์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ์‹คํ–‰๋˜๋Š” ์ •๋ฆฌ ์ž‘์—…์ด๋‚˜ ์•Œ๋ฆผ ๋กœ์ง์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. always, success, failure, unstable, changed ๋“ฑ์˜ ์กฐ๊ฑด์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1,800๊ฐœ ์ด์ƒ์˜ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๋ณด์œ ํ•œ Jenkins ์ƒํƒœ๊ณ„๋Š” DevOps ์˜์—ญ์˜ ๊ฑฐ์˜ ๋ชจ๋“  ๋„๊ตฌ์™€์˜ ์—ฐ๋™์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. Blue Ocean(๋ชจ๋˜ UI), Pipeline Stage View(ํŒŒ์ดํ”„๋ผ์ธ ์‹œ๊ฐํ™”), Configuration as Code(JCasC, ์„ ์–ธ์  Jenkins ๊ตฌ์„ฑ)๋Š” ๋ฉด์ ‘์—์„œ ์ž์ฃผ ๋‹ค๋ฃจ์–ด์ง€๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ์ž…๋‹ˆ๋‹ค. ๋‹ค๋งŒ ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ด€๋ฆฌ์—๋Š” ์ง€์†์ ์ธ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ํ•„์š”ํ•˜๋ฉฐ, ์˜ค๋ž˜๋˜๊ฑฐ๋‚˜ ํ˜ธํ™˜๋˜์ง€ ์•Š๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ์žฅ์• ์˜ ์›์ธ์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ณด์•ˆ ๋ชจ๋ฒ” ์‚ฌ๋ก€: ์‹œํฌ๋ฆฟ ๊ด€๋ฆฌ์™€ ๊ณต๊ธ‰๋ง ๊ณต๊ฒฉ ๋Œ€์‘

2026๋…„ CI/CD ๋ฉด์ ‘์—์„œ ๋ณด์•ˆ ๊ด€๋ จ ์งˆ๋ฌธ์€ ๊ฐ€์žฅ ์ค‘์š”ํ•˜๊ฒŒ ๋‹ค๋ฃจ์–ด์ง€๋Š” ์ฃผ์ œ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. SolarWinds์™€ CodeCov ์‚ฌ๋ก€ ์ดํ›„, ๋นŒ๋“œ ํŒŒ์ดํ”„๋ผ์ธ์— ๋Œ€ํ•œ ๊ณต๊ธ‰๋ง ๊ณต๊ฒฉ ๋ฐฉ์–ด๋Š” ์ตœ์šฐ์„  ๊ณผ์ œ๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

yaml
# .github/workflows/secure.yml
steps:
  # Vulnerable: tag can be moved to malicious commit
  - uses: actions/checkout@v4

  # Secure: pinned to exact commit SHA
  - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683

GitHub Workflows์—์„œ Action์˜ SHA ๊ณ ์ •(pinning)์€ ํƒœ๊ทธ๋ช…์ด ์•…์„ฑ ์ฝ”๋“œ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋˜๋Š” ์œ„ํ—˜์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. Dependabot์ด ๋ณด์•ˆ ์ˆ˜์ •์ด ํฌํ•จ๋œ ์ƒˆ ๋ฒ„์ „์˜ Pull Request๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๋ฏ€๋กœ, SHA ๊ณ ์ •๊ณผ ์ž๋™ ์—…๋ฐ์ดํŠธ์˜ ์กฐํ•ฉ์œผ๋กœ ๋ณด์•ˆ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ ์‚ฌ์ด์˜ ๊ท ํ˜•์„ ๋งž์ถœ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹œํฌ๋ฆฟ ๊ด€๋ฆฌ๋Š” ํ”Œ๋žซํผ๋ณ„๋กœ ๋‹ค๋ฅธ ์ „๋žต์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. GitHub Actions๋Š” Repository, Organization, Environment์˜ ์„ธ ๊ฐ€์ง€ ๋ฒ”์œ„(scope)์—์„œ ์‹œํฌ๋ฆฟ์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. Environment Secrets๋Š” ์Šน์ธ ์›Œํฌํ”Œ๋กœ์™€ ๋ธŒ๋žœ์น˜ ์ œํ•œ์„ ์ถ”๊ฐ€๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. GitLab CI๋Š” ์ผ๋ฐ˜ ๋ณ€์ˆ˜์™€ Protected Variables๋ฅผ ๊ตฌ๋ถ„ํ•˜๋ฉฐ, ํ›„์ž๋Š” Protected Branch์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. Jenkins๋Š” Credentials Plugin์„ ํ†ตํ•ด Username/Password, Secret Text, SSH ํ‚ค, ์ธ์ฆ์„œ ๋“ฑ ๋‹ค์–‘ํ•œ ์œ ํ˜•์˜ ์ž๊ฒฉ ์ฆ๋ช…์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

OIDC(OpenID Connect)๋Š” ํด๋ผ์šฐ๋“œ ๋ฐฐํฌ์˜ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋กœ ํ™•๋ฆฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ •์  ์•ก์„ธ์Šค ํ‚ค ๋Œ€์‹  ํŒŒ์ดํ”„๋ผ์ธ์ด ๋‹จ๊ธฐ ํ† ํฐ์„ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ผ์šฐ๋“œ ๊ณต๊ธ‰์ž์— ์ง์ ‘ ์ธ์ฆํ•ฉ๋‹ˆ๋‹ค. GitHub Actions๋Š” AWS, Azure, GCP์— ๋Œ€ํ•œ OIDC๋ฅผ ๋„ค์ดํ‹ฐ๋ธŒ๋กœ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. GitLab CI๋Š” $CI_JOB_JWT๋ฅผ ํ†ตํ•ด ID ํ† ํฐ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. Jenkins์˜ ๊ฒฝ์šฐ OIDC ํ†ตํ•ฉ์„ ์œ„ํ•ด ์ „์šฉ ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

DevOps ๋ฉด์ ‘ ์ค€๋น„๊ฐ€ ๋˜์…จ๋‚˜์š”?

์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ, flashcards, ๊ธฐ์ˆ  ํ…Œ์ŠคํŠธ๋กœ ์—ฐ์Šตํ•˜์„ธ์š”.

์„ฑ๋Šฅ ์ตœ์ ํ™”: ์บ์‹ฑ ์ „๋žต๊ณผ Matrix ํšจ์œจํ™”

์„ฑ๋Šฅ ๊ด€๋ จ ์งˆ๋ฌธ์€ ํŒŒ์ดํ”„๋ผ์ธ ๋น„์šฉ ์ธ์‹๊ณผ ์ตœ์ ํ™” ์—ญ๋Ÿ‰์„ ํ‰๊ฐ€ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•˜๋ฃจ์— 10๋ฒˆ ์‹คํ–‰๋˜๋Š” 20๋ถ„์งœ๋ฆฌ ํŒŒ์ดํ”„๋ผ์ธ์€ ์ƒ๋‹นํ•œ ๋Ÿฌ๋„ˆ ์‹œ๊ฐ„์„ ์†Œ๋น„ํ•˜๊ณ  ๊ฐœ๋ฐœ์ž ํ”ผ๋“œ๋ฐฑ ๋ฃจํ”„๋ฅผ ์ €ํ•ดํ•ฉ๋‹ˆ๋‹ค.

์บ์‹ฑ์€ ๊ฐ€์žฅ ํšจ๊ณผ์ ์ธ ์ตœ์ ํ™” ๊ธฐ๋ฒ•์ž…๋‹ˆ๋‹ค. GitHub Actions์˜ actions/cache๋Š” ์‹คํ–‰ ๊ฐ„ ์˜์กด์„ฑ์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์บ์‹œ ํ‚ค์—๋Š” ์˜์กด์„ฑ ํŒŒ์ผ์˜ ํ•ด์‹œ(hashFiles('package-lock.json'))๋ฅผ ํฌํ•จ์‹œ์ผœ ์˜์กด์„ฑ์ด ๋ณ€๊ฒฝ๋  ๋•Œ ์ž๋™์œผ๋กœ ๋ฌดํšจํ™”๋˜๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. restore-keys ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋Š” ํ‚ค๊ฐ€ ์—†์„ ๋•Œ ๋Œ€์ฒด ํ‚ค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

GitLab CI ์บ์‹œ๋Š” key: files: ['package-lock.json']์œผ๋กœ ์œ ์‚ฌํ•œ ๋กœ์ง์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. policy: pull-push(๊ธฐ๋ณธ๊ฐ’)์™€ policy: pull์˜ ๊ตฌ๋ถ„์€ ์—ฌ๋Ÿฌ ์ž‘์—…์ด ๋™์ผํ•œ ์บ์‹œ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๊ฒฝ์Ÿ ์ƒํƒœ๋ฅผ ๋ฐฉ์ง€ํ•˜๋Š” ๋ฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์บ์‹œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ์ž‘์—…์€ ํ•˜๋‚˜๋งŒ ๋‘๊ณ  ๋‚˜๋จธ์ง€๋Š” ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค.

Jenkins๋Š” ์ˆœ์ฐจ ์‹คํ–‰ ์Šคํ…Œ์ด์ง€์—์„œ ์›Œํฌ์ŠคํŽ˜์ด์Šค ์žฌ์‚ฌ์šฉ์„ ๊ธฐ๋ณธ์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค. ๋ณ‘๋ ฌ ์ž‘์—…์ด๋‚˜ ๋ฉ€ํ‹ฐ ๋ธŒ๋žœ์น˜ ํŒŒ์ดํ”„๋ผ์ธ์—์„œ๋Š” Stash/Unstash ๊ธฐ๋Šฅ์ด ์—์ด์ „ํŠธ ๊ฐ„ ์•„ํ‹ฐํŒฉํŠธ ์ „์†ก์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋Œ€๊ทœ๋ชจ ์ฝ”๋“œ๋ฒ ์ด์Šค์—์„œ๋Š” Job Cacher Plugin์ด๋‚˜ Artifact Manager on S3 Plugin์„ ์‚ฌ์šฉํ•œ ์™ธ๋ถ€ ์บ์‹ฑ์ด ๋” ํ™•์žฅ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

Matrix Builds๋Š” ๋ณ‘๋ ฌํ™”๋ฅผ ์ด‰์ง„ํ•˜์ง€๋งŒ ๋น„์šฉ๋„ ์ฆ๊ฐ€์‹œํ‚ต๋‹ˆ๋‹ค. 5๊ฐœ Node ๋ฒ„์ „ x 3๊ฐœ OS = 15๊ฐœ ๋ณ‘๋ ฌ ์ž‘์—…์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ๋ฉด์ ‘์—์„œ๋Š” ๋งคํŠธ๋ฆญ์Šค ์ฐจ์›์„ ํ•ฉ๋ฆฌ์ ์œผ๋กœ ์ œํ•œํ•  ์ˆ˜ ์žˆ๋Š”์ง€๊ฐ€ ํ‰๊ฐ€๋ฉ๋‹ˆ๋‹ค. GitHub Actions์˜ strategy.matrix.exclude์™€ include๋ฅผ ํ†ตํ•ด ์„ ํƒ์ ์ธ ์กฐํ•ฉ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

ํ”Œ๋žซํผ ๋น„๊ต: GitHub Actions vs GitLab CI vs Jenkins

๋ฉด์ ‘ ํŒจ๋„์€ ์กฐ์ง ์š”๊ตฌ์‚ฌํ•ญ์— ๊ธฐ๋ฐ˜ํ•œ ๊ทผ๊ฑฐ ์žˆ๋Š” ์ถ”์ฒœ์„ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ํ‘œ๋Š” ๊ธฐ์ˆ ์  ์ฐจ์ด๋ฅผ ์ •๋ฆฌํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

| ํ•ญ๋ชฉ | GitHub Actions | GitLab CI | Jenkins | |---|---|---|---| | ์„ค์ • ํŒŒ์ผ | .github/workflows/*.yml | .gitlab-ci.yml | Jenkinsfile | | ์‹คํ–‰ ๋ชจ๋ธ | ์ž‘์—… ๊ธฐ๋ฐ˜(๊ธฐ๋ณธ ๋ณ‘๋ ฌ) | ์Šคํ…Œ์ด์ง€ ๊ธฐ๋ฐ˜(์Šคํ…Œ์ด์ง€ ๊ฐ„ ์ˆœ์ฐจ) | ์Šคํ…Œ์ด์ง€ ๊ธฐ๋ฐ˜(์œ ์—ฐ) | | ๋Ÿฌ๋„ˆ ํ˜ธ์ŠคํŒ… | GitHub-hosted + Self-hosted | GitLab.com Shared + Self-hosted | Self-hosted๋งŒ | | ์‹œํฌ๋ฆฟ ๊ด€๋ฆฌ | Repository/Org/Environment Secrets | CI/CD ๋ณ€์ˆ˜(๋ณดํ˜ธ ๊ฐ€๋Šฅ) | Credentials Plugin | | Matrix Builds | strategy.matrix | parallel:matrix | matrix(Plugin) | | ์ˆ˜๋™ ๊ฒŒ์ดํŠธ | environment + Required Reviewers | when: manual | input ๋””๋ ‰ํ‹ฐ๋ธŒ | | ๋งˆ์ผ“ํ”Œ๋ ˆ์ด์Šค | 20,000+ Actions | CI/CD Components Catalog | 1,800+ Plugins | | AI ๊ธฐ๋Šฅ | Copilot for Actions(Preview) | Duo CI Expert Agent(Beta) | Community Plugins | | ๊ฐ€๊ฒฉ ์ •์ฑ… | ๊ณต๊ฐœ ์ €์žฅ์†Œ ๋ฌด๋ฃŒ, ๋น„๊ณต๊ฐœ๋Š” ๋ถ„๋‹น ๊ณผ๊ธˆ | ์›” 400๋ถ„ ๋ฌด๋ฃŒ, ๋‹จ๊ณ„๋ณ„ ๊ณผ๊ธˆ | ๋ฌด๋ฃŒ(OSS), ์ž์ฒด ๊ด€๋ฆฌ |

GitHub Actions๋Š” ์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ๋‚˜ ์ด๋ฏธ GitHub์„ ์ฝ”๋“œ ํ˜ธ์ŠคํŒ…์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ํŒ€์— ์ตœ์ ์ž…๋‹ˆ๋‹ค. GitLab CI๋Š” ์ €์žฅ์†Œ, CI/CD, ์ปจํ…Œ์ด๋„ˆ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ, ๋ณด์•ˆ ์Šค์บ”, ์ธ์‹œ๋˜ํŠธ ๊ด€๋ฆฌ๋ฅผ ํ†ตํ•ฉํ•œ ์˜ฌ์ธ์› ํ”Œ๋žซํผ์œผ๋กœ์„œ ๊ฐ•์ ์„ ๋ฐœํœ˜ํ•ฉ๋‹ˆ๋‹ค. Jenkins๋Š” ๋ ˆ๊ฑฐ์‹œ ์‹œ์Šคํ…œ, ์—„๊ฒฉํ•œ ์ปดํ”Œ๋ผ์ด์–ธ์Šค ์š”๊ตฌ์‚ฌํ•ญ, ํด๋ผ์šฐ๋“œ ์—ฐ๊ฒฐ์ด ์—†๋Š” ๋ณต์žกํ•œ ์˜จํ”„๋ ˆ๋ฏธ์Šค ์ธํ”„๋ผ๋ฅผ ๋ณด์œ ํ•œ ์กฐ์ง์—์„œ ์—ฌ์ „ํžˆ ์œ ๋ ฅํ•œ ์„ ํƒ์ง€์ž…๋‹ˆ๋‹ค.

ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์ ‘๊ทผ ๋ฐฉ์‹๋„ ์‹ค๋ฌด์—์„œ ํ”ํžˆ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. Pull Request์˜ ๋น ๋ฅธ ํ”ผ๋“œ๋ฐฑ์— GitHub Actions๋ฅผ, ๋ณต์žกํ•œ ์ปดํ”Œ๋ผ์ด์–ธ์Šค ์š”๊ตฌ์‚ฌํ•ญ์ด ์ˆ˜๋ฐ˜๋˜๋Š” ๋ฐฐํฌ์— Jenkins๋ฅผ ์กฐํ•ฉํ•˜๋Š” ํŒจํ„ด์ด ๋Œ€ํ‘œ์ ์ธ ์˜ˆ์ž…๋‹ˆ๋‹ค. ๋ฉด์ ‘์—์„œ๋Š” ํ•˜๋‚˜์˜ ํ”Œ๋žซํผ์„ ๊ณ ์ง‘ํ•˜๊ธฐ๋ณด๋‹ค ์ด๋Ÿฌํ•œ ์‹ค์šฉ์ ์ธ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๋…ผ์˜ํ•  ์ˆ˜ ์žˆ๋Š” ์—ญ๋Ÿ‰์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋‹ˆํ„ฐ๋ง๊ณผ ๊ด€์ฐฐ ๊ฐ€๋Šฅ์„ฑ: ํŒŒ์ดํ”„๋ผ์ธ ๋ฉ”ํŠธ๋ฆญ๊ณผ ์ธ์‹œ๋˜ํŠธ ๋Œ€์‘

ํ”„๋กœ๋•์…˜ ์ˆ˜์ค€์˜ CI/CD์—๋Š” ๋ชจ๋‹ˆํ„ฐ๋ง๊ณผ ์•Œ๋ฆผ์ด ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค. Build Success Rate์™€ Mean Time to Recovery(MTTR)๊ฐ€ ํ•ต์‹ฌ ์ง€ํ‘œ์ž…๋‹ˆ๋‹ค. GitHub Actions์˜ Workflow Insights๋Š” ์„ฑ๊ณต๋ฅ ๊ณผ ํ‰๊ท  ์‹คํ–‰ ์‹œ๊ฐ„์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. GitLab CI Analytics๋Š” Deployment Frequency, Lead Time, Change Failure Rate ๋“ฑ DORA Metrics 4๋Œ€ ์ง€ํ‘œ๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. Jenkins๋Š” Prometheus Metrics Plugin์„ ํ†ตํ•ด ๋นŒ๋“œ ํ†ต๊ณ„๋ฅผ Grafana ๋Œ€์‹œ๋ณด๋“œ๋กœ ๋‚ด๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Flaky Test(๋ถˆ์•ˆ์ •ํ•œ ํ…Œ์ŠคํŠธ)๋Š” ํŒŒ์ดํ”„๋ผ์ธ์„ ๋ถˆ์•ˆ์ •ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ์š”์ธ์ž…๋‹ˆ๋‹ค. GitHub Actions๋Š” ์›Œํฌํ”Œ๋กœ ์ „์ฒด๊ฐ€ ์•„๋‹Œ ์‹คํŒจํ•œ ์ž‘์—…๋งŒ ์žฌ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. GitLab CI์˜ retry: 2๋Š” ์‹คํŒจํ•œ ์ž‘์—…์„ ์ž๋™์œผ๋กœ ์žฌ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค. Jenkins์—๋Š” Flaky Test Handler Plugin์ด ์žˆ์–ด ๊ฐ„ํ—์  ์‹คํŒจ์˜ ํ†ต๊ณ„์  ๋ถ„์„์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋งŒ ์ž๋™ ์žฌ์‹œ๋„๋Š” ์ฆ์ƒ ์™„ํ™”์— ๋ถˆ๊ณผํ•˜๋ฉฐ ๊ทผ๋ณธ ์›์ธ ๋ถ„์„์ด ์—ฌ์ „ํžˆ ํ•„์ˆ˜์ ์ด๋ผ๋Š” ์ ์„ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์•Œ๋ฆผ ์ „๋žต์€ ๊ฐ€์‹œ์„ฑ(Visibility)๊ณผ ์•Œ๋ฆผ ํ”ผ๋กœ(Alert Fatigue) ์‚ฌ์ด์˜ ๊ท ํ˜•์„ ๋งž์ถฐ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ ์‹œ GitHub Actions workflow_run Webhook์—์„œ Slack์œผ๋กœ ์•Œ๋ฆผ์„ ๋ณด๋‚ด๋Š” ๊ฒƒ์€ ํšจ๊ณผ์ ์ด์ง€๋งŒ, ๋ชจ๋“  ํ…Œ์ŠคํŠธ ์‹คํŒจ๋งˆ๋‹ค ์•Œ๋ฆผ์„ ๋ณด๋‚ด๋ฉด ์ฑ„๋„์ด ๊ณผ๋ถ€ํ•˜๋ฉ๋‹ˆ๋‹ค. GitLab CI์˜ Pipeline Schedules์™€ ์ƒํƒœ ๋ณ€๊ฒฝ ์‹œ์—๋งŒ ๋ฐœ์†ก๋˜๋Š” ์ด๋ฉ”์ผ ์•Œ๋ฆผ์€ ๋…ธ์ด์ฆˆ๋ฅผ ์ค„์—ฌ์ค๋‹ˆ๋‹ค. Jenkins์˜ Email-ext Plugin๊ณผ Groovy ํ…œํ”Œ๋ฆฟ์€ ์ปจํ…์ŠคํŠธ์— ๋งž๋Š” ๋ฉ”์‹œ์ง€ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

๊ฐ์‚ฌ ๋กœ๊ทธ๋Š” ๋ˆ„๊ฐ€ ํŒŒ์ดํ”„๋ผ์ธ์„ ํŠธ๋ฆฌ๊ฑฐํ–ˆ๋Š”์ง€, ์‹œํฌ๋ฆฟ์„ ๋ณ€๊ฒฝํ–ˆ๋Š”์ง€, ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ๋ฅผ ์Šน์ธํ–ˆ๋Š”์ง€๋ฅผ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค. GitHub Audit Log API๋Š” ๋ณด์•ˆ ๋ถ„์„๊ณผ ์ปดํ”Œ๋ผ์ด์–ธ์Šค ๋ณด๊ณ ์„œ๋ฅผ ์ง€์›ํ•˜๊ณ , GitLab Audit Events๋Š” ๋ชจ๋“  ๋ณด์•ˆ ๊ด€๋ จ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค. Jenkins Audit Trail Plugin์€ ํƒ€์ž„์Šคํƒฌํ”„์™€ ์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ ํฌํ•จ๋œ ๊ตฌ์„ฑ ๋ณ€๊ฒฝ ๋กœ๊ทธ๋ฅผ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.

CI/CD ๋ฉด์ ‘ ์ค€๋น„๋ฅผ ์œ„ํ•ด CI/CD ๊ธฐ์ดˆ์™€ ํ”Œ๋žซํผ๋ณ„ ๋ชจ๋“ˆ์ธ GitHub Actions, GitLab CI, Jenkins์—์„œ์˜ ์‹ค์Šต์ด ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค. CI/CD ์™ธ์˜ DevOps ์˜์—ญ์— ๋Œ€ํ•ด์„œ๋Š” DevOps ๋ฉด์ ‘ ์งˆ๋ฌธ ์ข…ํ•ฉ ๊ฐ€์ด๋“œ๋ฅผ ์ฐธ๊ณ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฐ์Šต์„ ์‹œ์ž‘ํ•˜์„ธ์š”!

๋ฉด์ ‘ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์™€ ๊ธฐ์ˆ  ํ…Œ์ŠคํŠธ๋กœ ์ง€์‹์„ ํ…Œ์ŠคํŠธํ•˜์„ธ์š”.

๊ฒฐ๋ก 

  • GitHub Actions๋Š” GitHub๊ณผ์˜ ์›ํ™œํ•œ ํ†ตํ•ฉ, ํ’๋ถ€ํ•œ Marketplace, Parallel Steps ๋“ฑ ์‹ ๊ทœ ๊ธฐ๋Šฅ์œผ๋กœ ์˜คํ”ˆ์†Œ์Šค ์ƒํƒœ๊ณ„๋ฅผ ์„ ๋„ํ•˜๊ณ  ์žˆ์œผ๋‚˜, ๊ณต๊ธ‰๋ง ์œ„ํ—˜์— ๋Œ€๋น„ํ•œ SHA ๊ณ ์ •์˜ ์ฒ ์ €ํ•œ ์ ์šฉ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค
  • GitLab CI๋Š” CI/CD์™€ ๋ณด์•ˆ ์Šค์บ”์˜ ๊ธด๋ฐ€ํ•œ ํ†ตํ•ฉ์„ ์ œ๊ณตํ•˜๋ฉฐ, ๋ฒ„์ „ 18.3 ์ดํ›„ SLSA ์ธ์ฆ๊ณผ ์„ธ๋ถ„ํ™”๋œ ์ž‘์—… ํ† ํฐ ๊ถŒํ•œ ๊ด€๋ฆฌ๊ฐ€ ๊ตฌํ˜„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค
  • Jenkins๋Š” ์™„์ „ํ•œ ์ธํ”„๋ผ ์ œ์–ด๊ฐ€ ํ•„์š”ํ•œ ์กฐ์ง์— ๊ฐ€์žฅ ์œ ์—ฐํ•œ ์„ ํƒ์ง€์ด์ง€๋งŒ, 2026๋…„ 1์›”๋ถ€ํ„ฐ Java 21์ด ํ•„์ˆ˜์ด๋ฉฐ ์šด์˜ ๋น„์šฉ์ด ๋†’๋‹ค๋Š” ์ ์„ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค
  • ์‹œํฌ๋ฆฟ ๊ด€๋ฆฌ๋Š” ์„ธ ํ”Œ๋žซํผ ๋ชจ๋‘์—์„œ ๊ฐ€์žฅ ์ž์ฃผ ์ถœ์ œ๋˜๋Š” ๋ณด์•ˆ ์ฃผ์ œ์ด๋ฉฐ, ๋ฒ”์œ„ ์ง€์ • ์‹œํฌ๋ฆฟ, ๋ณดํ˜ธ ๋ณ€์ˆ˜, ์ž๊ฒฉ ์ฆ๋ช… ์ˆœํ™˜ ์ „๋žต์— ๋Œ€ํ•œ ์ง€์‹์ด ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค
  • ์บ์‹ฑ, ๋ณ‘๋ ฌํ™”, ์กฐ๊ฑด๋ถ€ ์‹คํ–‰์„ ํ†ตํ•œ ํŒŒ์ดํ”„๋ผ์ธ ์ตœ์ ํ™”๋Š” ๋ณดํŽธ์ ์ธ ์Šคํ‚ฌ์ด๋ฉฐ, ์‹ค๋ฌด ๊ฒฝํ—˜์˜ ์ฆ๊ฑฐ๋กœ์„œ ๋ฉด์ ‘๊ด€์—๊ฒŒ ๋†’์ด ํ‰๊ฐ€๋ฉ๋‹ˆ๋‹ค
  • ๋ฉด์ ‘ ์ค€๋น„ ์‹œ ๊ฐ ํ”Œ๋žซํผ์— ๋Œ€ํ•ด ์ตœ์†Œ ํ•˜๋‚˜์˜ ์‹ค์šฉ์ ์ธ ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์„ฑ์„ ์ค€๋น„ํ•˜๊ณ , ๋‹จ์ˆœํ•œ ์˜ˆ์ œ๊ฐ€ ์•„๋‹Œ ์‹ค์ „ ํŒจํ„ด์— ์ดˆ์ ์„ ๋งž์ถ”๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค

์—ฐ์Šต์„ ์‹œ์ž‘ํ•˜์„ธ์š”!

๋ฉด์ ‘ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์™€ ๊ธฐ์ˆ  ํ…Œ์ŠคํŠธ๋กœ ์ง€์‹์„ ํ…Œ์ŠคํŠธํ•˜์„ธ์š”.

ํƒœ๊ทธ

#devops
#ci-cd
#github-actions
#gitlab-ci
#jenkins
#interview

๊ณต์œ 

๊ด€๋ จ ๊ธฐ์‚ฌ

Terraform Infrastructure as Code ๋ฉด์ ‘ ์ค€๋น„ - HCL ๊ตฌ์„ฑ๊ณผ ํด๋ผ์šฐ๋“œ ํ”„๋กœ๋น„์ €๋‹ ๋‹ค์ด์–ด๊ทธ๋žจ

Terraform ๋ฉด์ ‘ ์งˆ๋ฌธ ์™„๋ฒฝ ๊ฐ€์ด๋“œ 2026: Infrastructure as Code ํ•ต์‹ฌ ์ •๋ฆฌ

Terraform ๋ฉด์ ‘์—์„œ ์ž์ฃผ ์ถœ์ œ๋˜๋Š” ์ƒํƒœ ๊ด€๋ฆฌ, ๋ชจ๋“ˆ, ์›Œํฌ์ŠคํŽ˜์ด์Šค, ํ”„๋กœ๋ฐ”์ด๋”, IaC ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ์ฒด๊ณ„์ ์œผ๋กœ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค. 2026๋…„ Terraform 1.14 ๋ฐ HCP Terraform ์ตœ์‹  ๋‚ด์šฉ์„ ๋ฐ˜์˜ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

Pod, Service, Deployment๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” Kubernetes ์•„ํ‚คํ…์ฒ˜ ๋‹ค์ด์–ด๊ทธ๋žจ

Kubernetes ๋ฉด์ ‘ ์™„๋ฒฝ ๊ฐ€์ด๋“œ: Pod, Service, Deployment ํ•ต์‹ฌ ์ •๋ฆฌ

Kubernetes ๋ฉด์ ‘์—์„œ ์ž์ฃผ ์ถœ์ œ๋˜๋Š” Pod, Service, Deployment์˜ ํ•ต์‹ฌ ๊ฐœ๋…์„ YAML ์˜ˆ์ œ์™€ ํ•จ๊ป˜ ์ƒ์„ธํžˆ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค. 2026๋…„ ์ตœ์‹  ํŠธ๋ Œ๋“œ๋ฅผ ๋ฐ˜์˜ํ•œ ์‹ค์ „ ๋Œ€๋น„ ๊ฐ€์ด๋“œ์ž…๋‹ˆ๋‹ค.

DevOps ์ธํ„ฐ๋ทฐ ํ•„์ˆ˜ ์งˆ๋ฌธ

DevOps ์ธํ„ฐ๋ทฐ ํ•„์ˆ˜ ์งˆ๋ฌธ: ์™„์ „ ๊ฐ€์ด๋“œ 2026

CI/CD, Kubernetes, Docker, Terraform, SRE ์‹ค์ฒœ์— ๊ด€ํ•œ ํ•„์ˆ˜ ์งˆ๋ฌธ์œผ๋กœ DevOps ์ธํ„ฐ๋ทฐ๋ฅผ ์ค€๋น„ํ•˜์‹ญ์‹œ์˜ค. ์ƒ์„ธํ•œ ๋‹ต๋ณ€ ํฌํ•จ.