이미지 레지스트리
flowchart LR
DEV["로컬\n개발 환경"]
REG["레지스트리\n(Docker Hub / GHCR)"]
SERVER["프로덕션\n서버"]
DEV -->|"docker push"| REG
SERVER -->|"docker pull"| REG
Docker Hub에 이미지 푸시
# Docker Hub 로그인
docker login
# 이미지 태그 (계정명/이미지명:태그)
docker tag my-app username/my-app:latest
docker tag my-app username/my-app:1.0.0
# 푸시
docker push username/my-app:latest
docker push username/my-app:1.0.0
# 서버에서 풀
docker pull username/my-app:1.0.0
GitHub Container Registry (GHCR)
# GitHub 토큰으로 로그인
echo $GITHUB_TOKEN | docker login ghcr.io -u username --password-stdin
# 이미지 태그 (ghcr.io/계정명/이미지명:태그)
docker tag my-app ghcr.io/username/my-app:latest
# 푸시
docker push ghcr.io/username/my-app:latest
GitHub Actions CI/CD
# .github/workflows/deploy.yml
name: Build and Deploy
on:
push:
branches: [main]
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Docker Hub 로그인
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: 이미지 빌드 및 푸시
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
username/my-app:latest
username/my-app:${{ github.sha }}
deploy:
needs: build-and-push
runs-on: ubuntu-latest
steps:
- name: 서버 배포
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
docker pull username/my-app:latest
docker compose -f /app/docker-compose.prod.yml up -d
프로덕션 docker-compose.yml
# docker-compose.prod.yml
services:
app:
image: username/my-app:latest # 빌드 대신 이미지 사용
restart: always
env_file: .env.prod
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`example.com`)"
db:
image: postgres:16-alpine
restart: always
volumes:
- postgres_data:/var/lib/postgresql/data
env_file: .env.prod
# 포트 노출하지 않음 (외부에서 직접 접근 불가)
nginx:
image: nginx:alpine
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- certs:/etc/letsencrypt
volumes:
postgres_data:
certs:
헬스체크와 자동 재시작
# Dockerfile에 헬스체크 추가
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
# docker-compose.yml
services:
app:
restart: unless-stopped # 수동 중지 제외 항상 재시작
# on-failure: 에러 시만 재시작
# always: 항상 재시작
이미지 정리
# 사용하지 않는 이미지, 컨테이너, 볼륨, 네트워크 정리
docker system prune
# 이미지까지 포함
docker system prune -a
# 사용 중인 디스크 확인
docker system df
정리
| 명령 | 역할 |
|---|---|
docker tag | 이미지에 태그 추가 |
docker push | 레지스트리에 업로드 |
docker pull | 레지스트리에서 다운로드 |
restart: always | 자동 재시작 |
HEALTHCHECK | 컨테이너 상태 확인 |
docker system prune | 미사용 리소스 정리 |
다음 편에서는 Docker 실전 프로젝트 — 전체 스택을 Docker로 구성하는 방법을 배웁니다.