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.jsonscript 에 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 에 복사하는 기능을 한다. COPYRUN 과 다르게 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

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"

Reference