Docker: ๊ฐ๋ฐ์์ ํ๋ก๋์ ๊น์ง
์ ํ๋ฆฌ์ผ์ด์ ์ปจํ ์ด๋ํ๋ฅผ ์ํ ์๋ฒฝํ Docker ๊ฐ์ด๋. Dockerfile, Docker Compose, ๋ฉํฐ์คํ ์ด์ง ๋น๋ ๋ฐ ํ๋ก๋์ ๋ฐฐํฌ๋ฅผ ์ค์ฉ์ ์ธ ์์ ์ ํจ๊ป ์ค๋ช ํฉ๋๋ค.

Docker๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐ, ํ ์คํธ, ๋ฐฐํฌ ๋ฐฉ์์ ๊ทผ๋ณธ์ ์ผ๋ก ํ์ ํ๊ณ ์์ต๋๋ค. ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ๊ทธ ์์กด์ฑ์ ํด๋ ๊ฐ๋ฅํ ์ปจํ ์ด๋์ ์บก์ํํจ์ผ๋ก์จ Docker๋ ์ ๋ช ํ "๋ด ์ปดํจํฐ์์๋ ๋์ํฉ๋๋ค" ๋ฌธ์ ๋ฅผ ์ ๊ฑฐํ๊ณ ๋ชจ๋ ํ๊ฒฝ์์์ ์ผ๊ด์ฑ์ ๋ณด์ฅํฉ๋๋ค. ์ด ๊ฐ์ด๋๋ ์ฒซ ๋ฒ์งธ Dockerfile๋ถํฐ ํ๋ก๋์ ๋ฐฐํฌ๊น์ง์ ์ ์ฒด ์ฌ์ ์ ๋ค๋ฃน๋๋ค.
Docker Desktop 5.x๋ ๋ค์ดํฐ๋ธ containerd ์ง์, ์ต์ ํ๋ ๋ฆฌ์์ค ๊ด๋ฆฌ, ์ํํ Kubernetes ํตํฉ์ ํฌํจํ ์ฃผ์ ์ฑ๋ฅ ๊ฐ์ ์ ์ ๊ณตํฉ๋๋ค. ๋ฉํฐ ์ํคํ ์ฒ ์ด๋ฏธ์ง(ARM/x86)๋ ์ด์ ํ์ค ๊ดํ์ด ๋์์ต๋๋ค.
์ปจํ ์ด๋ํ ๊ธฐ์ด
์ปจํ ์ด๋๋ ์ฝ๋, ๋ฐํ์, ์์คํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฐ ์ค์ ์ ํจํค์งํ๋ ๊ฒฝ๋ ์ํํธ์จ์ด ๋จ์์ ๋๋ค. ํ๋์จ์ด๋ฅผ ๊ฐ์ํํ๋ ๊ฐ์ ๋จธ์ ๊ณผ ๋ฌ๋ฆฌ ์ปจํ ์ด๋๋ ํธ์คํธ ์์คํ ์ ์ปค๋์ ๊ณต์ ํ๋ฏ๋ก ์์์ด ๋น ๋ฅด๊ณ ๋ฆฌ์์ค ์๋น๊ฐ ์ ์ต๋๋ค.
# terminal
# Docker installation on Ubuntu
sudo apt update
sudo apt install -y docker.io
# Add user to docker group (avoids sudo)
sudo usermod -aG docker $USER
# Verify installation
docker --version
# Docker version 26.1.0, build 1234567
# First container: downloads image and runs
docker run hello-world์ด ๋ช
๋ น์ Docker Hub์์ hello-world ์ด๋ฏธ์ง๋ฅผ ๋ค์ด๋ก๋ํ๊ณ ํ์ธ ๋ฉ์์ง๋ฅผ ํ์ํ๋ ์ปจํ
์ด๋๋ฅผ ์คํํฉ๋๋ค.
# terminal
# List running containers
docker ps
# List all containers (including stopped)
docker ps -a
# List downloaded images
docker images
# Remove a container
docker rm <container_id>
# Remove an image
docker rmi <image_name>์ด ๊ธฐ๋ณธ ๋ช ๋ น๋ค์ ์ปจํ ์ด๋์ ์ด๋ฏธ์ง์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค.
์ฒซ ๋ฒ์งธ Dockerfile ์์ฑ
Dockerfile์๋ Docker ์ด๋ฏธ์ง๋ฅผ ๋น๋ํ๊ธฐ ์ํ ๋ช ๋ น์ด ํฌํจ๋์ด ์์ต๋๋ค. ๊ฐ ๋ช ๋ น์ ์ต์ข ์ด๋ฏธ์ง์ ๋ ์ด์ด๋ฅผ ์์ฑํ์ฌ ์บ์ฑ๊ณผ ์ฌ์ฌ์ฉ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
# Dockerfile
# Base image: Node.js 22 on Alpine Linux (lightweight)
FROM node:22-alpine
# Set working directory in the container
WORKDIR /app
# Copy dependency files first (cache optimization)
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production
# Copy source code
COPY . .
# Expose port (documentation)
EXPOSE 3000
# Startup command
CMD ["node", "server.js"]๋ช ๋ น์ ์์๋ ์บ์ ์ต์ ํ์ ๋งค์ฐ ์ค์ํฉ๋๋ค. ๋ณ๊ฒฝ ๋น๋๊ฐ ๋ฎ์ ํ์ผ(package.json)์ ์์ค ์ฝ๋๋ณด๋ค ๋จผ์ ๋ณต์ฌํด์ผ ํฉ๋๋ค.
# terminal
# Build image with a tag
docker build -t my-app:1.0 .
# Run the container
docker run -d -p 3000:3000 --name my-app-container my-app:1.0
# Check logs
docker logs my-app-container
# Access container shell
docker exec -it my-app-container sh-d ํ๋๊ทธ๋ ์ปจํ
์ด๋๋ฅผ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์คํํ๊ณ , -p๋ ์ปจํ
์ด๋์ ํฌํธ 3000์ ํธ์คํธ์ ํฌํธ 3000์ ๋งคํํฉ๋๋ค.
Alpine ์ด๋ฏธ์ง๋ ์๋นํ ์์ต๋๋ค(Debian์ ์ฝ 120MB์ ๋นํด ์ฝ 5MB). ๊ทธ๋ฌ๋ glibc ๋์ musl libc๋ฅผ ์ฌ์ฉํ๋ฏ๋ก ์ผ๋ถ ๋ค์ดํฐ๋ธ ์์กด์ฑ๊ณผ ๋นํธํ์ฑ์ด ๋ฐ์ํ ์ ์์ต๋๋ค. ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ฉด Debian ๊ธฐ๋ฐ ์ด๋ฏธ์ง(node:22-slim)๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๊ถ์ฅ๋ฉ๋๋ค.
ํ๋ก๋์ ์ ์ํ ๋ฉํฐ์คํ ์ด์ง ๋น๋
๋ฉํฐ์คํ ์ด์ง ๋น๋๋ ๋น๋ ํ๊ฒฝ์ ๋ฐํ์ ํ๊ฒฝ์์ ๋ถ๋ฆฌํ์ฌ ์ต์ ํ๋ ํ๋ก๋์ ์ด๋ฏธ์ง๋ฅผ ์์ฑํฉ๋๋ค. ์ต์ข ์ด๋ฏธ์ง์๋ ํ์ํ ์ํฐํฉํธ๋ง ํฌํจ๋ฉ๋๋ค.
# Dockerfile.production
# ============================================
# Stage 1: Build
# ============================================
FROM node:22-alpine AS builder
WORKDIR /app
# Copy and install dependencies (including devDependencies)
COPY package*.json ./
RUN npm ci
# Copy source code
COPY . .
# Build the application (TypeScript, bundling, etc.)
RUN npm run build
# ============================================
# Stage 2: Production
# ============================================
FROM node:22-alpine AS production
# Non-root user for security
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
WORKDIR /app
# Copy only necessary files from builder stage
COPY /app/dist ./dist
COPY /app/node_modules ./node_modules
COPY /app/package.json ./
# Switch to non-root user
USER nodejs
# Environment variables
ENV NODE_ENV=production
ENV PORT=3000
EXPOSE 3000
# Startup command
CMD ["node", "dist/server.js"]์ด ์ ๊ทผ ๋ฐฉ์์ ๋น๋ ๋๊ตฌ, devDependencies ๋ฐ ์์ค ํ์ผ์ ์ ์ธํ์ฌ ์ต์ข ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ํฌ๊ฒ ์ค์ ๋๋ค.
# terminal
# Build with specific file
docker build -f Dockerfile.production -t my-app:production .
# Compare image sizes
docker images | grep my-app
# my-app production abc123 150MB
# my-app 1.0 def456 450MBํฌ๊ธฐ ๊ฐ์๋ ํ๋ก์ ํธ์ ๋ฐ๋ผ 60-70%์ ๋ฌํ ์ ์์ผ๋ฉฐ, ๋ฐฐํฌ ์๊ฐ์ ๊ฐ์ ํ๊ณ ๊ณต๊ฒฉ ํ๋ฉด์ ์ค์ ๋๋ค.
๋ก์ปฌ ์ค์ผ์คํธ๋ ์ด์ ์ ์ํ Docker Compose
Docker Compose๋ ๋ฉํฐ ์ปจํ ์ด๋ ์ ํ๋ฆฌ์ผ์ด์ ๊ด๋ฆฌ๋ฅผ ๊ฐ์ํํฉ๋๋ค. YAML ํ์ผ๋ก ๋ชจ๋ ์๋น์ค, ๊ตฌ์ฑ ๋ฐ ์์กด์ฑ์ ์ ์ธํฉ๋๋ค.
# docker-compose.yml
version: "3.9"
services:
# Main application
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NODE_ENV=development
- DATABASE_URL=postgresql://postgres:secret@db:5432/myapp
- REDIS_URL=redis://cache:6379
volumes:
# Mount source code for hot-reload
- ./src:/app/src
- ./package.json:/app/package.json
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
networks:
- app-network
# PostgreSQL database
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: secret
POSTGRES_DB: myapp
volumes:
# Data persistence
- postgres_data:/var/lib/postgresql/data
# Initialization script
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
networks:
- app-network
# Redis cache
cache:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
command: redis-server --appendonly yes
networks:
- app-network
# Named volumes for persistence
volumes:
postgres_data:
redis_data:
# Dedicated network for isolation
networks:
app-network:
driver: bridge์๋น์ค๋ Docker ๋ด๋ถ ๋คํธ์ํฌ๋ฅผ ํตํด ์ด๋ฆ(db, cache)์ผ๋ก ํต์ ํฉ๋๋ค. ํฌ์ค์ฒดํฌ๋ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ ์ ์์กด์ฑ์ด ์ค๋น๋์๋์ง ํ์ธํฉ๋๋ค.
# terminal
# Start all services
docker compose up -d
# View logs from all services
docker compose logs -f
# Logs from a specific service
docker compose logs -f app
# Stop and remove containers
docker compose down
# Removal including volumes (caution: data loss)
docker compose down -v
# Rebuild after Dockerfile changes
docker compose up -d --buildDevOps ๋ฉด์ ์ค๋น๊ฐ ๋์ จ๋์?
์ธํฐ๋ํฐ๋ธ ์๋ฎฌ๋ ์ดํฐ, flashcards, ๊ธฐ์ ํ ์คํธ๋ก ์ฐ์ตํ์ธ์.
์ํฌ๋ฆฟ ๋ฐ ํ๊ฒฝ ๋ณ์ ๊ด๋ฆฌ
์ํฌ๋ฆฟ์ ์์ ํ ๊ด๋ฆฌ๋ ํ๋ก๋์ ์์ ๋งค์ฐ ์ค์ํฉ๋๋ค. Docker๋ ์ํฉ์ ๋ฐ๋ผ ์ฌ๋ฌ ์ ๊ทผ ๋ฐฉ์์ ์ ๊ณตํฉ๋๋ค.
# docker-compose.override.yml (development only)
version: "3.9"
services:
app:
env_file:
- .env.development
environment:
- DEBUG=trueํ๋ก๋์ ์์๋ Docker secrets๊ฐ ๋ ๋์ ๋ณด์์ ์ ๊ณตํฉ๋๋ค.
# docker-compose.production.yml
version: "3.9"
services:
app:
build:
context: .
dockerfile: Dockerfile.production
secrets:
- db_password
- api_key
environment:
- NODE_ENV=production
- DATABASE_PASSWORD_FILE=/run/secrets/db_password
- API_KEY_FILE=/run/secrets/api_key
secrets:
db_password:
file: ./secrets/db_password.txt
api_key:
file: ./secrets/api_key.txt์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋๋ ๋ง์ดํธ๋ ํ์ผ์์ ์ํฌ๋ฆฟ์ ์ฝ์ต๋๋ค.
const fs = require('fs');
const path = require('path');
// Utility function to read Docker secrets
function readSecret(secretName) {
const secretPath = `/run/secrets/${secretName}`;
// Check if secret file exists
if (fs.existsSync(secretPath)) {
return fs.readFileSync(secretPath, 'utf8').trim();
}
// Fallback to classic environment variables
const envVar = secretName.toUpperCase();
return process.env[envVar];
}
module.exports = {
databasePassword: readSecret('db_password'),
apiKey: readSecret('api_key'),
};์ด ์ ๊ทผ ๋ฐฉ์์ ํ๊ฒฝ ๋ณ์๋ Docker ์ด๋ฏธ์ง์์ ์ํฌ๋ฆฟ์ด ๋ ธ์ถ๋๋ ๊ฒ์ ๋ฐฉ์งํฉ๋๋ค.
Docker ์ด๋ฏธ์ง ์ต์ ํ
์ฌ๋ฌ ๊ธฐ๋ฒ์ผ๋ก ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์ค์ด๊ณ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
# Dockerfile.optimized
FROM node:22-alpine AS base
# Install necessary tools in a single layer
RUN apk add --no-cache \
dumb-init \
&& rm -rf /var/cache/apk/*
# ============================================
# Stage: Dependencies
# ============================================
FROM base AS deps
WORKDIR /app
# Copy only lock files for caching
COPY package.json package-lock.json ./
# Install with mounted npm cache (BuildKit)
RUN \
npm ci --only=production
# ============================================
# Stage: Builder
# ============================================
FROM base AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN \
npm ci
COPY . .
RUN npm run build
# ============================================
# Stage: Production
# ============================================
FROM base AS production
# Image metadata
LABEL maintainer="team@example.com"
LABEL version="1.0"
LABEL description="Production-ready Node.js application"
# Non-root user
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
WORKDIR /app
# Copy production dependencies
COPY /app/node_modules ./node_modules
# Copy build output
COPY /app/dist ./dist
COPY /app/package.json ./
USER nodejs
ENV NODE_ENV=production
# dumb-init as PID 1 for signal handling
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "dist/server.js"]dumb-init์ ์ฌ์ฉํ๋ฉด Unix ์๊ทธ๋์ ์ฌ๋ฐ๋ฅธ ์ฒ๋ฆฌ๊ฐ ๋ณด์ฅ๋์ด ์ปจํ
์ด๋์ ๊ทธ๋ ์ด์คํ ์
ง๋ค์ด์ด ๊ฐ๋ฅํด์ง๋๋ค.
# terminal
# Enable BuildKit for advanced features
export DOCKER_BUILDKIT=1
# Build with cache and detailed output
docker build --progress=plain -t my-app:optimized .
# Analyze image layers
docker history my-app:optimized
# Detailed image inspection
docker inspect my-app:optimized์ด๋ฏธ์ง๋ Trivy๋ Snyk๊ณผ ๊ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ ๊ธฐ์ ์ผ๋ก ์ทจ์ฝ์ ์ค์บ์ ์ํํด์ผ ํฉ๋๋ค. ๋ฒ ์ด์ค ์ด๋ฏธ์ง๋ ๋ณด์ ํจ์น๋ฅผ ํฌํจํ๊ธฐ ์ํด ์ ๊ธฐ์ ์ผ๋ก ์ ๋ฐ์ดํธํด์ผ ํฉ๋๋ค.
๊ณ ๊ธ Docker ๋คํธ์ํน
Docker๋ ๋ค์ํ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ์ํ ์ฌ๋ฌ ๋คํธ์ํฌ ๋๋ผ์ด๋ฒ๋ฅผ ์ ๊ณตํฉ๋๋ค.
# docker-compose.networking.yml
version: "3.9"
services:
# Publicly accessible frontend
frontend:
build: ./frontend
ports:
- "80:80"
networks:
- frontend-network
- backend-network
# API accessible only from frontend
api:
build: ./api
networks:
- backend-network
- database-network
# No external ports exposed
# Isolated database
database:
image: postgres:16-alpine
networks:
- database-network
# Accessible only by API
networks:
frontend-network:
driver: bridge
backend-network:
driver: bridge
internal: true # No internet access
database-network:
driver: bridge
internal: true์ด ๊ตฌ์ฑ์ ์ต์ ๊ถํ ์์น์ ๋ฐ๋ผ ์๋น์ค๋ฅผ ๊ฒฉ๋ฆฌํฉ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ API์์๋ง ์ ๊ทผํ ์ ์์ต๋๋ค.
# terminal
# Inspect Docker networks
docker network ls
# Details of a specific network
docker network inspect app-network
# Create a custom network
docker network create --driver bridge --subnet 172.28.0.0/16 custom-network
# Connect a container to an existing network
docker network connect custom-network my-container๋ณผ๋ฅจ๊ณผ ๋ฐ์ดํฐ ์์์ฑ
Docker ๋ณผ๋ฅจ์ ์ปจํ ์ด๋ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๋์ด ๋ฐ์ดํฐ๋ฅผ ๋ณด์กดํฉ๋๋ค.
# docker-compose.volumes.yml
version: "3.9"
services:
app:
image: my-app:latest
volumes:
# Named volume for persistent data
- app_data:/app/data
# Bind mount for development
- ./uploads:/app/uploads:rw
# Read-only mount for configuration
- ./config:/app/config:ro
backup:
image: alpine
volumes:
# Access same volume for backups
- app_data:/data:ro
- ./backups:/backups
command: |
sh -c "tar czf /backups/backup-$$(date +%Y%m%d).tar.gz /data"
volumes:
app_data:
driver: local
driver_opts:
type: none
device: /path/to/host/data
o: bind๋ช ๋ช ๋ ๋ณผ๋ฅจ๊ณผ ๋ฐ์ธ๋ ๋ง์ดํธ์ ๊ตฌ๋ถ์ ์ค์ํฉ๋๋ค. ๋ณผ๋ฅจ์ Docker๊ฐ ๊ด๋ฆฌํ๊ณ ๋ฐ์ธ๋ ๋ง์ดํธ๋ ํธ์คํธ ํ์ผ ์์คํ ์ ์ง์ ์ฌ์ฉํฉ๋๋ค.
# terminal
# List volumes
docker volume ls
# Inspect a volume
docker volume inspect app_data
# Remove orphaned volumes
docker volume prune
# Backup a volume
docker run --rm -v app_data:/data -v $(pwd):/backup alpine \
tar czf /backup/volume-backup.tar.gz /dataํ๋ก๋์ ๋ฐฐํฌ
๊ฒฌ๊ณ ํ ๋ฐฐํฌ ์ํฌํ๋ก์ฐ์๋ ๋น๋, ํ ์คํธ ๋ฐ ๋ ์ง์คํธ๋ฆฌ๋ก์ ํธ์๊ฐ ํฌํจ๋ฉ๋๋ค.
# deploy.sh
#!/bin/bash
set -e
# Variables
REGISTRY="registry.example.com"
IMAGE_NAME="my-app"
VERSION=$(git describe --tags --always)
echo "Building version: $VERSION"
# Build production image
docker build \
-f Dockerfile.production \
-t $REGISTRY/$IMAGE_NAME:$VERSION \
-t $REGISTRY/$IMAGE_NAME:latest \
--build-arg BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
--build-arg VERSION=$VERSION \
.
# Security scan
echo "Running security scan..."
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image $REGISTRY/$IMAGE_NAME:$VERSION
# Push to registry
echo "Pushing to registry..."
docker push $REGISTRY/$IMAGE_NAME:$VERSION
docker push $REGISTRY/$IMAGE_NAME:latest
echo "Deployment complete: $REGISTRY/$IMAGE_NAME:$VERSION"์๋ฒ ๋ฐฐํฌ๋ฅผ ์ํด ๋ณ๋์ ํ๋ก๋์ compose ํ์ผ์ด ๊ตฌ์ฑ์ ์กฐ์ ํฉ๋๋ค.
# docker-compose.prod.yml
version: "3.9"
services:
app:
image: registry.example.com/my-app:latest
restart: always
deploy:
replicas: 3
resources:
limits:
cpus: "0.5"
memory: 512M
reservations:
cpus: "0.25"
memory: 256M
update_config:
parallelism: 1
delay: 10s
failure_action: rollback
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"์ด ๊ตฌ์ฑ์ ์์ ์ ์ธ ๋ฐฐํฌ๋ฅผ ์ํ ๋ฆฌ์์ค ํ ๋น, ์ ๋ฐ์ดํธ ์ ๋ต ๋ฐ ํฌ์ค์ฒดํฌ๋ฅผ ์ ์ํฉ๋๋ค.
# terminal
# Production deployment with Docker Compose
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# Zero-downtime update (rolling update)
docker compose -f docker-compose.yml -f docker-compose.prod.yml pull
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --no-deps app
# Rollback if issues occur
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --no-deps \
--scale app=0 && \
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --no-deps app์ปจํ ์ด๋ ๋ชจ๋ํฐ๋ง ๋ฐ ๋๋ฒ๊น
์ปจํ ์ด๋ ๋ชจ๋ํฐ๋ง์ ํ๋ก๋์ ์์ ํ์์ ์ ๋๋ค.
# terminal
# Real-time statistics for all containers
docker stats
# Statistics for a specific container with custom format
docker stats my-app --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
# Inspect processes in a container
docker top my-app
# Real-time Docker events
docker events --filter container=my-app
# Copy files from/to a container
docker cp my-app:/app/logs/error.log ./error.log์ฌ์ธต ๋๋ฒ๊น ์ ์ํด ์ฌ๋ฌ ๊ธฐ๋ฒ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
# terminal
# Interactive shell in a running container
docker exec -it my-app sh
# Execute a single command
docker exec my-app cat /app/config/settings.json
# Start a container in debug mode
docker run -it --rm --entrypoint sh my-app:latest
# Inspect environment variables
docker exec my-app printenv
# Analyze logs with filters
docker logs my-app --since 1h --tail 100 | grep ERROR# docker-compose.monitoring.yml
version: "3.9"
services:
app:
# ... existing configuration
labels:
- "prometheus.scrape=true"
- "prometheus.port=3000"
- "prometheus.path=/metrics"
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention.time=15d'
grafana:
image: grafana/grafana:latest
ports:
- "3001:3000"
volumes:
- grafana_data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=secret
volumes:
prometheus_data:
grafana_data:์ด ๋ชจ๋ํฐ๋ง ์คํ์ ์ปจํ ์ด๋ ๋ฉํธ๋ฆญ์ ์์ง๊ณผ ์๊ฐํ๋ฅผ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
๊ฒฐ๋ก
Docker๋ ๋ชจ๋ ํ๊ฒฝ์์์ ์ผ๊ด์ฑ์ ๋ณด์ฅํ์ฌ ๊ฐ๋ฐ ์ฃผ๊ธฐ๋ฅผ ํ์ ํฉ๋๋ค. ์ปจํ ์ด๋ํ๋ ์ด์์ฑ, ๊ฒฉ๋ฆฌ ๋ฐ ์ฌํ์ฑ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ ํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์์ ์ธ ํน์ฑ์ ๋๋ค.
ํ๋ก๋์ ์ ์ํ Docker ์ฒดํฌ๋ฆฌ์คํธ
- โ ์ต์ ํ๋ ์ด๋ฏธ์ง๋ฅผ ์ํ ๋ฉํฐ์คํ ์ด์ง ๋น๋
- โ ์ปจํ ์ด๋ ๋ด non-root ์ฌ์ฉ์
- โ ๋ชจ๋ ์๋น์ค์ ํฌ์ค์ฒดํฌ ๊ตฌ์ฑ
- โ Docker secrets ๋๋ ์์ ํ ํ๊ฒฝ ๋ณ์๋ก ์ํฌ๋ฆฟ ๊ด๋ฆฌ
- โ ๋ฆฌ์์ค ์ ํ(CPU, ๋ฉ๋ชจ๋ฆฌ) ์ ์
- โ ์ค์ ๋ฐ์ดํฐ ์์์ฑ์ ์ํ ๋ณผ๋ฅจ
- โ ํ์ผ ๋กํ ์ด์ ๊ธฐ๋ฅ์ ์ค์ ์ง์ค์ ๋ก๊น
- โ ๋ฐฐํฌ ์ ์ด๋ฏธ์ง ๋ณด์ ์ค์บ
- โ ๋ค์ดํ์ ์๋ ์ ๋ฐ์ดํธ ์ ๋ต
- โ ์๋น์ค ๊ฐ ๊ฒฉ๋ฆฌ๋ ๋คํธ์ํฌ
์ฐ์ต์ ์์ํ์ธ์!
๋ฉด์ ์๋ฎฌ๋ ์ดํฐ์ ๊ธฐ์ ํ ์คํธ๋ก ์ง์์ ํ ์คํธํ์ธ์.
Docker ์๋ฌ์ ๋ชจ๋ ํ๋ ๊ฐ๋ฐ์์๊ฒ ๊ธฐ๋ณธ์ ์ธ ๊ธฐ์ ์ ๋๋ค. ๋ก์ปฌ ํ๊ฒฝ์์ ํ๋ก๋์ ๋ฐฐํฌ๊น์ง Docker๋ ์ํฌํ๋ก์ฐ๋ฅผ ํ์คํํ๊ณ ์ด์์ ๊ฐ์ํํฉ๋๋ค. ์ฌ๊ธฐ์ ์ ์๋ ๊ฐ๋ ๋ค์ Kubernetes์ ๋๊ท๋ชจ ์ปจํ ์ด๋ ์ค์ผ์คํธ๋ ์ด์ ์ ํ๊ตฌํ๊ธฐ ์ํ ๊ฒฌ๊ณ ํ ๊ธฐ๋ฐ์ ํ์ฑํฉ๋๋ค.
ํ๊ทธ
๊ณต์
๊ด๋ จ ๊ธฐ์ฌ

Kubernetes: ์ฒซ ์ ํ๋ฆฌ์ผ์ด์ ๋ฐฐํฌํ๊ธฐ
Kubernetes์์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐฐํฌํ๊ธฐ ์ํ ์ค์ฉ ๊ฐ์ด๋์ ๋๋ค. minikube ์ค์น๋ถํฐ Deployment, Service, ConfigMap๊น์ง ๊ตฌ์ฒด์ ์ธ ์์ ์ ํจ๊ป ์ค๋ช ํฉ๋๋ค.

ArgoCD์ GitOps ์๋ฒฝ ๊ฐ์ด๋ 2026: Kubernetes ์ง์์ ๋ฐฐํฌ ์ ๋ต๊ณผ ๋ฉด์ ํต์ฌ ์ง๋ฌธ
ArgoCD 3.4 GitOps ํํ ๋ฆฌ์ผ. Kubernetes ์ง์์ ๋ฐฐํฌ, Application CRD, Sync Waves, ๋ฉํฐํด๋ฌ์คํฐ ๊ด๋ฆฌ, Flux ๋น๊ต, ๋ฉด์ ๋น์ถ ์ง๋ฌธ์ YAML ์์ ์ ํจ๊ป ํด์คํฉ๋๋ค.

Terraform ๋ฉด์ ์ง๋ฌธ ์๋ฒฝ ๊ฐ์ด๋ 2026: Infrastructure as Code ํต์ฌ ์ ๋ฆฌ
Terraform ๋ฉด์ ์์ ์์ฃผ ์ถ์ ๋๋ ์ํ ๊ด๋ฆฌ, ๋ชจ๋, ์ํฌ์คํ์ด์ค, ํ๋ก๋ฐ์ด๋, IaC ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ์ฒด๊ณ์ ์ผ๋ก ์ ๋ฆฌํฉ๋๋ค. 2026๋ Terraform 1.14 ๋ฐ HCP Terraform ์ต์ ๋ด์ฉ์ ๋ฐ์ํ์์ต๋๋ค.