NodeJS, ExpressJS 와 Docker
nodeJS 앱 만들기
프로젝트 폴더를 생성한 후에 폴더 안에 app.js 를 만든다. 아래와 같은 코드로 작성하며, hello world 를 출력하는 간단한 웹 앱이다.
app.js
const express = require('express');
const app = express();
app.get('/', (req, res) => res.send('hello world'));
app.listen(80, () => {
console.log('My REST API running on port 80!');
});
Express 를 app.js 에서 사용하기 때문에 terminal 에 다음과 같은 명령어를 입력하여 express 를 설치한다.
npm install express
이제 package.json 의 script 에 start command 를 추가한다. 이는 app.js 를 run 하기 위해서다.
package.json
"scripts": {
"start": "node app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
start command 가 제대로 작동하는지 확인하기 위해 terminal 에서 다음과 같이 명령어를 입력한 후에 웹브라우저에서 localhost 로 접속한다.
npm start
Docker 활용
프로젝트 디렉토리에 파일을 새로 만들고, 이름을 Dockerfile 이라고 한다. 아래와 같이 코드를 작성해준다.
Dockerfile
FROM node:14-slim
WORKDIR /app
COPY package.json /app
<!-- COPY package.json . -->
RUN npm install
COPY . /app
<!-- COPY . . -->
CMD ["npm", "start"]
위의 코드에서 FROM, WORKDIR, COPY, RUN, CMD 는 Instruction 로 통칭한다. 각 instruction 의 뜻을 살펴보자.
FROM instruction 은 DockerHub 에서 불러와 Container 안에서 사용할 Docker image 지정한다. 여기서 말하는 Docker image 는 node, python, ubuntu 등으로, DockerHub 에 이미 공식적으로 등록돼 있다. 위의 코드에서 FROM instruction 은 terminal 에서 install node 명령어를 실행한 것과 같다. 즉, FROM instruction 덕분에 따로 node 를 설치하지 않아도 되는 것이다. node:14-slim 에서 14-slim 은 tag 로, node 의 버전이다. slim, alpine, buster 등 버전 차이는 reference 를 참고하자.
WORKDIR 는 Container 의 working directory 를 의미한다. 위의 코드에서는 WORKDIR /app 이 입력돼 있다. 그렇기 때문에 아래에 있는 두 개의 COPY instructions 에서 “/app” 대신에 “.” 를 써도 된다.
COPY instruction 은 Host 에 있는 local 파일을 Container 에 복사하는 기능을 한다. COPY 는 RUN 과 다르게 Host 에서 명령어를 실행한다. COPY <source> <target> 가 instruction 형식으로, 위의 코드에서는 “COPY . /app” 이 입력돼 있다. 이 코드는 Host 의 directory “.” 에 있는 파일을 Container 의 “/app” directory 에 복사한다는 뜻이다.
RUN instruction 은 리눅스 명령어를 Container 내부에서 실행하는 기능을 한다. 즉, 위의 코드에서 RUN npm install 은 Container 내부에서만 실행될뿐, Host 나 local 에서는 실행되지 않는다.
CMD instruction 은 Container 안에서 무슨 linux 명령어를 실행할지 지정하는 기능이다. 위의 코드에서는 “CMD [“npm”, “start”]” 가 입력돼 있다. 이 코드는
npm start
를 입력한 것과 동일하다. “1. nodeJS 앱 만들기” 에서 package.json 에 아래와 같은 설정을 한 바 있다.
"scripts": {
"start": "node app.js",
위의 설정으로 인해 “npm start” 는 “node app.js” 를 Terminal 에 입력하는 것과 동일하다.
AWS 를 통해 배포하는 것은 여기를 참조하자.
Reference
- Docker-izing a NodeJS ExpressJS API - Tutorial, TutorialEdge - Youtube
- Best practices for writing Dockerfiles , docker docs - Docker Inc.
- Dockerfile Tutorial - Docker in Practice || Docker Tutorial 10 , TechWorld with Nana - Youtube
- Dockerfile copy command, Richard Chesterwood - Youtube
- Alpine, Slim, Stretch, Buster, Jessie, Bullseye — What are the Differences in Docker Images?, Julie Perilla Garcia - Medium
NodeJS Crash Course 정리
node js 를 설치한 후에 visual studio terminal 에서
npm init
을 입력한다. 필자는 여기서 author 만 설정하고 나머지는 모두 default 로 두었다.
추후에 dependenices 와 devDependencies 를 추가하기 위해 각각 아래와 같은 명령어를 terminal 에 입력한다.
npm install uuid
npm install -D nodemon
package.json 에 dependencies 가 추가된 것을 확인할 수 있다. package.json 로 dependencies 를 설정할 수 있으며, deploy 할 때는 node_modules 로 하지 않고 package.json 으로 한다.
이제 main file 을 생성한다. package.json 을 보면 “main” 이 “index.js” 로 설정돼 있다. 그러므로 main file 의 이름을 index.js 로 생성한다.
참고로 module 에는 Module Wrapper Function 이 존재한다. 미리 생성돼 있기 때문에 우리가 써줄 필요는 없다. 아래와 같은 함수다.
(function (exports, require, module, __filename, __dirname) {
})
그렇기 때문에 아래와 같은 코드를 입력해도 에러 없이 작동한다.
console.log(__dirname, __filename)
서버를 돌릴 경우 .js 파일이 변경될 때마다 서버를 중지하고 다시 실행해야 반영된다. 서버를 중지할 필요 없이 .js 파일의 변경 사항이 즉시 반영되게 하는 방법은 nodemon 이다. package.json 의 Debug 항목에 다음과 같이 “dev” 항목을 추가한다.
"scripts": {
"start": "node index",
"dev": "nodemon index"
}
그 다음에 terminal 에서 다음과 같은 명령어를 실행하면, 서버를 중지할 필요 없이 즉시 변경사항이 반영된다.
npm run dev
index.js
const PORT = process.env.PORT || 5000;
package.json
"start": "node index"