DockerDocker 기초강의 6개 중 5번째난이도 기초

레지스트리와 배포 — 이미지 공유와 프로덕션

발행 읽는 시간 약 1 분

  • Docker
  • 레지스트리
  • DockerHub
  • 배포
  • CICD

강의 소개

Docker Hub나 GitHub Container Registry에 이미지를 푸시하고, 서버에서 컨테이너를 배포하는 방법을 배웁니다. CI/CD 파이프라인과의 연동도 이해합니다.

이미지 레지스트리#

Diagram · Mermaid

Docker Hub에 이미지 푸시#

Bash
# 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)#

Bash
# 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#

YAML
# .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#

YAML
# 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
# Dockerfile에 헬스체크 추가
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
    CMD curl -f http://localhost:3000/health || exit 1
YAML
# docker-compose.yml
services:
  app:
    restart: unless-stopped  # 수동 중지 제외 항상 재시작
    # on-failure: 에러 시만 재시작
    # always: 항상 재시작

이미지 정리#

Bash
# 사용하지 않는 이미지, 컨테이너, 볼륨, 네트워크 정리
docker system prune

# 이미지까지 포함
docker system prune -a

# 사용 중인 디스크 확인
docker system df

정리#

명령역할
docker tag이미지에 태그 추가
docker push레지스트리에 업로드
docker pull레지스트리에서 다운로드
restart: always자동 재시작
HEALTHCHECK컨테이너 상태 확인
docker system prune미사용 리소스 정리

다음 편에서는 Docker 실전 프로젝트 — 전체 스택을 Docker로 구성하는 방법을 배웁니다.

Follow · Ask · Work

이 글이 도움이 됐다면

짧은 작업 기록과 데모는 인스타그램에 올립니다. 만들고 싶은 것이 있다면 프로젝트 의뢰나 협업 제안도 편하게 보내 주세요.

글쓴이

파란여우

직접 만든 AI 앱·제품의 개발·배포를 공개하는 실전형 테크 크리에이터

파란여우 소개 Instagram @bluefox._.hi

이어서 보기

만들고 싶은 것이 있다면 프로젝트 의뢰로 알려 주세요.