CI/CD๋ ๋ฌด์์ธ๊ฐ
๊ฐ๋ฐ์๊ฐ ์ฝ๋๋ฅผ ์์ฑํ๊ณ ๋ฐฐํฌํ๋ ๊ณผ์ ,
๋งค๋ฒ ์๋์ผ๋ก ํ๋ฉด ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ๊ณ ์ค์ํ ์ ์๋ค.
CI/CD๋ ์ด๋ฐ ๊ณผ์ ์ ์๋ํํ๋ ๋ฐฉ๋ฒ์ด๋ค.
๋ง์น ๊ณต์ฅ์ ์๋ํ ์์ฐ ๋ผ์ธ์ฒ๋ผ,
์ฝ๋๋ฅผ ์์ฑํ๋ฉด ์๋์ผ๋ก ํ
์คํธํ๊ณ ,
๋ฌธ์ ๊ฐ ์์ผ๋ฉด ์๋์ผ๋ก ๋ฐฐํฌ๋๋ค.
CI (Continuous Integration): ์ง์์ ํตํฉ
๊ฐ๋ฐ์๋ค์ด ์์ฑํ ์ฝ๋๋ฅผ ์๋์ผ๋ก ํตํฉํ๊ณ ํ
์คํธ
CD (Continuous Deployment/Delivery): ์ง์์ ๋ฐฐํฌ
ํ
์คํธ๋ฅผ ํต๊ณผํ ์ฝ๋๋ฅผ ์๋์ผ๋ก ์๋ฒ์ ๋ฐฐํฌ
์ CI/CD๋ฅผ ๋ฐฐ์์ผ ํ ๊น?
์ด์ 1: ์๊ฐ ์ ์ฝ
์๋ ๋ฐฐํฌ 30๋ถ โ ์๋ ๋ฐฐํฌ 5๋ถ
์ด์ 2: ๋ฒ๊ทธ ์กฐ๊ธฐ ๋ฐ๊ฒฌ
์ฝ๋๋ฅผ ํธ์ํ์๋ง์ ์๋ ํ
์คํธ ์คํ
์ด์ 3: ์์ ์ ์ธ ๋ฐฐํฌ
์ฌ๋์ ์ค์๋ฅผ ์ค์ด๊ณ ์ผ๊ด์ฑ ์ ์ง
์ด์ 4: ๋ฉด์ ํ์
DevOps, GitHub Actions๋ ๋ฉด์ ๋จ๊ณจ ์ง๋ฌธ
๊ธฐ๋ณธ ๊ฐ๋ ์์ฝ
๐ท๏ธ CI/CD ํ์ดํ๋ผ์ธ ๋จ๊ณ
1. [๊ฐ๋ฐ์] โ [Git Push]
โ
2. [CI ์๋ฒ] : ์ฝ๋ ๋น๋
- ์์กด์ฑ ์ค์น
- ์ปดํ์ผ
โ
3. [CI ์๋ฒ] : ํ
์คํธ ์คํ
- ๋จ์ ํ
์คํธ
- ํตํฉ ํ
์คํธ
- E2E ํ
์คํธ
โ
4. [CI ์๋ฒ] : ์ฝ๋ ํ์ง ๊ฒ์ฌ
- ๋ฆฐํธ(Lint)
- ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง
- ๋ณด์ ์ค์บ
โ
5. [CD ์๋ฒ] : Docker ์ด๋ฏธ์ง ๋น๋
- Dockerfile๋ก ์ด๋ฏธ์ง ์์ฑ
- ๋ ์ง์คํธ๋ฆฌ์ ํธ์
โ
6. [CD ์๋ฒ] : ๋ฐฐํฌ
- ๊ฐ๋ฐ ํ๊ฒฝ
- ์คํ
์ด์ง ํ๊ฒฝ
- ํ๋ก๋์
ํ๊ฒฝ
โ
7. [๋ชจ๋ํฐ๋ง]
- ํฌ์ค ์ฒดํฌ
- ๋ก๊ทธ ํ์ธ
- ์๋ฆผ
๐ท๏ธ CI/CD ๋๊ตฌ ๋น๊ต
| ๋๊ตฌ | ํ์ | ๊ฐ๊ฒฉ | ํน์ง | ์ฌ์ฉ ์์ |
|---|---|---|---|---|
| GitHub Actions | ํด๋ผ์ฐ๋ | ๋ฌด๋ฃ~์ ๋ฃ | GitHub ํตํฉ, ๊ฐํธ | ์คํ์์ค, ์คํํธ์ |
| GitLab CI/CD | ํด๋ผ์ฐ๋/์จํ๋ ๋ฏธ์ค | ๋ฌด๋ฃ~์ ๋ฃ | ์ฌ์ธ์ ํ๋ซํผ | ๋๊ธฐ์ |
| Jenkins | ์จํ๋ ๋ฏธ์ค | ๋ฌด๋ฃ | ๊ฐ๋ ฅํ๊ณ ์ ์ฐ | ๋ ๊ฑฐ์ ์์คํ |
| CircleCI | ํด๋ผ์ฐ๋ | ๋ฌด๋ฃ~์ ๋ฃ | ๋น ๋ฅธ ๋น๋ | SaaS ์๋น์ค |
| Travis CI | ํด๋ผ์ฐ๋ | ๋ฌด๋ฃ~์ ๋ฃ | ์คํ์์ค ์นํ์ | ์คํ์์ค ํ๋ก์ ํธ |
๐ท๏ธ GitHub Actions ํต์ฌ ๊ฐ๋
1. Workflow (์ํฌํ๋ก์ฐ)
๊ฐ๋
: ์๋ํ๋ ํ๋ก์ธ์ค ์ ์ฒด
.github/workflows/ ๋๋ ํ ๋ฆฌ์ YAML ํ์ผ๋ก ์ ์
2. Event (์ด๋ฒคํธ)
๊ฐ๋
: ์ํฌํ๋ก์ฐ๋ฅผ ์คํ์ํค๋ ํธ๋ฆฌ๊ฑฐ
์ฃผ์ ์ด๋ฒคํธ:
push: ์ฝ๋ ํธ์pull_request: PR ์์ฑ/์์ schedule: ์ฃผ๊ธฐ์ ์คํ (cron)workflow_dispatch: ์๋ ์คํ
3. Job (์์ )
๊ฐ๋
: ํ๋ ์ด์์ Step์ผ๋ก ๊ตฌ์ฑ๋ ์์
๋จ์
์ฌ๋ฌ Job์ ๋ณ๋ ฌ ๋๋ ์์ฐจ ์คํ ๊ฐ๋ฅ
4. Step (๋จ๊ณ)
๊ฐ๋
: Job ๋ด์ ๊ฐ๋ณ ์์
๋ช
๋ น์ด ์คํ ๋๋ Action ์ฌ์ฉ
5. Action (์ก์ )
๊ฐ๋
: ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์์
๋ชจ๋
GitHub Marketplace์์ ๋ค์ด๋ก๋ ๊ฐ๋ฅ
6. Runner (๋ฌ๋)
๊ฐ๋
: ์ํฌํ๋ก์ฐ๋ฅผ ์คํํ๋ ์๋ฒ
GitHub ์ ๊ณต ๋๋ Self-hosted
๐ท๏ธ ๋ฐฐํฌ ์ ๋ต
1. Rolling Deployment (๋กค๋ง ๋ฐฐํฌ)
๊ฐ๋
: ์๋ฒ๋ฅผ ์์ฐจ์ ์ผ๋ก ๊ต์ฒด
[์๋ฒ1] [์๋ฒ2] [์๋ฒ3] [์๋ฒ4]
โ
[์๋ฒ์ ] [์๋ฒ2] [์๋ฒ3] [์๋ฒ4]
โ
[์๋ฒ์ ] [์๋ฒ์ ] [์๋ฒ3] [์๋ฒ4]
โ
[์๋ฒ์ ] [์๋ฒ์ ] [์๋ฒ์ ] [์๋ฒ4]
โ
[์๋ฒ์ ] [์๋ฒ์ ] [์๋ฒ์ ] [์๋ฒ์ ]
์ฅ์ : ๋ฌด์ค๋จ ๋ฐฐํฌ, ์ ์ง์ ์
๋ฐ์ดํธ
๋จ์ : ๋ฐฐํฌ ์๊ฐ ์ค๋ ๊ฑธ๋ฆผ, ๋ฒ์ ํผ์ฌ
2. Blue-Green Deployment
๊ฐ๋
: ๋ ๊ฐ์ ํ๊ฒฝ์ ๊ต๋๋ก ์ฌ์ฉ
[Blue ํ๊ฒฝ - ๊ตฌ๋ฒ์ ] โ ํ์ฌ ํธ๋ํฝ
[Green ํ๊ฒฝ - ์ ๋ฒ์ ] โ ๋ฐฐํฌ ์ค
๋ฐฐํฌ ์๋ฃ ํ:
[Blue ํ๊ฒฝ - ๊ตฌ๋ฒ์ ]
[Green ํ๊ฒฝ - ์ ๋ฒ์ ] โ ํธ๋ํฝ ์ ํ
๋ฌธ์ ๋ฐ์ ์ ์ฆ์ Blue๋ก ๋กค๋ฐฑ
์ฅ์ : ์ฆ์ ๋กค๋ฐฑ ๊ฐ๋ฅ, ๋ฌด์ค๋จ ๋ฐฐํฌ
๋จ์ : 2๋ฐฐ์ ๋ฆฌ์์ค ํ์
3. Canary Deployment (์นด๋๋ฆฌ ๋ฐฐํฌ)
๊ฐ๋
: ์ผ๋ถ ํธ๋ํฝ๋ง ์ ๋ฒ์ ์ผ๋ก ์ ํ
[๊ตฌ๋ฒ์ ] โ 90% ํธ๋ํฝ
[์ ๋ฒ์ ] โ 10% ํธ๋ํฝ
๋ฌธ์ ์์ผ๋ฉด ์ ์ง์ ์ผ๋ก ์ฆ๊ฐ:
[๊ตฌ๋ฒ์ ] โ 50% ํธ๋ํฝ
[์ ๋ฒ์ ] โ 50% ํธ๋ํฝ
์ต์ข
:
[์ ๋ฒ์ ] โ 100% ํธ๋ํฝ
์ฅ์ : ์ํ ์ต์ํ, ์ ์ง์ ๊ฒ์ฆ
๋จ์ : ๋ณต์กํ ํธ๋ํฝ ๊ด๋ฆฌ
์ค์ ์์
๐ท๏ธ GitHub Actions ๊ธฐ๋ณธ ์ํฌํ๋ก์ฐ
1. ํ๋ก์ ํธ ๊ตฌ์กฐ
project/
โโโ .github/
โ โโโ workflows/
โ โโโ ci.yml # CI ์ํฌํ๋ก์ฐ
โ โโโ deploy-dev.yml # ๊ฐ๋ฐ ํ๊ฒฝ ๋ฐฐํฌ
โ โโโ deploy-prod.yml # ํ๋ก๋์
๋ฐฐํฌ
โโโ src/
โโโ tests/
โโโ Dockerfile
โโโ package.json
2. CI ์ํฌํ๋ก์ฐ (ci.yml)
name: CI
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x, 20.x]
steps:
# 1. ์ฝ๋ ์ฒดํฌ์์
- name: Checkout code
uses: actions/checkout@v4
# 2. Node.js ์ค์
- name: Setup Node.js $
uses: actions/setup-node@v4
with:
node-version: $
cache: 'npm'
# 3. ์์กด์ฑ ์ค์น
- name: Install dependencies
run: npm ci
# 4. ๋ฆฐํธ ๊ฒ์ฌ
- name: Run linter
run: npm run lint
# 5. ๋จ์ ํ
์คํธ
- name: Run unit tests
run: npm test
# 6. ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: ./coverage/coverage-final.json
fail_ci_if_error: true
e2e-test:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
- name: Install dependencies
run: npm ci
# 7. Playwright ์ค์น
- name: Install Playwright
run: npx playwright install --with-deps
# 8. E2E ํ
์คํธ
- name: Run E2E tests
run: npm run test:e2e
# 9. ํ
์คํธ ์คํจ ์ ์คํฌ๋ฆฐ์ท ์
๋ก๋
- name: Upload test results
if: failure()
uses: actions/upload-artifact@v3
with:
name: playwright-report
path: playwright-report/
retention-days: 30
security-scan:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
# 10. ๋ณด์ ์ทจ์ฝ์ ์ค์บ
- name: Run security audit
run: npm audit --audit-level=moderate
# 11. SAST (์ ์ ๋ถ์)
- name: Run CodeQL Analysis
uses: github/codeql-action/init@v2
with:
languages: javascript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
๐ท๏ธ Docker ๋น๋ ๋ฐ ๋ฐฐํฌ
1. Dockerfile
# ๋ฉํฐ ์คํ
์ด์ง ๋น๋
FROM node:20-alpine AS builder
WORKDIR /app
# ์์กด์ฑ ์ค์น
COPY package*.json ./
RUN npm ci --only=production
# ์์ค ๋ณต์ฌ ๋ฐ ๋น๋
COPY . .
RUN npm run build
# ํ๋ก๋์
์ด๋ฏธ์ง
FROM node:20-alpine
WORKDIR /app
# ๋น๋ ๊ฒฐ๊ณผ๋ฌผ๋ง ๋ณต์ฌ
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package.json ./
# ๋นroot ์ฌ์ฉ์๋ก ์คํ
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001
USER nodejs
EXPOSE 3000
CMD ["node", "dist/main.js"]
2. Docker ๋น๋ ์ํฌํ๋ก์ฐ
name: Build and Push Docker Image
on:
push:
branches: [ main ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: $
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
# 1. Docker Buildx ์ค์
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# 2. GitHub Container Registry ๋ก๊ทธ์ธ
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: $
username: $
password: $
# 3. ๋ฉํ๋ฐ์ดํฐ ์ถ์ถ
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: $/$
tags: |
type=ref,event=branch
type=sha,prefix=-
type=semver,pattern=
# 4. Docker ์ด๋ฏธ์ง ๋น๋ ๋ฐ ํธ์
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: $
labels: $
cache-from: type=gha
cache-to: type=gha,mode=max
๐ท๏ธ ๋ฐฐํฌ ์ํฌํ๋ก์ฐ (AWS ECS)
name: Deploy to Production
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- name: Checkout
uses: actions/checkout@v4
# 1. AWS ์๊ฒฉ์ฆ๋ช
์ค์
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: $
aws-secret-access-key: $
aws-region: ap-northeast-2
# 2. ECR ๋ก๊ทธ์ธ
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
# 3. Docker ์ด๋ฏธ์ง ๋น๋ ๋ฐ ํธ์
- name: Build and push image to ECR
id: build-image
env:
ECR_REGISTRY: $
ECR_REPOSITORY: my-app
IMAGE_TAG: $
run: |
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
# 4. ECS ํ์คํฌ ์ ์ ์
๋ฐ์ดํธ
- name: Fill in the new image ID in the ECS task definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: task-definition.json
container-name: my-app
image: $
# 5. ECS ์๋น์ค ๋ฐฐํฌ
- name: Deploy to Amazon ECS
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: $
service: my-app-service
cluster: my-app-cluster
wait-for-service-stability: true
# 6. Slack ์๋ฆผ
- name: Notify Slack
if: always()
uses: 8398a7/action-slack@v3
with:
status: $
text: 'Deployment to production: $'
webhook_url: $
๐ท๏ธ Blue-Green ๋ฐฐํฌ ์ ๋ต
name: Blue-Green Deployment
on:
workflow_dispatch:
inputs:
environment:
description: 'Target environment'
required: true
type: choice
options:
- blue
- green
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: $
aws-secret-access-key: $
aws-region: ap-northeast-2
# 1. Blue ๋๋ Green ํ๊ฒฝ์ ๋ฐฐํฌ
- name: Deploy to $ environment
run: |
echo "Deploying to $ environment"
aws ecs update-service \
--cluster my-cluster \
--service my-app-$ \
--force-new-deployment
# 2. ํฌ์ค ์ฒดํฌ
- name: Wait for deployment
run: |
aws ecs wait services-stable \
--cluster my-cluster \
--services my-app-$
# 3. ์ค๋ชจํฌ ํ
์คํธ
- name: Run smoke tests
run: |
ENDPOINT="https://$.example.com"
curl -f $ENDPOINT/health || exit 1
# 4. ํธ๋ํฝ ์ ํ (์๋ ์น์ธ ํ์)
- name: Switch traffic
if: inputs.environment == 'green' && success()
run: |
echo "Ready to switch traffic to green"
# Route53์ด๋ ALB ์ค์ ๋ณ๊ฒฝ
๐ท๏ธ ํ๊ฒฝ๋ณ ๋ฐฐํฌ ์ค์
name: Deploy to Environment
on:
push:
branches: [ main, develop ]
jobs:
determine-environment:
runs-on: ubuntu-latest
outputs:
environment: $
steps:
- id: set-env
run: |
if [[ "$" == "refs/heads/main" ]]; then
echo "environment=production" >> $GITHUB_OUTPUT
else
echo "environment=development" >> $GITHUB_OUTPUT
fi
deploy:
needs: determine-environment
runs-on: ubuntu-latest
environment: $
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Deploy to $
run: |
echo "Deploying to $"
# ํ๊ฒฝ๋ณ ์ค์ ํ์ผ ์ฌ์ฉ
cp .env.$ .env
# ๋ฐฐํฌ ์คํฌ๋ฆฝํธ ์คํ
./deploy.sh $
์ค์ ์ฒดํฌ๋ฆฌ์คํธ
โ CI ์ค์
- ์๋ ๋น๋ ์ค์
- ๋จ์ ํ ์คํธ ์๋ ์คํ
- ํตํฉ ํ ์คํธ ์๋ ์คํ
- E2E ํ ์คํธ ์๋ ์คํ
- ์ฝ๋ ๋ฆฐํธ ๊ฒ์ฌ
- ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง ์ธก์
โ ๋ณด์
- ์์กด์ฑ ์ทจ์ฝ์ ์ค์บ
- SAST (์ ์ ๋ถ์)
- ์ํฌ๋ฆฟ ๊ด๋ฆฌ (GitHub Secrets)
- ์ปจํ ์ด๋ ์ด๋ฏธ์ง ์ค์บ
- ์ต์ ๊ถํ ์์น
โ CD ์ค์
- Docker ์ด๋ฏธ์ง ์๋ ๋น๋
- ๋ ์ง์คํธ๋ฆฌ ํธ์
- ํ๊ฒฝ๋ณ ๋ฐฐํฌ ์ค์
- ๋กค๋ฐฑ ์ ๋ต
- ํฌ์ค ์ฒดํฌ
โ ๋ชจ๋ํฐ๋ง
- ๋ฐฐํฌ ์ฑ๊ณต/์คํจ ์๋ฆผ
- ๋น๋ ์๊ฐ ๋ชจ๋ํฐ๋ง
- ํ ์คํธ ๊ฒฐ๊ณผ ๋ฆฌํฌํธ
- ๋ก๊ทธ ์์ง
- ๋ฉํธ๋ฆญ ๋์๋ณด๋
โ ๋ฐฐํฌ ์ ๋ต
- ๋ฐฐํฌ ์ ๋ต ์ ํ (Rolling/Blue-Green/Canary)
- ๋ฌด์ค๋จ ๋ฐฐํฌ ๊ตฌํ
- ๋กค๋ฐฑ ์ ์ฐจ ๋ฌธ์ํ
- ๋ฐฐํฌ ์น์ธ ํ๋ก์ธ์ค
- ๋ฐฐํฌ ์ผ์ ๊ด๋ฆฌ
์์ฝ
CI/CD๋ ๊ฐ๋ฐ๋ถํฐ ๋ฐฐํฌ๊น์ง์ ๊ณผ์ ์ ์๋ํํ๋ ํ์ ๋๊ตฌ๋ค.
๐ ํต์ฌ ํฌ์ธํธ:
- CI: ์ฝ๋ ํตํฉ ๋ฐ ํ ์คํธ ์๋ํ
- CD: ๋ฐฐํฌ ์๋ํ
- GitHub Actions: ๊ฐํธํ CI/CD ๊ตฌํ
- Docker: ์ผ๊ด๋ ๋ฐฐํฌ ํ๊ฒฝ
- ๋ฐฐํฌ ์ ๋ต: Rolling, Blue-Green, Canary
- ๋ชจ๋ํฐ๋ง: ๋ฐฐํฌ ํ ์์ ์ฑ ํ์ธ
๐ฏ CI/CD ํ์ดํ๋ผ์ธ ๋จ๊ณ:
- ์ฝ๋ ํธ์ โ ๊ฐ๋ฐ์๊ฐ ์ฝ๋ ์ปค๋ฐ
- ๋น๋ โ ์์กด์ฑ ์ค์น ๋ฐ ์ปดํ์ผ
- ํ ์คํธ โ ๋จ์/ํตํฉ/E2E ํ ์คํธ
- ์ฝ๋ ํ์ง โ ๋ฆฐํธ, ์ปค๋ฒ๋ฆฌ์ง, ๋ณด์ ์ค์บ
- ์ด๋ฏธ์ง ๋น๋ โ Docker ์ด๋ฏธ์ง ์์ฑ
- ๋ฐฐํฌ โ ํ๊ฒฝ๋ณ ์๋ ๋ฐฐํฌ
- ๋ชจ๋ํฐ๋ง โ ํฌ์ค ์ฒดํฌ ๋ฐ ์๋ฆผ
๐ ๋ฐฐํฌ ์ ๋ต ๋น๊ต:
| ์ ๋ต | ์๋ | ๋กค๋ฐฑ | ๋ฆฌ์์ค | ์ํ๋ |
|---|---|---|---|---|
| Rolling | ๋๋ฆผ | ๋๋ฆผ | 1๋ฐฐ | ์ค๊ฐ |
| Blue-Green | ๋น ๋ฆ | ์ฆ์ | 2๋ฐฐ | ๋ฎ์ |
| Canary | ์ค๊ฐ | ๋น ๋ฆ | 1.1๋ฐฐ | ๋งค์ฐ ๋ฎ์ |
๐ Best Practices:
- ์์ ๋จ์๋ก ์์ฃผ ๋ฐฐํฌ: ์ํ ์ต์ํ
- ์๋ํ ์ฐ์ : ์๋ ์์ ์ต์ํ
- ํ ์คํธ๋ ํ์: ๋ฐฐํฌ ์ ์ถฉ๋ถํ ํ ์คํธ
- ๋กค๋ฐฑ ๊ณํ: ๋ฌธ์ ๋ฐ์ ์ ์ฆ์ ๋ณต๊ตฌ
- ๋ชจ๋ํฐ๋ง: ๋ฐฐํฌ ํ ์ง์์ ์ธ ๊ด์ฐฐ
- ๋ฌธ์ํ: ๋ฐฐํฌ ํ๋ก์ธ์ค ๋ช ํํ ๊ธฐ๋ก
CI/CD๋ ํ ๋ฒ ์ค์ ํ๋ฉด ๊ณ์ ํํ์ ๋ฐ๋๋ค.
์ด๊ธฐ ์ค์ ์ ์๊ฐ์ด ๊ฑธ๋ฆฌ๋๋ผ๋,
์ฅ๊ธฐ์ ์ผ๋ก๋ ๊ฐ๋ฐ ์๋์ ์์ ์ฑ์ ํฌ๊ฒ ํฅ์์ํจ๋ค.