📋 전체 학습 목차 (14개 섹션)
🚀 Section 01. DevOps란? 배포의 A-Z 전체 그림
개발자가 만든 코드가 어떻게 전 세계 사용자에게 도달하는가
🍕 피자 배달로 이해하는 배포
피자 가게를 운영한다고 상상해보세요. 개발자 = 요리사, 코드 = 레시피, 서버 = 주방, 사용자 = 손님. 레시피가 아무리 완벽해도 손님에게 배달되지 않으면 의미가 없습니다!
| 배포 개념 | 피자 가게 비유 | 실제 기술 |
|---|---|---|
| 코드 작성 | 새 레시피 개발 | git commit, push |
| 빌드 | 재료 손질 + 반죽 | npm run build |
| 테스트 | 맛 검수 | npm run test |
| 컨테이너화 | 피자박스 포장 | docker build |
| 배포 | 배달 완료 | docker compose up |
| 모니터링 | 고객 만족도 확인 | Prometheus + Grafana |
🔄 DevOps = Dev + Ops 문화 혁명
📊 DevOps 도입 후 실제 효과 (DORA 리서치)
🗺️ DevOps 전체 도구 생태계
🐧 Section 02. Linux 서버 완전 정복
서버의 96%가 Linux — 백엔드 개발자의 기본 무기
🔑 SSH 서버 접속부터 시작
🛠️ 필수 Linux 명령어 완전 정리
| 카테고리 | 명령어 | 용도 & 예시 |
|---|---|---|
| 📂 파일 탐색 | ls -la / cd / pwd | ls -la /var/log (숨김포함 상세) |
| 📝 파일 내용 | cat / tail / grep | tail -f app.log | grep ERROR |
| ⚙️ 프로세스 | ps / kill / top / htop | ps aux | grep node |
| 🌐 네트워크 | ss / curl / netstat | ss -tulnp | grep 3000 |
| 💾 디스크/메모리 | df -h / free -h | df -h (장애 시 디스크 풀 확인) |
| 🔐 권한 | chmod / chown / sudo | chmod 755 deploy.sh |
| 🔧 서비스 | systemctl / journalctl | journalctl -u nginx -f |
🔐 방화벽(UFW) + 서버 보안 기초
📜 배포 자동화 셸 스크립트
🐳 Section 03. Docker 완전 정복 (기초~고급)
"내 컴에선 되는데요"를 영원히 없애주는 기술
🍱 도시락 비유로 이해하기
도시락은 어디서 먹든 항상 같은 내용물! Docker도 마찬가지입니다.
📝 Dockerfile 완전 가이드 — NestJS 프로덕션용 (멀티스테이지)
RUN npm ci --only=production && npm cache clean --force
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
RUN addgroup -g 1001 -S nodejs && adduser -S nestjs -u 1001
COPY --from=builder --chown=nestjs:nodejs /app/dist ./dist
COPY --from=deps --chown=nestjs:nodejs /app/node_modules ./node_modules
USER nestjs
EXPOSE 3000
CMD wget -qO- http://localhost:3000/health || exit 1
CMD ["node", "dist/main.js"]
⚡ Docker 핵심 명령어 A-Z
🎼 Section 04. Docker Compose 멀티 컨테이너
NestJS + PostgreSQL + Redis + Nginx을 한 파일로!
📄 실전 docker-compose.yml (프로덕션 풀스택)
build:
context: .
target: production
container_name: nestjs-app
restart: unless-stopped
ports: ["3000:3000"]
env_file: [.env.production]
depends_on:
postgres: {condition: service_healthy}
redis: {condition: service_healthy}
healthcheck:
test: ["CMD","wget","-qO-","http://localhost:3000/health"]
interval: 30s
retries: 3
networks: [backend]
logging:
driver: "json-file"
options: {max-size: "10m", max-file: "3"}
image: postgres:16-alpine
container_name: postgres-db
restart: unless-stopped
environment:
POSTGRES_DB: ${DB_NAME}
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes: [pgdata:/var/lib/postgresql/data]
healthcheck:
test: ["CMD-SHELL","pg_isready -U ${DB_USER}"]
interval: 10s
retries: 5
ports: ["127.0.0.1:5432:5432"]
networks: [backend]
image: redis:7-alpine
container_name: redis-cache
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD} --maxmemory 256mb
volumes: [redisdata:/data]
healthcheck:
test: ["CMD","redis-cli","-a","${REDIS_PASSWORD}","ping"]
interval: 10s
networks: [backend]
image: nginx:1.25-alpine
container_name: nginx-proxy
restart: unless-stopped
ports: ["80:80","443:443"]
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- certbot-etc:/etc/letsencrypt
depends_on: [app]
networks: [backend]
⚡ Docker Compose 핵심 명령어
🌐 Section 05. Nginx 리버스 프록시 + HTTPS
도메인 연결 · SSL · 로드밸런싱 · Rate Limiting — 실서비스 필수
🏨 호텔 프런트 데스크 비유
손님(사용자)은 항상 프런트(Nginx :443)에 옵니다. 어느 방(포트)으로 갈지는 프런트가 결정. 손님은 방 번호(:3000)를 몰라도 됩니다 → 보안!
server_name api.myapp.com;
return 301 https://$host$request_uri;
server_name api.myapp.com;
ssl_certificate /etc/letsencrypt/live/api.myapp.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.myapp.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header Strict-Transport-Security "max-age=63072000" always;
location /api {
limit_req zone=api burst=20 nodelay;
proxy_pass http://nestjs;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
🔒 Let's Encrypt 무료 SSL 발급
⚙️ Section 06. PM2 프로세스 관리 + 무중단 배포
서버 꺼도 앱이 살아있는 비결 — 클러스터 모드로 성능 2배
📄 ecosystem.config.js — 현업 수준 설정
⚡ PM2 핵심 명령어
⚙️ Section 07. GitHub Actions CI/CD 완전정복
push 한 번 → 테스트 → 빌드 → 배포 — 완전 자동화!
🏭 CI/CD 파이프라인 전체 흐름
build+push
배포(EC2)
운영중
📄 .github/workflows/deploy.yml 완전 구현
pull_request: {branches: [main]}
IMAGE_NAME: ${{ github.repository }}
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env: {POSTGRES_PASSWORD: testpass, POSTGRES_DB: testdb}
ports: ['5432:5432']
options: --health-cmd pg_isready
redis:
image: redis:7
ports: ['6379:6379']
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: {node-version: '20', cache: 'npm'}
- run: npm ci
- run: npm run lint
- run: npm run test:cov
- run: npm run test:e2e
env:
DATABASE_URL: postgresql://postgres:testpass@localhost:5432/testdb
REDIS_URL: redis://localhost:6379
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
permissions: {contents: read, packages: write}
steps:
- uses: actions/checkout@v4
- name: GHCR 로그인
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: 빌드 & 푸시
uses: docker/build-push-action@v5
with:
push: true
target: production
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max
needs: build
runs-on: ubuntu-latest
environment: production
steps:
- name: EC2 SSH 배포
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.EC2_HOST }}
username: ubuntu
key: ${{ secrets.EC2_SSH_KEY }}
script: |
cd /app
docker compose pull app
docker compose up -d --no-deps --remove-orphans app
docker image prune -f
echo "✅ 배포완료: $(date)"
🔑 GitHub Secrets 설정 (Settings → Secrets → Actions)
| EC2_HOST | EC2 퍼블릭 IP |
| EC2_SSH_KEY | .pem 파일 전체 내용 |
| GITHUB_TOKEN | 자동 제공 (설정 불필요) |
☁️ Section 08. AWS EC2 + RDS + S3 실전 배포
국내 스타트업 70%가 선택 — 처음부터 프로덕션까지
🏗️ AWS 핵심 서비스 완전 정리
| 서비스 | 역할 | 비유 | 월 비용 |
|---|---|---|---|
| EC2 t3.small | 가상 서버 | 임대 컴퓨터 | ~$17 |
| RDS (PostgreSQL) | 관리형 DB | 전문 창고 관리인 | ~$25 |
| S3 | 객체 스토리지 | 무한 USB | ~$0.023/GB |
| ElastiCache | 관리형 Redis | 초고속 메모 | ~$20 |
| ALB | 로드 밸런서 | 고객 안내 데스크 | ~$20 |
| CloudFront | CDN | 전국 배송 허브 | ~$0.0085/GB |
🚀 EC2 서버 초기화 스크립트 (한 번에 실행)
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl git unzip htop fail2ban
# Docker 공식 설치
curl -fsSL https://get.docker.com | sudo bash
sudo usermod -aG docker ubuntu
sudo apt install -y docker-compose-plugin
# Node.js 20
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -
sudo apt install -y nodejs
sudo npm install -g pm2
# Nginx
sudo apt install -y nginx certbot python3-certbot-nginx
# UFW 방화벽
sudo ufw allow 22 && sudo ufw allow 80 && sudo ufw allow 443 && sudo ufw --force enable
# 앱 디렉토리
sudo mkdir -p /app && sudo chown ubuntu:ubuntu /app
echo "✅ 서버 초기 세팅 완료!"
🗄️ S3 파일 업로드 — NestJS + AWS SDK v3
@Injectable()
export class S3Service {
private readonly s3 = new S3Client({
region: process.env.AWS_REGION,
credentials: { accessKeyId: process.env.AWS_ACCESS_KEY_ID, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY },
});
async upload(file: Express.Multer.File, folder = 'uploads') {
const key = `${folder}/${Date.now()}-${file.originalname}`;
await this.s3.send(new PutObjectCommand({ Bucket: process.env.AWS_S3_BUCKET, Key: key, Body: file.buffer, ContentType: file.mimetype }));
return `https://${process.env.AWS_S3_BUCKET}.s3.amazonaws.com/${key}`;
}
async getPresignedUrl(key: string) {
return getSignedUrl(this.s3, new GetObjectCommand({ Bucket: process.env.AWS_S3_BUCKET, Key: key }), { expiresIn: 3600 });
}
}
🔐 Section 09. 환경변수 & 시크릿 관리
비밀번호를 코드에 박으면 AWS 요금 폭탄! 올바른 관리법
🚨 절대 하면 안 되는 것!
const awsKey = 'AKIAIOSFODNN7EXAMPLE';
const jwt = 'super-secret';
const awsKey = process.env.AWS_ACCESS_KEY_ID;
const jwt = process.env.JWT_SECRET;
📋 환경별 .env 파일 구조
PORT=3000
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp_dev
DB_PASSWORD=devpass
JWT_SECRET=dev-secret-key
REDIS_URL=redis://localhost:6379
PORT=3000
DB_HOST=mydb.xxx.rds.amazonaws.com
DB_PORT=5432
DB_NAME=myapp_prod
DB_PASSWORD=[절대 커밋 금지]
JWT_SECRET=[최소 32자 랜덤]
AWS_S3_BUCKET=myapp-prod
.env.local
.env.development
.env.production
🔒 NestJS ConfigModule + Joi 검증
🏆 시크릿 관리 도구 비교
| 도구 | 추천 상황 | 비용 |
|---|---|---|
| .env 파일 | 로컬 개발, 소규모 | 무료 |
| GitHub Secrets | CI/CD 파이프라인 | 무료 |
| AWS Secrets Manager | AWS 프로덕션 | $0.4/시크릿/월 |
| HashiCorp Vault | 대규모 엔터프라이즈 | 오픈소스/유료 |
📊 Section 10. 모니터링 & 로깅 완전 정복
장애 전에 알아채기 — Prometheus + Grafana + Winston
👀 4 Golden Signals (Google SRE 핵심 지표)
P95 <200ms 목표
초당 요청 수(RPS)
5xx <0.1% 목표
CPU/메모리 <80%
📦 NestJS Winston 구조화 로깅
📈 Prometheus 메트릭 수집 + Grafana 대시보드
private httpReqCounter = new Counter({
name: 'http_requests_total',
help: 'Total HTTP requests',
labelNames: ['method','path','status'],
});
increment(method,path,status) { this.httpReqCounter.labels(method,path,String(status)).inc(); }
}
🔀 Section 11. 블루그린 & 카나리 배포 전략
다운타임 제로 배포 — 대기업에서 사용하는 전략
🎨 배포 전략 3가지 완전 비교
| 전략 | 방식 | 다운타임 | 롤백 속도 | 비용 |
|---|---|---|---|---|
| 롤링 업데이트 | 인스턴스 순차 교체 | 없음 | 보통 | 낮음 |
| 블루/그린 | 두 환경 동시 운영 후 전환 | 없음 | 즉시(<1초) | 2배 비용 |
| 카나리 배포 | 소수 트래픽으로 먼저 테스트 | 없음 | 빠름 | 약간 높음 |
☸️ Section 12. Kubernetes 입문
Docker Compose의 다음 단계 — 대규모 서비스 표준
🏗️ K8s 핵심 개념
컨테이너 1개 이상
같은 IP 공유
롤링 업데이트
원하는 상태 유지
로드밸런싱
DNS 자동 등록
도메인 라우팅
SSL 처리
트래픽 급증 대응
min~max 범위 설정
Pod 재시작 없이 업데이트
📄 NestJS K8s Deployment + HPA
🚨 Section 13. 장애 대응 & 포스트모템
새벽 3시 알람 — 프로처럼 장애 대응하는 법
🔥 장애 대응 5단계 프로세스
📋 장애 대응 체크리스트
💼 Section 14. 면접 Q&A + 체크리스트 + 로드맵
취업 완전 정복 — 실제 기술 면접 DevOps 질문들
❓ 실제 기술 면접 Q&A
✅ DevOps 현업 준비도 체크리스트
🗺️ DevOps 마스터 로드맵 (6단계)
BackendDevGuide0007 완료!
Docker부터 Kubernetes까지 — 이제 코드를 세상에 배포할 수 있습니다!
다음: BackendDevGuide0008 - 성능 최적화와 캐싱 전략 A-Z