도커 이미지를 만들기 위해 Dockerfile을 작성합니다. Dockerfile은 프로젝트 루트 디렉토리에 위치시키면 됩니다. 테스트 당시 next.js 개발환경 버전은 아래와 같습니다.
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로 확연히 줄어든 것을 확인할 수 있었습니다.
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 메뉴에 우리가 좀전에 설치한 이미지 파일이 올라가 있는 것을 확인할 수 있습니다.
도커 데스크탑에 정상적으로 이미지 배포를 완료한 모습
이미지를 컨테이너 배포에 사용하고 싶다면, 원하는 이미지를 누르고 컨테이너 이름을 입력, 접근할 로컬 호스트 포트번호를 입력하면 컨테이너를 생성됩니다.
<간단하게 이미지를 활용해서 컨테이너를 생성한 모습>
# 업로드
docker push 도커허브아이디/web_client
$ sudo wget -qO- http://get.docker.com/ | sh
$ docker login
$ sudo systemctl start docker
$ docker pull 도커허브아이디/web_client:버전정보
$ docker images
$ docker run -p 80:3000 -d --rm 도커허브아이디/web_client