🚀 DevOps — CI/CD 파이프라인
📖 CI/CD 개념과 원리
CI/CD는 Continuous Integration(지속적 통합)과 Continuous Delivery/Deployment(지속적 전달/배포)의 약자로, 소프트웨어를 개발하고 배포하는 과정을 자동화하는 방법론이다.
🍞 비유: 빵 공장
- CI/CD 없는 개발 — 빵을 하나하나 손으로 만든 뒤, 다 만들고 나서야 맛을 확인. 100개를 만든 뒤 "밀가루 비율이 틀렸다"는 걸 알게 되면 전부 폐기.
- CI/CD 있는 개발 — 컨베이어 벨트 위에서 반죽 → 발효 → 성형 → 굽기 → 품질 검사까지 자동. 반죽 단계 문제도 즉시 알림.
🔄 CI — Continuous Integration
여러 개발자가 작업한 코드를 하루에도 여러 번 공유 저장소에 합치고, 합칠 때마다 자동으로 빌드와 테스트를 실행한다.
flowchart LR
DEV([개발자]) -->|git push| REPO[(Git Repository)]
REPO -->|webhook 트리거| CI[CI Server
GitHub Actions · Jenkins] CI --> BLD[Build
컴파일·번들] BLD --> TST[Test
unit · lint] TST --> PKG[Package
Docker image · artifact] PKG -->|성공| OK([✅ 통합 완료]) TST -.실패.-> NOTIFY[❌ 개발자 알림]
GitHub Actions · Jenkins] CI --> BLD[Build
컴파일·번들] BLD --> TST[Test
unit · lint] TST --> PKG[Package
Docker image · artifact] PKG -->|성공| OK([✅ 통합 완료]) TST -.실패.-> NOTIFY[❌ 개발자 알림]
🚢 CD — Delivery vs Deployment
| 구분 | Continuous Delivery | Continuous Deployment |
|---|---|---|
| 배포 방식 | 수동 승인 후 배포 | 자동 배포 |
| 사람 개입 | 필요 (승인 단계) | 불필요 |
| 적합 상황 | 금융·의료 등 신중 배포 | 빠른 반복이 중요한 웹 서비스 |
| 비유 | 포장 완료, 출고 대기 | 로봇이 자동으로 배송 차량에 탑재 |
🔧 CI/CD 파이프라인 표준 단계
- Source — 코드 변경 감지 (git push, PR 생성)
- Build — 컴파일 · Docker 이미지 빌드
- Test — 단위 테스트 · 통합 테스트 · 보안 스캔
- Deploy — 스테이징 또는 운영 배포
- Monitor — 배포 후 서비스 상태 모니터링
비유: 수도관(파이프) — 수도꼭지(Source)에서 물(코드)이 들어가 정수 필터(Build/Test)를 거쳐 수도관 끝(운영 서버)에서 깨끗한 물(검증된 코드)이 나온다. 필터가 막히면(테스트 실패) 물은 더 이상 흐르지 않는다.
🛠️ 대표 CI/CD 도구 비교
| 도구 | 특징 | 비용 |
|---|---|---|
| GitHub Actions | GitHub 내장, YAML 기반, 클라우드 실행 | 퍼블릭 무료, 프라이빗 월 2,000분 무료 |
| Jenkins | 오픈소스, 자체 서버, 플러그인 1,800+ | 무료 (서버 비용 별도) |
| GitLab CI | GitLab 내장, Docker 기반 Runner | 퍼블릭 프로젝트 무료 |
| AWS CodePipeline | AWS 서비스 긴밀 통합 | 파이프라인당 월 $1 |
⚡ GitHub Actions
GitHub 저장소에 내장된 CI/CD 도구. 별도 서버 없이 .github/workflows/에 YAML 파일 하나로 자동화가 가능하다.
핵심 용어 — 회사 조직도 비유
| 용어 | 설명 | 비유 |
|---|---|---|
| Workflow | 전체 자동화 프로세스 (YAML 파일) | 회사 SOP 문서 |
| Event | Workflow 시작 트리거 (push/PR/schedule) | "이 상황이면 시작" 신호 |
| Job | 병렬·순차 실행되는 작업 단위 | 회사의 부서 |
| Step | Job 안에서 순서대로 실행되는 개별 명령 | 부서 안의 업무 체크리스트 |
| Action | 재사용 가능한 단위 기능 (마켓플레이스) | 외주 용역 업체 |
| Runner | Workflow가 실행되는 VM | 임시 직원 (끝나면 사라짐) |
기본 구조
# .github/workflows/ci.yml
name: CI Pipeline
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: 저장소 체크아웃
uses: actions/checkout@v4
- name: Python 설정
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: 의존성 설치
run: pip install -r requirements.txt
- name: 테스트 실행
run: python -m pytest
키워드:
on = 트리거 · runs-on = 실행 환경 · uses = 마켓플레이스 Action(owner/repo@version) · run = 쉘 명령 · with = Action 입력값
📝 Actions 실전: Docker → ECR 푸시
name: Build and Push to ECR
on:
push:
branches: [ main ]
env:
AWS_REGION: ap-northeast-2
ECR_REPOSITORY: my-app
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: AWS 자격증명 설정
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: ECR 로그인
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Docker 이미지 빌드 및 푸시
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
🔐 Secrets 관리
- 경로: Settings → Secrets and variables → Actions → New repository secret
- YAML에 API 키·비밀번호 직접 작성 금지 — 로그에서
***로 자동 마스킹 - Organization 레벨에서 공유 Secrets 설정 시 여러 저장소 재사용 가능
- Fork된 저장소의 PR에서는 Secrets 접근 불가 (보안 설계)
🧪 Matrix Strategy — 여러 환경 동시 테스트
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.9', '3.10', '3.11']
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- run: python -m pytest
💾 캐싱으로 빌드 단축
- name: 의존성 캐시
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
🔨 Jenkins
Java로 만들어진 오픈소스 CI/CD 자동화 서버. 전 세계 기업 환경에서 가장 널리 쓰이는 CI/CD 도구.
비유: GitHub Actions가 관리 사무소에서 대신 돌려주는 서비스라면, Jenkins는 내가 직접 짓고 운영하는 단독 주택. 설계부터 인테리어까지 전부 내 손으로, 대신 완전한 자유.
선택 이유 3가지
- 완전한 제어권 — 빌드 서버·실행 환경·보안 정책 모두 직접 관리 (금융/의료 적합)
- 1,800+ 플러그인 — Git, Docker, Slack, AWS, Kubernetes 등 거의 모든 도구 연동
- 복잡한 파이프라인 자유 설계 — Groovy 스크립트(Jenkinsfile)로 조건 분기·병렬·승인 단계 표현
🏗️ Controller-Agent 아키텍처
| 구성 | 역할 | 비유 |
|---|---|---|
| Controller (Master) | 작업 스케줄링 · Web UI · 설정 관리 | 건설 현장 현장소장 |
| Agent (Slave) | 실제 빌드/테스트 수행 (VM · Docker · EC2) | 현장 작업자들 — 병렬 가능 |
🐳 Docker로 설치
docker run -d \
--name jenkins \
-p 8080:8080 \
-p 50000:50000 \
-v jenkins_home:/var/jenkins_home \
jenkins/jenkins:lts
# 초기 관리자 비밀번호 확인
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
-p 8080= Web UI ·-p 50000= Agent 통신 포트-v jenkins_home= Docker 볼륨에 설정·빌드 데이터 유지:lts= 장기지원(안정) 버전
📄 Jenkinsfile — 파이프라인 설계도
프로젝트 루트에 Jenkinsfile을 두면 Jenkins가 자동으로 읽어 실행한다. 실무 표준은 Declarative Pipeline이다.
기본 구조
pipeline {
agent any
stages {
stage('빌드') {
steps { sh 'echo "빌드 중..."' }
}
stage('테스트') {
steps { sh 'echo "테스트 중..."' }
}
stage('배포') {
steps { sh 'echo "배포 중..."' }
}
}
}
| 키워드 | 역할 | 비유 |
|---|---|---|
pipeline | 최상위 블록 | 레시피 책 전체 |
agent | 실행 환경 지정 | 어떤 주방에서 요리할지 |
stages | 단계들의 목록 | 레시피 전체 순서 |
stage | 하나의 단계 | "파 5분 섯는다" |
steps | 단계 안 실제 명령 | "175°C로 예열" |
실전 예제 — Spring Boot + Docker
pipeline {
agent any
environment {
DOCKER_IMAGE = 'myapp'
DOCKER_TAG = "${env.BUILD_NUMBER}"
}
stages {
stage('체크아웃') { steps { checkout scm } }
stage('빌드') {
steps { sh './gradlew clean build -x test' }
}
stage('테스트') {
steps { sh './gradlew test' }
post {
always { junit '**/build/test-results/**/*.xml' }
}
}
stage('Docker 이미지 빌드') {
steps {
sh "docker build -t ${DOCKER_IMAGE}:${DOCKER_TAG} ."
}
}
stage('배포') {
when { branch 'main' }
steps {
sh "docker stop ${DOCKER_IMAGE} || true"
sh "docker run -d --name ${DOCKER_IMAGE} -p 8080:8080 ${DOCKER_IMAGE}:${DOCKER_TAG}"
}
}
}
post {
success { echo '파이프라인 성공!' }
failure { echo '파이프라인 실패 - 로그 확인' }
}
}
🔑 핵심 문법
environment + credentials
environment {
DB_HOST = 'db.example.com'
DB_PASSWORD = credentials('db-password-id') // Jenkins 금고에서 참조
}
→ 로그에 ****로 자동 마스킹. 코드에 비밀번호 직접 작성 금지.
when — 조건부 실행
stage('운영 배포') {
when { branch 'main' }
steps { /* ... */ }
}
stage('스테이징') {
when { branch 'develop' }
steps { /* ... */ }
}
post — 결과 후처리
post {
always { cleanWs() }
success { slackSend channel: '#deploys', message: "배포 성공: #${env.BUILD_NUMBER}" }
failure { slackSend channel: '#alerts', color: 'danger', message: "빌드 실패" }
}
parallel — 병렬 실행
stage('테스트') {
parallel {
stage('단위 테스트') { steps { sh './gradlew test' } }
stage('통합 테스트') { steps { sh './gradlew integrationTest' } }
stage('코드 분석') { steps { sh './gradlew sonarqube' } }
}
}
→ 한 명이 3시간 걸릴 일을 세 명이 나누면 1시간.
🪝 Webhook 자동 트리거
- Git 저장소 Settings → Webhooks
- Payload URL:
http://<jenkins>:8080/github-webhook/ - Jenkins에서 GitHub hook trigger for GITScm polling 활성화
🔌 실무 필수 플러그인
- Pipeline — Jenkinsfile 실행 (필수)
- Git / Docker Pipeline / Credentials Binding
- Slack Notification — 빌드 결과 알림
- Blue Ocean — 파이프라인 시각화 모던 UI
⚖️ GitHub Actions vs Jenkins 선택 가이드
| 항목 | GitHub Actions | Jenkins |
|---|---|---|
| 설치/운영 | 불필요 (SaaS) | 서버 직접 운영 |
| 설정 방식 | YAML (.github/workflows/) | Groovy (Jenkinsfile) |
| 러닝커브 | 낮음 | 중간~높음 |
| 보안 | GitHub Secrets | Credentials + 자체 격리 |
| 플러그인 | 마켓플레이스 Actions | 1,800+ 플러그인 |
| 적합 상황 | GitHub 사용 중·스타트업·오픈소스 | 온프레미스·금융·커스텀 요구 많음 |
실전 팁:
① 테스트 자동화가 CI/CD의 전제 — 테스트 없는 파이프라인은 "자동 빌드 머신"에 불과 ·
② 처음부터 완벽할 필요 없음 —
git push → 빌드 → 테스트 1~2개로 시작 ·
③ CI 없이 CD는 위험 — 검증 없는 자동 배포는 장애를 자동 발생시킬 뿐.