Debugging Sparrow

웹앱을 Nginx로 Dockerize 하기 (multi-stage build)

2019/03/11 웹앱 도커 Web app Docker Multi-stage

웹앱을 Nginx로 Dockerize 하기 (multi-stage build)

npm 혹은 yarn을 통해 관리되는 웹앱을 Nginx로 Dockerize하는 방법(웹앱의 Dockerfile 작성법)을 배워봅니다. 생각하는 과정을 통해 설명할 것이기 때문에 바쁘신 분들은 아래만 읽으셔도 좋습니다. 샘플로 create-react-app를 이용합니다.

bash
1
2
3
4
$ npx create-react-app my-app
$ cd my-app
$ yarn eject
$ yarn start

중간에 yarn eject를 통해 실제 개발 환경과 최대한 비슷하게 만들어 봅시다. start를 하면 웹 페이지가 나옵니다.

Dockerize

우리는 이 샘플 웹앱을 Dockerize 할 것입니다.

bash
1
2
$ touch Dockerfile
$ touch .dockerignore

Dockerfile와 .dockerignore를 만들어 줍니다. 디렉터리 구조는 아래와 같습니다.

bash
1
2
3
4
5
6
7
8
9
10
11
12
13
.
├── .dockerignore
├── .git
├── .gitignore
├── Dockerfile
├── README.md
├── config
├── node_modules
├── package.json
├── public
├── scripts
├── src
└── yarn.lock

먼저 아래와 같이 Dockerfile을 수정해 봅니다.

Dockerfile
1
2
3
4
5
6
7
8
9
10
FROM node:10

WORKDIR /usr/src/app

COPY package*.json ./
RUN yarn install
COPY . .
EXPOSE 3000

CMD ["yarn", "start"]

COPY를 나눠서 해주는 이유는 cache를 적극적으로 이용하기 위해서입니다.
로컬 모듈과 디버깅 로그 복사를 막기 위해 .dockerignore도 작성해 줍니다. (CI/CD툴을 이용할 때는 필요하지 않습니다.)

.dockerignore
1
2
node_modules
npm-debug.log

이제 실행해 보겠습니다. 포트 중복을 막기 위해 위에서 실행한 프로그램은 종료해주세요.

실행하기

bash
1
2
docker build -t naive_image .
docker run -p 3001:3000 -d --name naive_webapp naive_image

localhost:3001로 접속해보면 정상적으로 접속이 됩니다.

하지만 위의 Dockerfile은 문제가 있습니다. yarn start의 script를 살펴보면 webpack-dev-server를 이용합니다. 최적화와 보안에 신경을 써야 하는 우리는 이렇게 하면 안 됩니다. yarn build를 통해 생성된 정적 파일을 서빙해야 합니다.

그렇다면 Dockerfile에서 해주어야 할 것은 무엇일까요? 빌드와 빌드를 통해 생성된 정적 파일의 서빙입니다. 정적 파일의 서빙은 nginx로 할 것입니다. 다시 말씀드리면 빌드는 node, 서버는 nginx 입니다. 빌드와 실행 시 환경이 다를때 Dockerfile은 어떻게 해야 할까요?

Dockerfile에 nginx를 설치하는 과정을 넣을 수 있습니다만, 이러면 Docker image가 커지고 실행 시에 불필요한 파일 또한 많아집니다. 그럴 때 필요한 것이 Multi-stage build입니다.

Multi-stage build

Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
FROM node:10 as builder

WORKDIR /usr/src/app

COPY package*.json ./
RUN yarn install
COPY . .
RUN yarn build

FROM nginx:1.15.9-alpine

COPY --from=builder /usr/src/app/build /usr/share/nginx/html

Dockerfile을 살펴보시면 FROM이 두 번 나옵니다. 빌드 시 필요한 Docker 이미지와 실행 시 필요한 Docker 이미지를 따로 해주고 12번 라인과 같이 첫 이미지에서 생성된 빌드 된 파일들을 복사해옵니다. CMD는 생략해서 nginx 기본 이미지에서 상속받습니다.

실행해 봅시다.

bash
1
2
docker build -t webapp .
docker run -p 8080:80 -d --name webapp_container webapp

이번엔 localhost:8080로 접속할 수 있습니다.

bash
1
2
3
4
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
naive_image latest 7970daf4d02 About a minute ago 1.18GB
webapp latest 9727d8420d66 6 minutes ago 16.6MB

도커 이미지의 사이즈가 확연히 차이 나는 걸 보실 수 있습니다.
핵심은 빌드와 실행 시 환경의 분리입니다.

Author: dbgsprw

Link: https://dbgsprw.github.io/2019/03/11/dockerize_webapp/

Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.

< PreviousPost
스칼라, 함수형 프로그래밍(1) - 프로그래밍 패러다임
NextPost >
쿠버네티스(Kubernetes, k8s) 용어 정리
CATALOG
  1. 1. 웹앱을 Nginx로 Dockerize 하기 (multi-stage build)
    1. 1.1. Dockerize
    2. 1.2. 실행하기
    3. 1.3. Multi-stage build