Skip to content

필사 모드: 현대 CI/CD 파이프라인 완전 분해 — GitHub Actions, GitOps, Argo CD, BuildKit, SLSA, Sigstore, SBOM (2025)

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

> "Continuous delivery is the ability to get changes of all types into production — safely and quickly in a sustainable way." — Jez Humble (*Continuous Delivery*, 2010)

CI/CD는 지루해 보인다. "빌드 돌리고, 테스트 돌리고, 배포한다." 그러나 대형 팀과 소형 팀을 가르는 가장 큰 차이가 **CI/CD 파이프라인의 질**이라는 건 놀라운 사실이다. Google은 "커밋 → 배포"를 **분 단위**로, 대부분의 한국 기업은 **일 단위**로 한다. 이 격차는 단순한 도구 차이가 아니라, **철학과 축적된 자동화**의 차이다.

2005년의 Jenkins부터 2025년의 GitHub Actions + Argo CD + Sigstore까지. 이 글은 현대 CI/CD의 지도를 그린다.

1. CI/CD의 간단한 역사

2001 — XP와 Continuous Integration

- Kent Beck의 *Extreme Programming*이 CI를 처음 제창

- "하루 여러 번 통합"

- CruiseControl (2001) — 최초의 오픈소스 CI 서버

2005 — Hudson의 탄생

- Sun 마이크로시스템즈의 Kohsuke Kawaguchi가 개발

- Java 기반, 플러그인 천국

- 쉽고 빠르게 전 세계로 확산

2011 — Hudson → Jenkins 분할

- Oracle의 Sun 인수 후 상표권 분쟁

- 커뮤니티 대다수가 **Jenkins**로 이동

- 10년 이상 CI의 사실상 표준

2014 — 클라우드 CI 1세대

- **Travis CI** — GitHub 네이티브, YAML 설정

- **CircleCI** — 병렬화, Docker 기반 혁신

- "Jenkins 안 깔아도 된다"는 각성

2019 — GitHub Actions

- GitHub이 직접 CI를 제공

- Marketplace 액션으로 재사용 가능

- 2025년 현재 **사실상 시장 1위**

2020s — GitOps와 공급망 보안

- **Argo CD** (2018), **Flux** (2019) — Pull 기반 배포

- **Sigstore** (2021), **SLSA** (2021)

- **SBOM** 의무화 (미국 행정명령 14028, 2021)

- **AI 기반 자동 수정** (Dependabot, Renovate, Copilot)

2. Pipeline as Code — 철학의 전환

GUI의 시대

- Jenkins Freestyle 프로젝트는 **UI 클릭**으로 설정

- 재현 불가, 버전 관리 불가, 리뷰 불가

Jenkinsfile (2016) — 첫 걸음

- Groovy DSL로 파이프라인 정의

- 리포지토리에 `Jenkinsfile` 커밋

- 여전히 복잡하고 Groovy 문법

YAML의 승리

- Travis → CircleCI → GitHub Actions 모두 YAML

- 선언적, 간결, 익숙함

- `.github/workflows/*.yml` 파일이 표준

예시 — GitHub Actions

name: CI

on:

push:

branches: [main]

pull_request:

jobs:

test:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- uses: actions/setup-node@v4

with:

node-version: 20

cache: 'pnpm'

- run: pnpm install --frozen-lockfile

- run: pnpm test

재사용성 — Composite Action, Reusable Workflow

**Composite Action**: 여러 step을 하나로 묶음.

**Reusable Workflow**: 전체 워크플로우를 다른 워크플로우에서 호출.

호출

jobs:

build:

uses: myorg/shared/.github/workflows/node-build.yml@v1

with:

node-version: 20

조직 전체에 일관된 빌드 표준을 강제할 수 있음.

모범 사례

- **pin to SHA** — `actions/checkout@8e5e7e5` (버전보다 안전, Dependabot 관리)

- **Matrix build** — 여러 Node/Python 버전 동시 테스트

- **if conditions** — skip 로직

- **concurrency group** — 같은 PR에 여러 커밋 오면 이전 취소

3. 빌드 캐시 — CI 속도의 핵심

왜 캐시인가

- 빌드는 **결정론적** — 같은 입력 → 같은 출력

- 입력 해시로 출력을 조회하면 **재빌드 불필요**

로컬 캐시

- npm/pnpm의 `node_modules` 캐시

- Maven `~/.m2`, Gradle build cache

- `actions/cache@v4`로 CI 간에 공유

원격 빌드 캐시 — 모노레포의 구원

- **Turborepo** (Vercel) — 원격 캐시로 "다른 개발자가 이미 빌드한 것"을 재사용

- **Nx** (Nrwl) — 유사한 원격 캐시 + 분산 실행

- **Bazel** — Google 내부에서 시작, 가장 강력한 Hermetic build

Bazel의 Remote Execution

- 빌드 자체를 원격 클러스터에서

- 수천 코어 병렬

- Google이 모노레포에서 하루 20억 빌드하는 비결

예시 — Turborepo

{

"pipeline": {

"build": {

"dependsOn": ["^build"],

"outputs": ["dist/**"]

},

"test": {

"dependsOn": ["build"]

}

}

}

입력 해시 = 파일 내용 + dependsOn 결과의 해시. 변경 없으면 **0초에 완료**.

4. Container 기반 빌드 — BuildKit과 Nixpacks

Dockerfile의 진화

- 초기: 각 `RUN`이 레이어, 순서가 중요

- 현재: **BuildKit** (2018+)이 기본

- 병렬 빌드

- 캐시 마운트 (`--mount=type=cache`)

- 시크릿 마운트

- 멀티 아키텍처

Multi-stage Build

FROM node:20 AS builder

WORKDIR /app

COPY package*.json ./

RUN npm ci

COPY . .

RUN npm run build

FROM node:20-slim AS runtime

WORKDIR /app

COPY --from=builder /app/dist ./dist

COPY --from=builder /app/node_modules ./node_modules

CMD ["node", "dist/index.js"]

최종 이미지에는 소스/빌드 도구 없음. **크기 10배 감소**.

BuildKit Cache Mount

RUN --mount=type=cache,target=/root/.npm \

npm ci

레이어 간에 캐시 유지 → 재빌드 속도 ↑

Nixpacks / Buildpacks

- **Cloud Native Buildpacks** — Dockerfile 없이 언어 감지 → 빌드

- **Nixpacks** (Railway) — Rust로 쓴 빠른 빌더

- 단순 앱에는 훌륭, 복잡하면 Dockerfile로

Distroless 이미지

- `gcr.io/distroless/nodejs20-debian12`

- Shell 없음, 공격면 최소

- 구글 표준, 보안 감사에 유리

5. Test 병렬화 — CI 시간 반으로

Sharding

- 테스트를 N개 조각으로 분할

- 각 조각을 독립 runner에서 실행

strategy:

matrix:

shard: [1, 2, 3, 4]

steps:

- run: npx jest --shard=${{ matrix.shard }}/4

지능적 할당

- 이전 실행 시간 기반으로 균등 분배 (Jest `--shard`, Nx 분산 실행)

- **hot shard** 문제 방지

Flaky Test 대응

- Flaky = 같은 코드인데 때때로 실패

- 원인: 타이밍, 공유 상태, 네트워크

- 전략:

- **재시도** (선택적, 남용 금지)

- **격리** (Flaky 목록 분리 실행)

- **뿌리 수정** — 가장 중요

E2E 병렬화

- Playwright `workers` 옵션

- 독립 DB 스키마, 독립 포트

- 상태 격리가 핵심

6. Artifact Management

OCI Registry — 이미지 저장소

- **GitHub Container Registry (GHCR)** — 무료, GitHub 연동

- **Docker Hub** — 역사적, 레이트 리밋

- **AWS ECR, Google Artifact Registry, Azure ACR** — 클라우드 네이티브

- **Harbor, Artifactory** — 엔터프라이즈

OCI는 이미지 이상을 저장한다

- Helm chart

- Python wheel (oci-python)

- Terraform module

- SBOM, provenance

**OCI = 콘텐츠 주소 가능한 저장소 프로토콜**이 되고 있음.

Semantic Tagging

v1.2.3 — 고정 버전

v1.2 — minor 고정

v1 — major 고정

latest — 최신 (prod에서 금지!)

sha-abc1234 — 커밋 기반 (추적 가능)

Pull-through Cache

- 사내 registry가 외부 registry를 캐시

- Docker Hub 레이트 리밋 회피

- 네트워크 지연 감소

7. Secrets Management — OIDC의 혁명

구시대 — 장기 자격증명

- `AWS_ACCESS_KEY_ID`를 CI secrets에 저장

- 유출되면 재앙

- 갱신 부담

OIDC 기반 — Keyless

- GitHub Actions가 자신을 증명하는 **OIDC 토큰** 발급

- AWS/GCP/Azure가 그 토큰을 신뢰 → **임시 자격증명** 발급

- 장기 비밀이 **아예 존재하지 않음**

예시 — AWS

permissions:

id-token: write

steps:

- uses: aws-actions/configure-aws-credentials@v4

with:

role-to-assume: arn:aws:iam::123:role/GitHubActions

aws-region: us-east-1

Vault / External Secrets

- HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager

- **External Secrets Operator** — K8s에서 자동 주입

- Secret rotation이 실제로 작동

SOPS — 암호화된 시크릿 git에 저장

- Mozilla SOPS (Secrets Operations)

- KMS/PGP로 암호화된 YAML/JSON

- GitOps 친화적

8. GitOps — Pull 모델의 우아함

Push vs Pull 배포

**Push (전통)**: CI가 kubectl apply로 직접 배포

- CI가 클러스터 자격 증명을 가져야 함 (보안 위험)

- 상태 drift 탐지 어려움

**Pull (GitOps)**: 클러스터가 git을 주기적으로 확인

- 자격 증명 CI에 노출 안됨

- **Git = 단일 진실 소스**

- drift 탐지/자동 복구

4원칙 (OpenGitOps)

1. **Declarative** — 원하는 상태를 선언

2. **Versioned & Immutable** — git에 기록

3. **Pulled Automatically** — 에이전트가 적용

4. **Continuously Reconciled** — 항상 감시

Argo CD

- CNCF Graduated

- 웹 UI가 강력 — 앱별 상태, diff, sync

- Application CRD로 선언

- Kustomize/Helm 네이티브 지원

- Multi-cluster 지원

Flux

- CNCF Graduated

- CLI 중심, Argo보다 가벼움

- GitOps Toolkit로 모듈화

예시 — Argo CD Application

apiVersion: argoproj.io/v1alpha1

kind: Application

metadata:

name: my-app

spec:

source:

repoURL: https://github.com/org/infra

path: apps/my-app

targetRevision: main

destination:

server: https://kubernetes.default.svc

namespace: my-app

syncPolicy:

automated:

prune: true

selfHeal: true

Argo Rollouts — Progressive Delivery와 통합

앞선 글 "Feature Flag & Progressive Delivery"와 연결:

- Canary/Blue-Green을 Kubernetes 네이티브로

- Analysis Template로 자동 rollback

9. Supply Chain Security — 2020년 이후 대격변

SolarWinds 충격 (2020)

- 해커가 **빌드 시스템**에 침투

- 악성 코드를 정상 소프트웨어에 주입

- 18,000+ 고객에 배포

- **CI/CD 자체가 공격 대상**임을 드러냄

SLSA — Supply chain Levels for Software Artifacts

Google 주도, OpenSSF로 이관. 4단계 성숙도:

| 레벨 | 요구사항 |

|---|---|

| L0 | 요구사항 없음 |

| L1 | 빌드가 자동화 + 기본 provenance |

| L2 | 버전 관리 + provenance 생성 서명 |

| L3 | Hardened build (isolated, hermetic) |

| L4 | 2-party review + hermetic, reproducible |

대부분의 기업은 L2-L3이 현실적 목표.

Provenance — 무엇을, 어떻게 빌드했나

- 어떤 소스(git SHA)

- 어떤 빌더(GitHub Actions runner)

- 어떤 의존성

- 어떤 파라미터

- **in-toto attestation** 형식

Sigstore — "무료 서명 인프라"

- Linux Foundation 프로젝트

- **Cosign** — 이미지/아티팩트 서명

- **Fulcio** — keyless 인증서 발급 (OIDC 기반)

- **Rekor** — 투명성 로그

cosign sign --yes ghcr.io/org/image:v1.0.0

cosign verify --certificate-identity "..." ghcr.io/org/image:v1.0.0

키 관리 없이도 서명 가능 — **Keyless 서명**의 혁명.

SBOM — Software Bill of Materials

- 빌드 결과물에 포함된 **모든 의존성 목록**

- 포맷: **SPDX**, **CycloneDX**

- 미국 행정명령 14028 — 연방 정부 납품 필수

- EU CRA (Cyber Resilience Act) — 2025-2027 시행

도구

- **Syft** — SBOM 생성 (Anchore)

- **Grype** — CVE 스캔 (SBOM 기반)

- **Trivy** — 통합 스캐너 (Aqua)

- **Dependency-Track** — SBOM 집중 관리

Provenance 검증 in Kubernetes

- **Kyverno / OPA Gatekeeper** 정책으로 "서명되지 않은 이미지 거부"

- 클러스터 수준에서 enforce

10. 배포 전략 — 안전하게 푸는 기술

(상세는 앞선 "Feature Flag & Progressive Delivery" 글 참조, 여기서는 CI/CD 관점)

Rolling Update

- K8s 기본값, 점진적 pod 교체

- maxSurge/maxUnavailable 튜닝

- 간단하지만 rollback이 단순 이미지 교체

Blue/Green

- 두 환경 병행, LB 스위칭

- 빠른 rollback (LB만 전환)

- 비용 2배

Canary

- 1%, 5%, 25%, 100% 단계적 노출

- 지표 확인 + 자동 진행/회귀

- Argo Rollouts, Flagger 활용

Feature Flag

- 코드는 모두 배포, **플래그로 노출 제어**

- 가장 유연, 코드 복잡도 증가

11. Dev Loop Speed — "5분 철학"

구글 내부 원칙 중 하나: "커밋 → 배포 가능 상태까지 5분 이내."

기법

1. **Incremental build** — 변경된 것만

2. **Test selection** — 관련 테스트만 (Bazel, Nx)

3. **Distributed execution** — Remote execution

4. **Parallel pipeline** — 독립 job 동시 실행

5. **Warm runner** — self-hosted + 캐시 볼륨

6. **Pre-commit hook** — 로컬에서 lint/format

측정 — DORA Metrics

2014년 Google DORA 팀이 제시한 4대 지표:

1. **Deployment Frequency** — 배포 빈도

2. **Lead Time for Changes** — 커밋 → 프로덕션 시간

3. **Change Failure Rate** — 배포 실패율

4. **Time to Restore Service** — 장애 복구 시간

Elite 팀:

- 배포: 하루 여러 번

- Lead Time: 1시간 미만

- 실패율: 15% 미만

- 복구: 1시간 미만

12. 실전 예시 — 현대적 풀스택 파이프라인

name: Full CI/CD

on:

push:

branches: [main]

pull_request:

concurrency:

group: ${{ github.workflow }}-${{ github.ref }}

cancel-in-progress: true

permissions:

contents: read

id-token: write

packages: write

attestations: write

jobs:

test:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4

- uses: actions/setup-node@v4

with:

node-version: 20

cache: 'pnpm'

- run: pnpm install --frozen-lockfile

- run: pnpm lint

- run: pnpm test --coverage

- uses: codecov/codecov-action@v5

build:

needs: test

runs-on: ubuntu-latest

outputs:

digest: ${{ steps.build.outputs.digest }}

steps:

- uses: actions/checkout@v4

- uses: docker/setup-buildx-action@v3

- uses: docker/login-action@v3

with:

registry: ghcr.io

username: ${{ github.actor }}

password: ${{ secrets.GITHUB_TOKEN }}

- id: build

uses: docker/build-push-action@v6

with:

push: true

tags: ghcr.io/${{ github.repository }}:${{ github.sha }}

cache-from: type=gha

cache-to: type=gha,mode=max

provenance: true

sbom: true

sign:

needs: build

runs-on: ubuntu-latest

steps:

- uses: sigstore/cosign-installer@v3

- run: |

cosign sign --yes \

ghcr.io/${{ github.repository }}@${{ needs.build.outputs.digest }}

deploy:

needs: sign

if: github.ref == 'refs/heads/main'

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

with:

repository: ${{ github.repository_owner }}/infra-gitops

token: ${{ secrets.GITOPS_TOKEN }}

- name: Update image tag

run: |

yq -i '.image.tag = "${{ github.sha }}"'

apps/my-app/values.yaml

- run: |

git config user.name github-actions

git config user.email github-actions@github.com

git commit -am "deploy: ${{ github.sha }}"

git push

Argo CD가 이후 자동 sync

이 한 파일에:

- 테스트 + 커버리지

- 멀티 스테이지 빌드 + GHA 캐시

- Provenance + SBOM 자동 생성

- Keyless 서명 (Cosign + Fulcio)

- GitOps 푸시 → Argo CD가 배포

13. 안티패턴 TOP 10

1. **Latest 태그 배포** — 재현 불가, 디버그 지옥

2. **CI에 장기 자격 증명 저장** — OIDC 써라

3. **메인 브랜치 직접 빌드/배포** — Branch protection 필수

4. **Flaky test 재시도로 가림** — 근본 원인 수정

5. **`npm install` (vs `npm ci`)** — lockfile 존중 안 함

6. **CI에서 `sudo apt install`** — 빌드 환경 오염, 느림

7. **Secret을 로그에 echo** — GitHub이 일부 마스킹하지만 주의

8. **Pipeline 없이 개별 CI 스크립트** — 일관성 부재

9. **서명 없는 이미지 배포** — SolarWinds 재현 가능

10. **빌드 시간 30분 이상 방치** — 개발 속도 마비

14. 현대 CI/CD 체크리스트

- [ ] **Pipeline as Code** — YAML이 리포지토리에

- [ ] **Branch protection** + **required status checks**

- [ ] **Concurrency control** — PR 중복 실행 취소

- [ ] **Build cache** — actions/cache 또는 Turborepo/Nx

- [ ] **Multi-stage Docker build** — 작은 이미지

- [ ] **OIDC 인증** — 장기 key 제거

- [ ] **테스트 병렬화** — shard + 재시도 전략

- [ ] **SBOM + Provenance** 자동 생성

- [ ] **Cosign keyless signing**

- [ ] **Argo CD/Flux** — pull 기반 배포

- [ ] **DORA 메트릭** 대시보드

- [ ] **배포 rollback 15분 이내 가능** 훈련

마치며 — CI/CD는 문화다

CI/CD는 도구 선택이 아니라 **문화**다. GitHub Actions냐 Jenkins냐보다, "커밋하면 15분 안에 staging에 가는가?" "금요일 오후 6시에도 배포할 수 있는가?" "배포 실패 시 1시간 안에 복구되는가?"가 훨씬 중요하다.

공급망 보안의 시대에는 한 걸음 더 나아가야 한다. "내가 빌드한 이것이 **정확히 어떤 소스에서, 어떤 경로로** 나왔는가?"를 서명된 증거로 남기는 것. SolarWinds 이후, 이 질문에 답하지 못하는 조직은 규제/고객 감사에서 걸러진다.

> "Slow is smooth, and smooth is fast. But in CI/CD, fast is safe — because you catch problems before they compound." — Charity Majors (Honeycomb)

다음 글 예고 — 프론트엔드 번들러의 내전 — Webpack, Vite, esbuild, Turbopack, Rspack, Rolldown (2026)

CI/CD가 배포의 혈관이라면, **번들러**는 프론트엔드 빌드의 심장이다. 다음 글에서는:

- **번들링의 역사** — Browserify → Webpack의 독점 → JS 런타임 전쟁

- **Webpack** — 왜 승자였고, 왜 내려가는가

- **esbuild** — Go의 위력, 100배 빠른 빌드

- **Vite** — Evan You의 "개발은 ESM, 빌드는 Rollup"

- **Turbopack** — Vercel의 Rust 베팅

- **Rspack** — 바이트댄스의 Rust Webpack

- **Rolldown** — Vite의 다음 진화 (2025)

- **Bun bundler** — 번들 + 런타임 + 패키지 매니저 통합

- **Tree-shaking, Code splitting, HMR** — 기저 기술

- **Module Federation** — 마이크로 프론트엔드

- **ESM in production** — import maps의 부상

"빌드 시간 3초" 시대를 가능케 한 Rust/Go 혁명을 해부하는 여정.

> "The best CI/CD pipeline is the one you don't notice. It just works, every time, for everyone." — Kelsey Hightower

현재 단락 (1/381)

CI/CD는 지루해 보인다. "빌드 돌리고, 테스트 돌리고, 배포한다." 그러나 대형 팀과 소형 팀을 가르는 가장 큰 차이가 **CI/CD 파이프라인의 질**이라는 건 놀라운 사실...

작성 글자: 0원문 글자: 10,553작성 단락: 0/381