소개: 왜 프론트엔드용 Docker인가요?
"하지만 내 컴퓨터에서는 작동합니다"라는 말을 몇 번이나 들어보셨나요? Docker는 이 문제를 해결합니다. 근본적으로: 개발부터 프로덕션까지 모든 환경은 정확히 동일한 컨테이너를 실행합니다. 동일한 종속성, 동일한 Node.js 버전 및 동일한 시스템 구성을 사용합니다.
프런트엔드 개발자에게 Docker는 단순한 백엔드용 도구가 아닙니다. 컨테이너화 Angular 애플리케이션은 100% 재현 가능한 빌드, 개발 환경을 갖추고 있음을 의미합니다. 팀 구성원 전체에 일관성이 있고 배포 프로세스가 단순화되었습니다. 이 기사에서는 최적화된 다단계 Dockerfile을 구축하고 SPA 라우팅을 위해 nginx를 구성합니다. Docker Compose로 완전한 개발 환경을 만들어 보겠습니다.
이 기사에서 배울 내용
- Docker가 프런트엔드 프로젝트에 유용한 이유
- Angular용 다단계 Dockerfile을 빌드하는 방법
- 구성 방법
.dockerignore더 빠른 빌드를 위해 - 로컬 개발에 Docker Compose를 사용하는 방법
- 빌드 시 환경 변수를 관리하는 방법
- SPA 라우팅을 위해 nginx를 구성하는 방법
- Docker 레이어 캐싱 최적화
- 컨테이너 상태 확인 및 디버깅
1. 프론트엔드용 Docker의 기본 개념
Dockerfile을 작성하기 전에 세 가지 주요 Docker 개념을 이해하는 것이 중요합니다. 프론트엔드 애플리케이션의 맥락에서:
프런트엔드 컨텍스트의 Docker
| 개념 | 설명 | 저는 프론트엔드를 사용합니다 |
|---|---|---|
| 영상 | 애플리케이션을 실행하는 데 필요한 모든 것을 포함하는 변경 불가능한 템플릿 | 컴파일된 Angular 앱 + nginx |
| 컨테이너 | 실행 중인 이미지 인스턴스 | 정적 파일을 제공하는 nginx 서버 |
| 다단계 구축 | 최종 결과만 이미지에 포함되는 여러 단계의 Dockerfile | 1단계: Node.js로 빌드, 2단계: nginx로 제공 |
다단계 빌드의 장점은 최종 이미지에 Node.js, npm 또는 i가 포함되지 않는다는 것입니다.
node_modules: 정적 파일과 nginx 파일만 컴파일됩니다. 이렇게 획기적으로 줄어듭니다
이미지 크기는 약 1.5GB에서 50MB 미만입니다.
2. .dockerignore 파일
Dockerfile을 만들기 전에 다음을 구성해 보겠습니다. .dockerignore. 이 파일은 작동합니다
어떻게 .gitignore 하지만 Docker 빌드 컨텍스트의 경우: 제외된 모든 것
Docker 데몬으로 전송되지 않으므로 빌드 속도가 크게 향상됩니다.
# .dockerignore
node_modules
dist
.angular
.git
.github
.vscode
.idea
# File di configurazione non necessari per la build
*.md
LICENSE
.editorconfig
.prettierrc
.eslintrc*
# File Docker (evita ricorsione)
Dockerfile*
docker-compose*
.dockerignore
# File di test
coverage
e2e
*.spec.ts
# File di ambiente locali
.env.local
.env.development.local
node_modules를 잊지 마세요!
들어오지 못하게 하다 node_modules 빌드 컨텍스트에서 중요한 것은 다음과 같습니다. 이러한 제외 없이
Docker는 각 빌드마다 수백 메가바이트의 파일을 데몬에 푸시합니다.
실행 npm ci 처음부터 종속성을 설치합니다. 빌드는 다음 사이에서 전환될 수 있습니다.
이 줄만 추가하면 2분에서 30초 정도 소요됩니다.
3. Angular용 Dockerfile 다단계
다음은 Angular 애플리케이션에 최적화된 다단계 Dockerfile입니다. 첫 번째 단계가 실행됩니다. 빌드, 두 번째는 nginx를 사용하여 정적 파일을 제공합니다.
# ============================================
# Stage 1: Build dell'applicazione Angular
# ============================================
FROM node:20-alpine AS build
# Impostare la directory di lavoro
WORKDIR /app
# Copiare PRIMA i file di dipendenze (per il layer caching)
COPY package.json package-lock.json ./
# Installare le dipendenze
RUN npm ci --ignore-scripts
# Copiare il resto del codice sorgente
COPY . .
# Eseguire la build di produzione
RUN npx ng build --configuration=production
# ============================================
# Stage 2: Servire con nginx
# ============================================
FROM nginx:1.25-alpine AS production
# Rimuovere la configurazione di default di nginx
RUN rm /etc/nginx/conf.d/default.conf
# Copiare la nostra configurazione nginx
COPY nginx.conf /etc/nginx/conf.d/
# Copiare i file compilati dallo stage di build
COPY --from=build /app/dist/my-app/browser /usr/share/nginx/html
# Esporre la porta 80
EXPOSE 80
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost/ || exit 1
# Avviare nginx in foreground
CMD ["nginx", "-g", "daemon off;"]
지시사항의 순서를 준수하세요. COPY: 먼저 복사하자 package.json e
package-lock.json, 그런 다음 실행합니다. npm ci, 그런 다음에만 코드를 복사합니다.
소스. 이 순서는 Docker 캐싱 계층의 기본입니다.
COPY 순서가 중요한 이유
Docker는 이미지를 레이어로 빌드합니다. 각 명령은 새 레이어를 생성하고 Docker
입력 파일이 변경되지 않은 경우 캐시의 레이어를 재사용합니다. 다 복사하면
하나와 함께 COPY . ., 파일을 수정하면 해당 파일이 무효화됩니다.
종속성 설치 캐시. 올바른 순서로:
- 소스 코드 변경: 마지막 2개 레이어만 다시 빌드됩니다.
- 편집하다
package.json: 그들은 다음에서 재건되었습니다npm ci앞으로 - 변경 사항 없음: 캐시에서 거의 즉시 빌드
4. SPA용 Nginx 구성
Angular와 같은 단일 페이지 애플리케이션은 클라이언트 측 라우팅을 처리합니다. 이는 다음을 의미합니다.
nginx는 서비스를 제공해야 함 index.html 파일과 일치하지 않는 경로의 경우
정적. 구성은 다음과 같습니다.
# nginx.conf
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# Compressione gzip
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/xml
image/svg+xml;
# Cache per i file statici con hash nel nome
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
try_files $uri =404;
}
# SPA fallback: qualsiasi percorso non trovato viene servito da index.html
location / {
try_files $uri $uri/ /index.html;
}
# Header di sicurezza
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Disabilitare il listing delle directory
autoindex off;
# Nascondere la versione di nginx
server_tokens off;
}
Nginx 구성 핵심 사항
try_files $uri $uri/ /index.html: SPA 라우팅의 기본 규칙gzip: 전송되는 파일의 크기를 줄이기 위한 압축expires 1y: 해시된 파일에 대한 적극적인 캐싱(Angular는 자동 해싱을 사용함)- 보안 헤더: XSS 및 클릭재킹에 대한 기본 보호
5. 빌드 시 환경 변수
컨테이너화된 Angular 애플리케이션의 일반적인 문제는 변수 관리입니다. 환경의. Angular는 빌드 시 변수를 번들로 컴파일하므로 다음을 수행해야 합니다. 빌드 인수로 전달합니다.
# Dockerfile con build arguments
FROM node:20-alpine AS build
WORKDIR /app
# Definire gli argomenti di build
ARG API_URL=http://localhost:3000
ARG ENVIRONMENT=production
ARG GOOGLE_ANALYTICS_ID
# Impostare le variabili d'ambiente per la build
ENV API_URL=${API_URL}
ENV ENVIRONMENT=${ENVIRONMENT}
ENV GOOGLE_ANALYTICS_ID=${GOOGLE_ANALYTICS_ID}
COPY package.json package-lock.json ./
RUN npm ci --ignore-scripts
COPY . .
# Usare la configurazione corrispondente all'ambiente
RUN npx ng build --configuration=${ENVIRONMENT}
FROM nginx:1.25-alpine AS production
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d/
COPY --from=build /app/dist/my-app/browser /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
빌드 중에 빌드 인수를 전달하려면 다음 안내를 따르세요.
# Build con variabili personalizzate
docker build \
--build-arg API_URL=https://api.example.com \
--build-arg ENVIRONMENT=production \
--build-arg GOOGLE_ANALYTICS_ID=G-XXXXXXXXXX \
-t my-angular-app:latest .
# Build per staging
docker build \
--build-arg API_URL=https://staging-api.example.com \
--build-arg ENVIRONMENT=staging \
-t my-angular-app:staging .
6. 개발용 Docker Compose
로컬 개발의 경우 Docker Compose를 사용하면 여러 서비스를 단일 서비스로 오케스트레이션할 수 있습니다. 명령. 다음은 API 백엔드인 핫 리로드된 Angular 앱을 포함하는 설정입니다. 그리고 데이터베이스:
# docker-compose.yml
services:
angular-app:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "4200:4200"
volumes:
- .:/app
- /app/node_modules
environment:
- NODE_ENV=development
command: npx ng serve --host 0.0.0.0
api:
image: node:20-alpine
working_dir: /app
ports:
- "3000:3000"
volumes:
- ./api:/app
command: npm run dev
environment:
- DATABASE_URL=postgresql://user:password@db:5432/mydb
db:
image: postgres:16-alpine
ports:
- "5432:5432"
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
- POSTGRES_DB=mydb
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
개발용 Dockerfile
개발 Dockerfile은 프로덕션 Dockerfile과 다릅니다. Node.js를 포함하고 코드를 어셈블합니다.
소스를 볼륨으로 사용하고 ng serve 핫 리로드 사용:
# Dockerfile.dev
FROM node:20-alpine
WORKDIR /app
# Installare Angular CLI globalmente
RUN npm install -g @angular/cli
# Copiare i file di dipendenze
COPY package.json package-lock.json ./
# Installare le dipendenze
RUN npm ci
# La directory di lavoro viene montata come volume
# quindi non serve COPY del codice sorgente
EXPOSE 4200
CMD ["npx", "ng", "serve", "--host", "0.0.0.0", "--poll", "2000"]
필수 Docker Compose 명령
| 명령 | 설명 |
|---|---|
docker compose up -d |
모든 백그라운드 서비스 시작 |
docker compose down |
컨테이너를 중지하고 제거합니다. |
docker compose logs -f angular-app |
실시간으로 로그 보기 |
docker compose exec angular-app sh |
컨테이너에서 셸을 엽니다. |
docker compose build --no-cache |
캐시 없이 재구축 |
7. Docker 빌드 최적화
Docker 빌드 최적화는 단지 속도에 관한 것이 아닙니다. 더 작은 이미지 이는 더 빠른 배포, 더 낮은 대역폭 소비 및 감소된 공격 표면을 의미합니다.
이미지 크기 비교
# Confronto dimensioni con diverse immagini base
# node:20 (Debian) ~1.1 GB
# node:20-slim ~240 MB
# node:20-alpine ~130 MB
# nginx:alpine ~40 MB (solo per la fase finale)
# Dimensioni tipiche dell'immagine finale:
# Senza multi-stage: ~1.5 GB (Node.js + node_modules + dist)
# Con multi-stage: ~45 MB (nginx + file statici)
최적화 전략
# Dockerfile ottimizzato con tutte le best practice
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
# Installare solo le dipendenze di produzione per ridurre i layer
RUN npm ci --ignore-scripts && npm cache clean --force
FROM node:20-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npx ng build --configuration=production
# Rimuovere i source map se non necessari
RUN find /app/dist -name "*.map" -delete
FROM nginx:1.25-alpine AS production
# Usare un utente non-root per sicurezza
RUN addgroup -g 1001 -S appgroup && \
adduser -S appuser -u 1001 -G appgroup
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist/my-app/browser /usr/share/nginx/html
RUN chown -R appuser:appgroup /usr/share/nginx/html && \
chown -R appuser:appgroup /var/cache/nginx && \
chown -R appuser:appgroup /var/log/nginx && \
touch /var/run/nginx.pid && \
chown appuser:appgroup /var/run/nginx.pid
USER appuser
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
8. 상태 확인 및 디버깅
상태 확인을 통해 Docker(및 Kubernetes와 같은 오케스트레이터)는 다음을 확인할 수 있습니다. 컨테이너는 단순히 실행되는 것이 아니라 실제로 작동합니다.
# Health check nel Dockerfile
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost/ || exit 1
디버깅에 유용한 명령
# Verificare lo stato di salute del container
docker inspect --format='{{.State.Health.Status}}' my-angular-container
# Visualizzare i log del container
docker logs my-angular-container --tail 50
# Entrare nel container in esecuzione
docker exec -it my-angular-container sh
# Verificare i file serviti
docker exec my-angular-container ls -la /usr/share/nginx/html
# Testare la risposta nginx dall'interno del container
docker exec my-angular-container wget -qO- http://localhost/
# Analizzare i layer dell'immagine
docker history my-angular-app:latest
# Controllare la dimensione dell'immagine
docker images my-angular-app
9. 생산 vs 개발 이미지
요구 사항이 있으므로 프로덕션 및 개발을 위해 별도의 Dockerfile을 유지하는 것이 중요합니다. 매우 다르다:
생산과 개발 비교
| 특성 | 생산 | 개발 |
|---|---|---|
| 기본 이미지 | nginx:알파인 | 노드:알파인 |
| 섬기는 사람 | nginx | ng 서브(webpack-dev-server) |
| 핫 리로드 | No | 예(볼륨 마운트 사용) |
| 소스 맵 | 아니요(또는 Sentry에 업로드) | Si |
| 크기 | ~45MB | ~500MB |
| 사용자 | 비루트 | 루트(볼륨 권한용) |
프로덕션에서 이미지 개발을 사용하지 마십시오.
개발 이미지에는 Node.js, npm 및 모든 devDependency가 포함되어 있습니다. 존재하는 것 외에도 훨씬 더 크면 훨씬 더 큰 공격 표면이 노출됩니다. 항상 프로덕션을 위한 다단계 Dockerfile.
10. 빌드 및 실행 완료
두 환경 모두에서 애플리케이션을 빌드하고 시작하는 명령을 요약합니다.
# === PRODUZIONE ===
# Build dell'immagine di produzione
docker build -t my-angular-app:latest .
# Avviare il container
docker run -d \
--name angular-prod \
-p 8080:80 \
--restart unless-stopped \
my-angular-app:latest
# Verificare che funzioni
curl http://localhost:8080
# === SVILUPPO ===
# Avviare con Docker Compose
docker compose up -d
# Verificare i servizi
docker compose ps
# Vedere i log
docker compose logs -f angular-app
# Fermare tutto
docker compose down
결론
이 기사에서는 프런트엔드 개발자의 관점에서 Docker를 살펴보았습니다. 최적화된 프로덕션 이미지를 생성하는 다단계 Dockerfile을 구축했습니다. 50MB 미만, 압축 및 캐싱을 사용하여 SPA 라우팅을 위해 nginx를 구성하고 생성했습니다. Docker Compose를 사용한 완전한 개발 환경.
기억해야 할 핵심 사항은 다음과 같습니다. 프로덕션에는 항상 다단계 빌드를 사용하세요.
올바르게 구성 .dockerignore,의 순서를 존중합니다 COPY
캐싱 계층의 경우 개발 및 프로덕션을 위해 별도의 Dockerfile을 유지합니다.
다음 글에서는 통합하는 방법을 알아보겠습니다. GitHub Actions를 사용한 Firebase 호스팅 끌어오기 요청에 대한 미리보기 채널을 사용하여 완전한 자동 배포 흐름을 생성합니다. 그리고 롤백 전략.







