Next.js Docker 컨테이너 배포 (Using Docker with Next.js)

bunny.log·2023년 5월 10일
0

도커 이미지를 만들기 위해 Dockerfile을 작성합니다. Dockerfile은 프로젝트 루트 디렉토리에 위치시키면 됩니다. 테스트 당시 next.js 개발환경 버전은 아래와 같습니다.

  • next@12.1.5
  • node@16.13.2

Dockerfile

node.js 버전 뒤에 alpine을 적었는데 이는 리눅스 경량 버전인 "알파인 리눅스" 이미지 설치를 명시한 것으로, 가볍고 간단한, 보안성을 목적으로 개발한 리눅스입니다. 각 단계별 설명은 아래 주석을 작성해 놨습니다.

FROM node:16.13.2-alpine

# 디렉토리 지정
WORKDIR /usr/src/app

# 의존성 설치를 위해 package.json, yarn.lock 복사
COPY package.json ./
COPY yarn.lock ./

# 의존성 설치
RUN yarn

# 필요한 모든 파일을 복사
COPY . .

# next.js 앱 빌드
RUN yarn build

# 컨테이너 포트 3000  설정
EXPOSE 3000

# 애플리케이션 실행
CMD [ "yarn", "start" ]

<다른 예제>

# 위에서 도커 허브 node 이미지를 기반으로 로컬로 다운로드 및 캐싱 되었기 때문에 이미지를 가져올 수 있다.
FROM node:18.4.0

# 만약 컨테이너 안의 이미지의 경로가 /app 이런식으로 되어있다면 작업할 div 경로를 설정할 수도 있다.
# 설정해주면 COPY 의 두번째 경로를 ./ 이것으로 했을 때 자동으로 /app 경로가 된다.
WORKDIR /app

# package.json 파일을 복사한다. 만약 다시 빌드할 때 변경사항이 없을 경우 npm install까지 그냥 넘어간다.
COPY package.json /app

# 이미지를 받으면 npm install을 자동으로 해줌
RUN npm install


# 어떤 파일이 이미지에 들어가야 하는지 
# 첫 번째 .은 이 프로젝트의 모든 폴더 및 파일들 (Dockerfile을 제외한)
# 두 번째 .은 파일을 저장할 컨테이너 내부 경로 (ex /app)
COPY . /app

# 배포환경으로 설정
ENV NODE_ENV=production

RUN npm run build

# 도케에게 우리가 서버를 실행할 포트를 말해준다.
EXPOSE 3000

# 이미지가 생성될 때 실행되지 않고 컨테이너가 실행될 때 수행하는 명령어
CMD ["npm","start"]

당연한 말이지만 개발 서버와 node 버전을 맞춰주어야 한다.

<다른 예제>

FROM node:14.15.5-alpine3.13 as base
WORKDIR /usr/src/app
COPY . /usr/src/app
RUN export $(grep -v '^#' .env.production | xargs) && \
  apk add curl bash --no-cache && \
  curl -sfL https://install.goreleaser.com/github.com/tj/node-prune.sh | bash -s -- -b /usr/local/bin && \
  npm i -g modclean minify-all serverless serverless-prune-plugin serverless-offline && \
  npm i --production && \
  npm i @vue/apollo-composable@4.0.0-alpha.10 && \
  npm run build --production && \
  node-prune && \
  minify-all && \
  echo y | modclean -n default:safe,default:caution && \
  NODE_ENV=production npm prune --production && \
  serverless config credentials --provider aws --key $AWS_ACCESS_KEY_ID --secret $AWS_SECRET_ACCESS_KEY

CMD ["sls", "deploy", "--stage", "production"]

각 라인마다 #1 이런 식으로 표기를 하겠습니다.

#2 WORKDIR를 이용해서 /usr/src/app으로 경로를 변경합니다.

#3 현재 경로에 있는 모든 파일을 /usr/src/app 으로 복사합니다.

(. dockerignore를 통해. gitignore처럼 복사에서 제외할 파일 및 폴더 등을 지정할 수 있습니다.)

#4 환경변수가 제대로 적용이 되지 않는 문제가 있어서 귀찮아서 shell로 박아 버렸습니다. 물론 해당 도커 파일은 node_modules 축소 후 배포를 하기 위함이기 때문에 전혀 문제없습니다.

#5 alpine 리눅스에 curl과 bash를 설치합니다.

#6 curl 명령을 이용하여 node-prune를 다운로드합니다. alpine 리눅스에서는 node-prune를 npm 명령으로 설치하기가 쉽지 않기 때문입니다. 다운로드 후에 bash 명령으로 node-prune를 실행 명령에 등록합니다.

#7 npm 명령으로 전역(글로벌)에 배포에 필요로 하는 패키지들과, node_modules를 축소시키기 위한 패키지들을 설치합니다. 전역으로 설치하면 S3에 업로드되는 압축파일에 포함되지 않아서 배포 과정 중에 필요한 경우는 전역으로 설치를 진행하시면 됩니다. (서버리스 플러그인은 이곳에!)

#8 production 명령을 포함하여 package.json을 설치합니다. --production으로 안 해도 되는 이유가 COPY를 통해

 node_modules를 이미 갖고 왔기 때문에 더 이상은 생략합니다...

(모르시는 분들도 있을 테니, --production 옵션을 주게 되면 devDependencis에 정의한 패키지를 설치하지 않습니다.)

#9 nuxt.js에서 vue/apollo-composable이 오류가 있어서 alpha10으로 강제 설치합니다.

 package.json에서 ^표시를 제외하시면 굳이 이렇게 안 하셔도 됩니다.

#10 production으로 빌드를 진행합니다.

#11 node-prune 명령을 이용해서 불순물(사용하지 않는 굳이 없어도 되는?)들을 제거합니다.

#12 minify-all 명령을 이용해서 코드의 축소(공백 제거 등)를 진행합니다.

#13 modclean을 '경고 주의'까지 포함하여 진행합니다. 이 녀석도 생각보다 물건이라 용량 축소에 도움이 큽니다.

#14 마지막으로 확인사살을 위해 npm prune까지 진행합니다.

#15 전역으로 설치한 serverless와 환경변수를 이용해서 도커 이미지에 본인 계정을 설정합니다.

#16 serverless를 production stage에 배포합니다.

이 도커 파일의 이미지를 확인해 보면 생각보다 높은걸 확인할 수 있습니다. alpine의 경우 117MB인 점을 감안해도 생각보다 높게 나오실 겁니다. 전역으로 설치한 패키지들이 문제지만, #7에서 언급한 것처럼 전역 설치 패키지들은 용량에 포함되지 않습니다.

저의 경우 buildModules와 node-prune minify-all modclean 등을 통해서 S3 압축파일 용량이 251MB -> 10.75MB로 확연히 줄어든 것을 확인할 수 있었습니다.

.dockerignore

node_modules는 이미지를 생성할 때 의존성 설치 명령어로 설치하기 때문에 .dockerignore에 추가합니다.

node_modules

.next

이미지 빌드 & 컨테이너 배포

컨테이너 배포를 위해 우선 이미지를 생성합니다. 이미지를 만들기 위해서 아래 명령어를 입력해 주세요.

# 이미지 빌드
docker build -t {이미지명} .
# ex) docker build -t myapp .

# 컨테이너 배포
docker run -d -p 3000:3000  test-app

docker build 명령어를 입력하면, 아래 과정을 거치면서 이미지 빌드를 진행합니다.


컨테이너 배포를 명령어로 진행할 수 있지만, 개인적으로 도커 데스크탑을 활용하면 굉장히 편리하게 도커를 사용할 수 있기 때문에 도커 데스크탑을 설치해서 사용하는 것을 추천합니다. 아래 images 메뉴에 우리가 좀전에 설치한 이미지 파일이 올라가 있는 것을 확인할 수 있습니다.

도커 데스크탑에 정상적으로 이미지 배포를 완료한 모습

이미지를 컨테이너 배포에 사용하고 싶다면, 원하는 이미지를 누르고 컨테이너 이름을 입력, 접근할 로컬 호스트 포트번호를 입력하면 컨테이너를 생성됩니다.


<간단하게 이미지를 활용해서 컨테이너를 생성한 모습>

Dockerhub Repository 생성

도커허브 업로드

# 업로드
docker push 도커허브아이디/web_client

Server

1. 인스턴스 서버에 도커 설치

$ sudo wget -qO- http://get.docker.com/ | sh

2. 인스턴스 서버에서 도커 로그인

$ docker login

3. 도커 시작

$ sudo systemctl start docker

4. 도커허브에서 이미지 pull

$ docker pull 도커허브아이디/web_client:버전정보

5. 이미지 id 확인

$ docker images

6. 컨테이너 실행

$ docker run -p 80:3000 -d --rm 도커허브아이디/web_client

출처
https://webruden.tistory.com/1060

https://typo.tistory.com/entry/Docker-Spring-Boot-Nextjs-%EB%B0%B0%ED%8F%AC-Nextjs-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0

profile
더 많은 유익한 내용은 ->> https://github.com/nam-yeun-hwa

0개의 댓글