로컬에서 Docker 를 이용한 Express 서버 어플리케이션 개발

2022. 12. 1. 17:00·Docker

들어가며

이번 게시글에서 어떻게 Express 서버 어플리케이션을 Docker를 이용해서 컨테이너화 후 가동하고, 어떻게 로컬에서 작업한 코드 변경사항이 현재 가동되고 있는 Express 서버 컨테이너에 즉시 반영될 수 있는지에 대해서 알아보도록 하겠습니다.

Express 서버 어플리케이션 작성

원하는 위치에 디렉토리 생성 후 그 안에 package.json 파일 생성

$ mkdir demo && cd demo
$ npm init -y

npm 을 통해 Express 패키지 설치

$ npm install express

index.js 파일 생성 후 간단한 Express 서버 코드 작성

index.js

const express = require("express");
const app = express();
const port = 3000;

app.get("/", (req, res) => res.send("Hello Express!"));

app.listen(port, () =>
  console.log(`Example app listening at http://localhost:${port}`)
);

node 로 서버를 실행하기 위한 npm start 스크립트 package.json 파일에 추가

package.json

{
  // ...
  "scripts": {
    "start": "node ."
  }
  // ...
}

이제부터 npm start 명령을 실행해 Express 서버 어플리케이션을 실행할 수 있습니다.

 

Docker 를 이용한 개발 환경을 구축하기 위해서는 Express 서버 어플리케이션에 대한 이미지를 생성하기 위한 Dockerfile 을 작성하는 것입니다.

Dockerfile 작성

Dockerfile

# Base 이미지를 nodeJS alpine 버전으로 사용
FROM node:alpine

# 작업 디렉토리 전환
WORKDIR /app

# local 컴터에있는  package.json 파일을 현재 워킹 디렉토리에 복사
COPY package*.json ./

# local machine 에서 npm install 실행 
RUN npm install --silent

# 코드 복사
COPY . .

# 어플리케이션 구동
CMD ["npm", "start"]
EXPOSE 3000

Docker는 Dockerfile에 작성된 명령어를 순차적으로 실행하면서 image 를 빌드(build)합니다.

image에는 어플리케이션 코드뿐만 아니라 어플리케이션 실행에 필요한 환경 구성, 작업 내용이 포함되어 있습니다.

 

Docker image의 파일 시스템에 있는 node_modules 디렉토리가 현재 로컬 작업 디렉토리의 node_modules 디렉토리로 덮어씌워지는 걸 방지하기 위해 .dockerignore 파일도 추가해줍니다.

.dockerignore

node_modules

.dockerignore 파일은 docker image를 빌드할 때, 어떤 파일을 제외시킬 것인지를 명시하는 파일입니다.

Docker image 빌드 및 Container 실행

다음의 명령어를 이용하여 위에서 작성한 Dockerfile 을 이용하여 Container Image 를 빌드합니다.

$ docker build --tag app:0.1 .

주의할 점은 점(.) 앞에 반드시 빈칸을 넣는 것입니다. 마지막 . 의 의미는 도커 파일의 경로를 지정하기 위한 것입니다.

 

다음의 명령어를 이용하여 빌드한 이미지를 확인할 수 있습니다.

$ docker images

빌드한 이미지를 확인했다면 이제 빌드된 이미지를 Docker container로 실행할 차례입니다.

host의 포트 8080으로 들어오는 트래픽을 container의 포트 3000으로 포워딩시키겠습니다.

$ docker run -d -p 8080:3000 app

 

현재 구동 중인 Docker container 는 다음 명령을 통해 알 수 있습니다.

$ docker ps

 

이제 브라우저 또는 새 터미널 탭에서 http://localhost:8080 에 접속하면 "Hello Express!" 를 확인하실 수 있습니다.

$ curl http://localhost:8080
Hello Express!

여기서 주의할 점은 http://localhost:3000 이 아닌 http://localhost:8080에 접속해야 한다는 것입니다.

3000은 container의 내부 네트워크에서 사용되는 포트이고, 현재 host 에서 접속하는 상황이므로 포워딩된 포트 8080으로 접속해야 합니다.

 

지금까지 Express 서버 어플리케이션을 Docker를 이용해서 어떻게 컨테이너화하고 가동시키는지 알아보았습니다.

 

이어서 어떻게 로컬에서 작업한 코드 변경사항이 현재 가동되고 있는 Express 서버 컨테이너에 즉시 반영될 수 있는지에 대해 알아보겠습니다.

코드 변경 실시간 감지를 위한 Nodemon 패키지 적용

npm 으로 nodemon 패키지 설치

$ npm install -D nodemon

node 대신 nodemon으로 서버를 실행하기 위해 npm start 스크립트를 수정합니다.

package.json

{
  // ...
  "scripts": {
    "start": "nodemon ."
  }
  // ...
}

다시 서버를 시작하고, 코드를 수정하면 바로 서버가 재시작되어 변경사항이 반영되는 것을 확인하실 수 있을 것입니다.

Image 재빌드

Nodemon 패키지를 추가로 설치했고, package.json 스크립트가 변경되었기 때문에 container image를 재빌드해야 합니다.

$ docker build --tag app:0.2 .

이제 재빌드된 image를 Docker container로 다시 실행해보면 마찬가지로 Nodemon이 어플리케이션을 실행해주는 것을 확인할 수 있습니다.

$ docker run -d -p 8080:3000 app

 

현재 구동 중인 Docker container 는 다음 명령을 통해 알 수 있습니다.

$ docker ps



로컬에서 코드를 변경한 후 변경사항이 잘 반영되는지 확인해보았습니다. Nodemon 으로 코드 변경사항을 실시간으로 감지함에도 불구하고 코드 변경사항은 반영되지 않았습니다.

그 이유는 바로 container는 host로부터 격리된 파일 시스템을 가지기 때문에 container는 image 빌드 당시의 코드 복사본을 계속 참조하고 있어 image 빌드 시점 이후의 코드 변경사항에 대해서는 감지하지 못합니다.

이 문제를 해결하기 위해 container 내부에서 구동 중인 어플리케이션도 로컬 작업 디렉토리를 참조할 수 있도록 마운트(mount)해줘야 합니다.

$ docker run -d -p 8080:3000 -v $PWD:/app app:0.2

여기서 $PWD 는 현재 로컬 작업 디렉토리 위치를 의미하며, /app 은 컨테이너에서 작업 디렉토리 위치를 의미합니다.

로컬 작업 디렉토리와 컨테이너 상의 작업 디렉토리 간 sync 를 맞춰주었습니다.
이를 바인드 마운트라고도 합니다.

바인드 마운트를 이용해서 로컬 작업 디렉터리를 컨테이너의 특정 경로(작업 디렉토리 위치)에 마운트해주면 코드를 변경할 때 마다 변경 사항을 실시간으로 컨테이너를 통해 확인할 수 있습니다.

 

이제, 로컬에서 코드를 수정하면 코드 수정 사항이 컨테이너 상의 작업 디렉토리 상에도 동일하게 반영되며 container 에서 돌아가는 Nodemon이 변경 사항을 감지하고 서버를 재시작해줄 것입니다.

 

 

'Docker' 카테고리의 다른 글

[Docker] vi: command not found 에러 해결  (0) 2022.12.02
Docker Volume 및 Docker 로 MySql 컨테이너 설정, 데이터 영구 저장  (2) 2022.12.01
도커 컨테이너 환경변수 주입  (0) 2022.11.10
계속해서 restart 상태인 컨테이너 디버깅하기  (0) 2022.11.10
[Error] unable to start container process: exec: "bash"  (0) 2022.11.10
'Docker' 카테고리의 다른 글
  • [Docker] vi: command not found 에러 해결
  • Docker Volume 및 Docker 로 MySql 컨테이너 설정, 데이터 영구 저장
  • 도커 컨테이너 환경변수 주입
  • 계속해서 restart 상태인 컨테이너 디버깅하기
rondeveloper
rondeveloper
  • rondeveloper
    Ron's learning record
    rondeveloper
  • 전체
    오늘
    어제
    • 분류 전체보기 (99)
      • k8s (1)
      • AWS (1)
      • 리눅스 (3)
      • Docker (8)
      • 라이브러리 & 프레임워크 (14)
        • React (2)
        • NestJS (8)
        • Spring (0)
        • Django (3)
        • FastAPI (1)
      • 웹 (2)
        • Nginx (1)
      • 프로그래밍 언어 (29)
        • HTML (0)
        • CSS (0)
        • JavaScript (21)
        • Python (3)
        • Node.js (0)
        • TypeScript (4)
        • Java (1)
      • Today I learned (9)
      • 알고리즘 (9)
        • 백준 (0)
        • 프로그래머스 (8)
        • 개념 (1)
      • 티끌모아 태산 (5)
        • 하루에 영단어 하나씩 (5)
        • 독서 (0)
      • 시행착오 (3)
      • 데이터베이스 (2)
        • MySQL (0)
      • 컴퓨터 과학 (8)
        • 네트워크 (2)
        • 운영체제 (0)
        • 데이터베이스 (2)
        • 자료구조 (4)
      • 포트폴리오 (4)
        • JJINCAFE IN SEOUL (4)
        • CODEUNICORN (0)
      • 회고 (0)
      • CICD (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    배열
    javascript
    Kubernetes
    typeorm
    쿠버네티스
    FastAPI
    도커
    nestjs
    코딩테스트
    Python
    typescript
    기초
    컨테이너
    프로그래머스
    모듈
    mysql
    Docker
    IP 주소
    자바스크립트
    Kubectl
    스택
    레벨2
    Til
    생활코딩
    리눅스
    iterable
    조인
    네트워크
    redis
    django
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
rondeveloper
로컬에서 Docker 를 이용한 Express 서버 어플리케이션 개발
상단으로

티스토리툴바