11. Docker Multi-stage builds
1. 테스트 구성 환경
1) 웹사이트 배포 워크 플로우
2) Angular
로컬 및 리모트 환경에서 Angular를 이용하여 웹사이트 개발
Angular를 이용하면 수많은 HTML, CSS, TypeScript 파일들이 생성됨
이외의 파일들은 Angular 프로젝트에서 사용되는 설정 파일, 디펜던시 파일 등이 있음
디펜던시 파일은 node_modules
라는 디렉터리에 저장되어 있고, 프로젝트에 따라 용량이 매우 커질 수 있음
node_modules
디렉터리는 .dockerignore
에 지정하여 제외시킨 후 빌드 시 설치함
3) Docker Node.js
Angular 프로젝트가 완성되었으면 Docker의 Node.js 이미지를 사용하여 빌드해야 함
여기서 빌드란 HTML, CSS, TypeScript 파일들을 압축하는 개념으로, 수많은 파일들이 몇 개의 파일들로 줄어듦
또한 TypeScript 파일은 JavaScript 파일로 컴파일되어 웹 브라우저가 로직을 읽을 수 있게 됨
결과적으로 index.html
, *.css
, *.js
형태의 파일이 생성됨
4) Docker Nginx
웹 브라우저는 index.html
을 요청할 곳이 필요하며, 웹 서버가 index.html
을 응답함
Angular는 Single Page Application(index.html
하나로 Navigating 할 수 있는 애플리케이션)이므로 nginx.conf
파일만 수정하면 웹 서버(현재 테스트에서는 프론트엔드 서버)를 구축할 수 있음
5) Docker Compose
프론트엔드 서버뿐만 아니라 백엔드 서버, 데이터베이스 서버 등의 네트워크 구성 및 관리를 위해 Docker Compose를 사용함
현재 테스트에서는 프론트엔드 서버만 구성함
6) 테스트용 디렉터리 생성 및 진입
mkdir -p ./Angular-Web/Web && cd ./Angular-Web
2. Angular (디폴트 프로젝트로 테스트)
1) NVM 설치
export NVM_DIR = " $HOME /.nvm" && (
git clone https://github.com/nvm-sh/nvm.git " $NVM_DIR "
cd " $NVM_DIR "
git checkout ` git describe --abbrev= 0 --tags --match "v[0-9]*" $( git rev-list --tags --max-count= 1 ) `
) && \. " $NVM_DIR /nvm.sh"
cat >>${ HOME } /.bashrc <<EOF
# NVM
export NVM_DIR="\$HOME/.nvm"
# This loads nvm
[ -s "\$NVM_DIR/nvm.sh" ] && \. "\$NVM_DIR/nvm.sh"
# This loads nvm bash_completion
[ -s "\$NVM_DIR/bash_completion" ] && \. "\$NVM_DIR/bash_completion"
EOF
2) Node.js 설치
nvm install --lts && \
nvm alias default lts/* && \
nvm use lts/*
3) Angular 설치 및 프로젝트 생성
npm install -g @angular/cli
ng new angular
3. Nginx
1) Angular 프로젝트 디펜던시 제외
echo "**/node_modules" >./Web/.dockerignore
2) nginx.conf
파일 작성
user www-data;
worker_processes 1;
pid /run/nginx.pid;
events {
worker_connections 4096;
multi_accept on;
use epoll;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html?$args;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
client_body_timeout 86400;
send_timeout 86400;
reset_timedout_connection off;
proxy_connect_timeout 86400;
proxy_send_timeout 86400;
proxy_read_timeout 86400;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
gzip on;
}
3) Dockerfile
파일 작성
# Get Arg from docker-compose.yml
ARG PROJECT
# Build Angular as base
FROM node:16.15.0-alpine AS base
ARG PROJECT
WORKDIR /app
COPY ./$PROJECT .
RUN npm install && npm run build
# Build Nginx as prod from base(Angular)
FROM nginx:latest AS prod
ARG PROJECT
RUN rm -rf /usr/share/nginx/html
COPY --from= base /app/dist/$PROJECT /usr/share/nginx/html
4. Docker Compose
1) .env
파일 작성
DRIVER="bridge"
SUBNET="172.18.0.0/16"
GATEWAY="172.18.0.1"
WEB_PROJECT="angular"
WEB_DIR="./Web"
WEB_DOCKERFILE="${WEB_DIR}/Dockerfile"
WEB_CONFIGFILE="${WEB_DIR}/nginx.conf"
WEB_IPV4="172.18.0.2"
WEB_HPORT="9999"
WEB_CPORT="80"
2) docker-compose.yml
파일 작성
version : "3.8"
services :
web :
container_name : "web"
build :
context : .
dockerfile : ${WEB_DOCKERFILE}
target : prod
args :
- PROJECT=${WEB_PROJECT}
ports :
- ${WEB_HPORT}:${WEB_CPORT}
working_dir : /
volumes :
- ${WEB_CONFIGFILE}:/etc/nginx/nginx.conf
networks :
net :
ipv4_address : ${WEB_IPV4}
networks :
net :
driver : ${DRIVER}
ipam :
config :
- subnet : ${SUBNET}
gateway : ${GATEWAY}
3) Docker Compose 실행
sudo docker-compose -p angular_web up -d
Docker Compose를 실행하면 다음과 같이 angular_web_web
이미지를 이용한 web
컨테이너가 생성되었음
Dockerfile
에서 Multi-stage builds를 이용했기 때문에 중간 이미지인 <none>
과 최종 이미지 angular_web_web
이 생성되었음
중간 이미지인 <none>
은 Angular 프로젝트를 빌드하는 것과 관련이 있을 뿐이지 웹사이트를 배포하는 것과는 관련이 없음
현재 기준으로 중간 이미지 자동 제거 기능은 없지만 Bash 스크립트로 해결 가능함
4) <none>
중간 이미지 제거
<none>
과 같이 컨테이너에 이용되지 않은 이미지는 다음과 같이 제거할 수 있음
sudo docker image prune -f
결과적으로, Multi-stage builds를 이용하면 총 539
MB가 필요한 웹사이트 배포를 142
MB에 할 수 있음(nginx:latest
및 node:16.15.0-alpine
이미지 제외 - 새로 빌드된 이미지 및 컨테이너에 종속되기 때문임)
142
MB인 이유는 nginx:latest 이미지의 사이즈(거의 전부) + Angular 빌드 후 사이즈
이기 때문임