🐳 Docker 실무
Multi-stage Build를 통한 이미지 최적화와 Docker Compose를 이용한 다중 컨테이너 오케스트레이션을 학습합니다.
🟢Nginx란?
Nginx (Engine-X)
Nginx는 가볍고 성능이 뛰어난 웹 서버(Web Server)이자 리버스 프록시(Reverse Proxy)입니다.
🌟 주요 특징
- 비동기 이벤트 기반 구조: 적은 메모리로 많은 동시 접속 처리가 가능합니다.
- 리버스 프록시: 클라이언트의 요청을 대신 받아 백엔드 서버로 전달합니다.
- 정적 파일 서빙: HTML, CSS, 이미지 등을 매우 빠르게 제공합니다.
📚 용어 정리
1. 비동기 (Asynchronous)
- 동기(Sync): 이전 작업이 완료될 때까지 다음 작업이 대기하는 방식입니다.
- 비동기(Async): 이전 작업의 완료 여부와 상관없이 다음 작업을 동시에 진행하는 방식입니다.
2. 프록시 / 리버스 프록시 (Reverse Proxy)
- 포워드 프록시: 클라이언트 앞에 위치하여, 클라이언트를 대신해 외부 서버에 요청을 보냅니다.
- 리버스 프록시: 서버 앞에 위치하여, 외부 요청을 받아 내부 백엔드 서버로 전달합니다.
3. 로드밸런싱 (Load Balancing)
들어오는 트래픽을 여러 서버에 균등하게 분산시켜 특정 서버의 과부하를 방지하는 기술입니다.
🏗️ Multi-stage Build란?
하나의 Dockerfile 안에서 여러 개의 FROM 구문을 사용하여 빌드 단계(Stage)를 나누는 기법입니다.
FROM이 여러 번 등장할 수 있습니다.FROM 구문의 Stage만 실제 배포 이미지로 생성됩니다. 앞선 Stage는 중간 작업 공간입니다.🚀 왜 사용하는가?
- 이미지 크기 최소화: 빌드에만 필요한 도구(SDK, 컴파일러 등)를 최종 이미지에서 제외합니다.
- 보안 강화: 소스 코드나 불필요한 바이너리를 배포 이미지에 포함하지 않아 공격 표면을 줄입니다.
- 캐싱 최적화: 단계별로 레이어를 나누어 빌드 속도를 향상시킬 수 있습니다.
💡 비교: 일반 빌드 방식은 "빌드 도구 + 소스 + 결과물"이 모두 포함되어 수백 MB가 넘어가지만, Multi-stage는 "결과물"만 담아 수십 MB로 줄일 수 있습니다.
💻 Multi-stage 예제 (Dockerfile)
npm ci를 활용하여 의존성을 설치하고, 빌드된 결과물(dist)만 Nginx 이미지로 복사합니다.
Dockerfile
package-lock.json을 기준으로 정확히 고정된 버전 설치. CI/CD 환경 권장
💡 레이어 캐싱 전략
package*.json을 소스보다 먼저 COPY하는 이유:
- 소스 코드는 자주 바뀌지만
package.json은 상대적으로 안정적 - 소스만 변경됐을 때
npm ci레이어를 캐시에서 재사용 → 빌드 속도 향상
.dockerignore
⚙️ 설정 파일 (Nginx)
SPA(Single Page Application) 라우팅을 위한 Nginx 설정입니다.
nginx.conf
listen 80
HTTP 기본 포트. HTTPS는 443 + SSL 설정 추가 필요
server_name
실제 운영 시 도메인명 입력 (example.com). 여러 도메인 공백으로 구분 가능
root
Dockerfile에서 COPY --from=builder /app/dist로 복사한 경로와 일치해야 함
location /
모든 URL 패턴을 이 블록에서 처리. API 서버가 있다면 location /api 블록으로 분리 가능
💡 Nginx SPA 설정
try_files: 요청된 파일이 없으면/index.html로 라우팅하여 Vue Router의 History 모드를 정상적으로 지원합니다.- 기본 포트 80으로 들어오는 모든 요청을 처리하며,
/usr/share/nginx/html에서 정적 파일들을 서빙합니다.
🚀 이미지 빌드 및 컨테이너 실행
Docker 이미지를 빌드하고 실행하여 Multi-stage 빌드의 결과물을 확인합니다.
1. 이미지 빌드
-t <이름:태그>
vue-multistage는 이미지 이름, 1.0은 버전 태그. 생략 시 latest로 자동 지정
. (빌드 컨텍스트)
현재 디렉토리를 빌드 컨텍스트로 설정. Dockerfile과 복사할 파일들의 기준 경로가 됨
2. 컨테이너 실행
-d
detached 모드. 컨테이너를 백그라운드에서 실행. 없으면 터미널이 컨테이너에 붙어 포그라운드로 실행됨
-p 8000:80
포트 포워딩. 호스트포트:컨테이너포트 형식. 호스트의 8000 → 컨테이너 Nginx 80으로 연결
--name
컨테이너에 이름 부여. 생략 시 Docker가 무작위 이름 자동 생성. 이름으로 stop/rm 가능
localhost:8000
:8000
Nginx :80
📋 Docker Compose란?
여러 개의 컨테이너를 정의하고 실행하기 위한 도구입니다. YAML 파일을 사용하여 애플리케이션의 서비스를 설정합니다.
* YAML은 Yet Another Markup Language 또는 YAML Ain't Markup Language를 의미합니다.
🌟 주요 특징
- 단일 명령 실행:
docker-compose up한 번으로 모든 서비스를 시작합니다. - 서비스 격리: 각 프로젝트마다 독립된 환경을 유지합니다.
- 데이터 보존: 컨테이너가 삭제되어도 볼륨을 통해 데이터를 유지합니다.
- 네트워크 자동 생성: 서비스 간 통신을 위한 기본 네트워크를 자동으로 구축합니다.
📝 YAML 코드란?
YAML 코드는 사람이 읽고 쓰기 쉽게 만들어진 데이터 직렬화 언어입니다. Docker Compose와 Kubernetes 등 다양한 인프라 도구의 설정 파일로 널리 사용됩니다.
📌 핵심 규칙
- 들여쓰기: 스페이스(Space)를 사용한 들여쓰기로 계층 구조를 나타냅니다. (탭(Tab) 문자 사용은 권장되지 않습니다)
- Key-Value:
키: 값형태로 데이터를 정의합니다. 콜론(:) 뒤에는 반드시 공백(스페이스)이 하나 있어야 합니다. - 리스트(배열): 하이픈(
-)으로 시작하여 여러 개의 항목을 나열합니다. - 주석:
#기호를 사용하여 주석을 작성합니다.
💻 작성 예시
⚡ 주요 명령어 (CLI)
실제 운영 시 가장 자주 사용되는 Compose 명령어 모음입니다.
| 명령어 | 설명 |
|---|---|
docker-compose up -d |
모든 서비스를 생성하고 백그라운드에서 실행 |
docker-compose down |
모든 컨테이너와 네트워크를 정지시키고 삭제 |
docker-compose logs -f |
실행 중인 서비스의 로그를 실시간 확인 |
docker-compose ps |
현재 Compose 프로젝트의 컨테이너 상태 확인 |
docker-compose exec [서비스] sh |
실행 중인 컨테이너 내부에 접속 |
🔥 실습: 방문자 카운터 (1) — 소스 코드
애플리케이션 소스 코드와 컨테이너 이미지를 빌드하기 위한 Dockerfile 구성입니다.
📄 main.py
📄 Dockerfile
📄 requirements.txt
🔥 실습: 방문자 카운터 (2) — Compose & 실행
Docker Compose를 활용하여 다중 컨테이너 환경을 구성하고 실행합니다.
📄 docker-compose.yaml
🚀 실행 및 확인
💡 주요 포인트
- 서비스 이름 통신:
app은redis라는 이름으로 자동 연결됩니다. - 의존성 관리:
depends_on으로 실행 순서를 제어합니다. - 원자적 연산: Redis의
incr()는 동시 요청에도 안전합니다.
✨ 부록: Node & Vue.js 설치
Node.js와 npm을 설치하고 최신 Vue 템플릿을 생성하여 개발 서버를 실행하는 과정입니다.
1. Node.js & npm 설치
2. Vue 프로젝트 생성 및 실행
💡 참고 사항
- 설치 시
create-vue패키지를 사용하여 프로젝트를 스캐폴딩합니다. - 기본 개발 서버 주소는 http://localhost:5173/ 입니다.
- 외부 네트워크에서 접근하려면
--host플래그를 추가해야 합니다.