처음 접하면 용어들이 정말 장벽처럼 느껴지죠.
저도 예전에 비슷한 프로젝트 하다가 도커 보고 좌절했던 기억이 있어서, 질문자님이 막막함을 느끼실 것 같아요.
걱정 마세요.
'완벽하게' 이해하고 가려면 시간이 걸리지만, '일단 돌아가게 만드는' 최소한의 워크플로우를 잡는 게 목표라면 충분히 단계별로 정리해 드릴 수 있어요.
질문자님이 원하시는 건 '개념 설명'보다는 '실행 순서'니까, 제가 제가 직접 해보면서 정리했던, 가장 기본적인 웹 서비스 배포의 전체 흐름(Workflow) 위주로 설명해 드릴게요.
--- ### 🧱 1단계: 로컬 개발 환경 구축 및 서비스 준비 (가장 익숙한 단계) 이 단계는 도커를 생각하기 전에, 그냥 일반적인 개발 환경에서 코드를 돌리는 단계예요.
1.
개발 언어/프레임워크 선택: 포트폴리오가 웹 서비스라면 (예: React + Node.js 백엔드, 혹은 Django/Flask 같은 Python 기반) 뭘로 할지 결정해야 해요.
일단 가장 쉽게 결과물을 볼 수 있는 걸로 시작하는 게 좋습니다.
2.
로컬 구동: 일단 npm start나 python manage.py runserver 같은 명령어로 개발 서버를 띄워봅니다.
3.
주의점 (
이 단계에서는 의존성 관리가 중요해요.
프로젝트 루트에 package.json (Node.js의 경우) 같은 파일에 필요한 모든 라이브러리 버전을 명시해야 나중에 다른 환경에서도 똑같이 돌아가요.
실전 팁: 만약 프론트엔드(React 등)만 한다면, 일단 create-react-app으로 뼈대만 만들고, 백엔드는 나중에 붙여도 괜찮아요.
작은 성공 경험이 중요합니다.
--- ###
2단계: 컨테이너화 이해하기 - 도커 맛보기 (Dockerizing) 여기서부터 도커의 영역이 시작돼요.
왜 도커를 쓰냐면, "내 컴퓨터에서는 되는데, 서버에서는 안 되는" 바로 그 문제를 없애주기 위해서예요.
핵심 개념 이해: * 이미지(Image): '설계도' 같은 거예요.
이 이미지에는 "이 서비스는 Node.js 버전 18을 기반으로 하고, 이 코드를 넣고, 이 라이브러리들을 설치해야 한다"는 모든 정보가 담겨 있어요.
- 컨테이너(Container): 그 '설계도(이미지)'를 바탕으로 실제로 돌아가는 '실체'예요.
실제 과정 (Dockerfile 작성): 1.
Dockerfile 작성: 프로젝트 루트 디렉토리에 Dockerfile이라는 파일을 만드세요.
(확장자 없음!) 2.
작성 순서 (예시 - Node.js 기준): ```dockerfile # 1.
베이스 이미지 지정: 이 컨테이너는 Node.js 런타임 환경을 기반으로 한다.
FROM node:18-alpine # 2.
작업 디렉토리 설정: 컨테이너 내부에서 작업할 폴더를 지정한다.
WORKDIR /app # 3.
의존성 파일 복사 및 설치: package.json과 package-lock.json을 먼저 복사하고 npm install을 돌린다.
️ 중요: 이 순서가 중요해요!
코드를 다 넣기 전에 의존성만 먼저 깔면, 코드가 바뀌어도 이 과정은 캐싱되어 빌드 시간이 빨라져요.
COPY package*.json ./ RUN npm install # 4.
실제 코드 복사: 나머지 소스 코드를 컨테이너로 가져온다.
COPY .
.
5.
포트 노출: 이 서비스가 외부와 통신할 포트를 알려준다.
(실제 서버 포트와 일치해야 함) EXPOSE 3000 # 6.
실행 명령어 지정: 컨테이너가 시작될 때 어떤 명령어를 실행할지 지정한다.
CMD ["npm", "start"] ``` 3.
이미지 빌드: 터미널에서 docker build -t my-portfolio:v1 . 를 실행합니다.
-t my-portfolio:v1: 붙여주는 이름과 태그예요.
.: 현재 디렉토리의 Dockerfile을 사용하라는 의미예요.
컨테이너 실행: docker run -d -p 80:3000 my-portfolio:v1 을 실행합니다.
-d: 백그라운드에서 돌리라는 뜻.
-p 80:3000: 포트 매핑이 핵심이에요.
"내 컴퓨터의 80번 포트(외부)로 들어오는 트래픽을 컨테이너 내부의 3000번 포트(실제 서비스 포트)로 연결해 줘"라는 뜻입니다.
흔한 실수 및 주의사항: * 볼륨 마운트 오해: 로컬 개발 시에는 docker-compose로 볼륨을 마운트해서 코드를 수정하면 즉시 반영되게 하는데, 이 방식은 '개발용'이에요.
배포할 때는 빌드 시점에 모든 것이 결정되는 것이 원칙입니다.
- 환경 변수: DB 접속 정보 같은 민감한 값은
Dockerfile에 절대 하드코딩하면 안 돼요.
무조건 docker run 시 -e KEY=VALUE로 넘겨주거나, docker-compose.yml에서 처리해야 합니다.
--- ### 🧩 3단계: 서비스 간 연결 및 복잡도 관리 (Docker Compose의 등장) 질문자님의 포트폴리오가 만약 '프론트엔드(React)' + '백엔드(API)' + '데이터베이스(DB)' 세 가지로 구성되어 있다면, 2단계만으로는 부족해요.
이럴 때 docker-compose가 등장합니다.
왜 필요할까요? 여러 개의 서비스(컨테이너)를 한 번에 띄우고, 이들 간의 네트워크 통신을 정의해 주기 위해서예요.
실제 과정 (docker-compose.yml 작성): docker-compose.yml 파일을 만들고 다음과 같이 작성합니다.
(가장 구조적인 예시입니다.) yaml version: '3.8' services: # 1. 백엔드 API 서비스 backend: build: ./backend # 백엔드 코드가 있는 폴더를 지정 ports: - "8080:3000" # 외부 8080 -> 컨테이너 내부 3000 environment: DATABASE_URL: postgres://user:pass@db:5432/mydatabase # 서비스 이름(db)으로 접속하게 함 depends_on: - db # DB가 먼저 올라와야 시작할 수 있음 # 2. 데이터베이스 서비스 (외부 이미지 사용) db: image: postgres:14-alpine # 이미 존재하는 PostgreSQL 이미지를 가져옴 environment: POSTGRES_USER: user POSTGRES_PASSWORD: pass POSTGRES_DB: mydatabase volumes: - postgres_data:/var/lib/postgresql/data # 데이터를 영구 저장할 볼륨 지정 # 3. 프론트엔드 서비스 (Nginx를 통해 정적 파일을 서빙하는 방식 가정) frontend: build: ./frontend # 프론트엔드 빌드 과정 포함 ports: - "80:80" # 가장 외부에 노출될 포트 depends_on: - backend # 백엔드가 먼저 올라와야 API 호출이 가능 volumes: postgres_data: # 이 볼륨이 DB 데이터를 보존합니다.
가장 중요한 포인트: 서비스 이름 기반 통신 backend 서비스 내부에서 DB에 접속할 때, localhost:5432 같은 걸 쓰지 않습니다.
대신 db:5432 와 같이 서비스 이름을 사용합니다.
docker-compose가 이 서비스 이름들을 내부 네트워크로 자동 연결해 주기 때문입니다.
실행: docker-compose up -d 하나만 치면, 필요한 모든 컨테이너(DB, Backend, Frontend)가 한 번에 띄워지고 서로 통신할 준비가 끝납니다.
--- ###
4단계: 실제 외부 서버 배포 (The Last Mile) 로컬에서 docker-compose up으로 잘 돌아가는 것도 하나의 성공이지만, 이게 끝이 아니에요.
실제 서버(AWS EC2, GCP VM 등)에 올리는 과정도 다릅니다.
핵심 원칙: "개발 환경에서 돌리던 방식 그대로 서버에 올리려고 하면 99% 실패한다."
배포 시 체크리스트: 1.
환경 변수 재점검: 서버의 실제 DB 비밀번호, API 키 등은 docker-compose.yml에 적지 말고, 서버 OS 레벨에서 환경 변수(.env 파일이나 OS 자체 변수)로 설정해야 합니다.
포트 매핑 확인: 서버의 방화벽(보안 그룹 등)에서 80, 443 포트가 열려 있는지 확인해야 합니다.
3.
빌드 과정의 재현: * 로컬에서 docker build로 만든 이미지를 서버로 옮겨야 합니다.
- (추천 방법)
docker build 후, docker tag my-portfolio:v1 your-registry/my-portfolio:v1 을 사용해 Docker Hub나 AWS ECR 같은 레지스트리에 푸시(Push)합니다.
- 서버에서는
docker pull your-registry/my-portfolio:v1 로 이미지를 다운받고, docker run ... 으로 실행합니다.
초보자를 위한 배포 로드맵 추천: 처음이라면, 복잡한 3단계(Compose)까지 가기보다, 1단계 (로컬 개발) $\rightarrow$ 2단계 (Dockerfile로 단일 서비스 컨테이너화) $\rightarrow$ Docker Hub에 Push $\rightarrow$ VPS(가장 저렴한 VM)에서 docker run으로 실행 하는 순서로 진행하시는 걸 가장 추천합니다.
이 흐름만 익숙해져도, 포트폴리오 사이트 배포는 절반 이상 성공했다고 볼 수 있어요.
너무 깊이 생각하지 마시고, 일단 **"작은 성공"**을 목표로 하세요.
일단 React 프로젝트만 돌려보고, 2.
그걸 Dockerfile로 만들어서 로컬에서 컨테이너로 띄워보는 것까지를 1차 목표로 잡으시면 됩니다.
질문자님 프로젝트 응원합니다!
질문 있으시면 언제든 다시 오세요.