배포/Docker

nestjs와 typeorm 그리고 postgres 환경에서 docker-compose로 한번에 띄우기

wonin 2023. 5. 16. 17:39

매번 개발을 할 때 db(postgres)를 docker로 띄웠었습니다. 그리고 서버를 따로 띄웠었습니다. 이 과정이 너무나 귀찮았기 때문에 서버+db를 한번에 띄우는걸 해보자 라고 결심했습니다.

제가 생각했던 흐름은

  1. 서버를 docker로 띄운다.
  2. db를 docker로 띄운다.(이미 postgres를 5432로 띄우고 있음)
  3. 서로 연결시켜준다.

위 과정을 진행시키려고 했습니다.

 

서버를 docker로 띄웁니다.

처음에 docker라는 계념을 잘 몰라서 서버를 Docker로 만다(?)라는 의미를 몰랐습니다. 이제는 알것도 같은데요. 서버를 docker 이미지 파일로 만든다 라는 뜻으로 이해하고 있습니다.

제가 이해한 docker의 계념은 어떤 환경에서든 잘 풀어쓸 수 있는 설계도를 이미지라 생각하고 설계도대로 물건을 만들면 컨테이너가 된다고 생각합니다.

제가 이해한 docker의 장점은 어떤 환경에서든 똑같은 물건을 만들어준다는게 장점이라고 합니다. 이를 “생산성”이라는 말로 멋지게 말할 수 있습니다.

 

서버를 docker 이미지 파일로 만들겠습니다.

🟦 먼저 Docker 이미지화 진행하고 싶은 프로젝트 root 경로에 Dockerfile을 생성합니다.

Dockerfile에 프로젝트 image화를 진행하기 위한 스크립트를 작성해줍니다.

Docker 파일 내용에는 본인 프로젝트를 도커 이미지화할 수 있는 스크립트가 포함되게 됩니다.

 

Dockerfile

FROM node:18          # 베이스 이미지
RUN mkdir -p /var/app # RUN 명령뒤에 리눅스 커맨드 사용가능
WORKDIR /var/app      # 실행 위치 설정
COPY . .              # COPY [복사할 파일] [복사할 목적지]
RUN npm install       # 실행 시 node_module 설치를 위함
RUN npm run build     # 스크립트 실행히 자동으로 빌드가 되도록
EXPOSE 3586           # 실행할 포트를 열기
CMD ["node", "dist/main.js"] # dist 파일의 main.js(빌드된 프로젝트)를 실행시키위한 명령어

이렇게 Dockerfile 생성을 완료했다면, 프로젝트를 이미지화 할 때 본인이 원하지 않은 파일까지 이미지화되는 것을 방지하기 위해 .dockerignore 파일도 생성해 줍니다.

 

.dockerignore

.git
Dockerfile
node_modules
dist

.dockerignore 은 .gitignore와 비슷하죠? 이것도 Dockerfile이 위치해있는 루트 폴더에 넣어줍니다.

 

🟦 docker build

이렇게 Dockerfile과 .dockerignore 파일을 구성한 이후 아래 명령어를 실행합니다.

docker build . -t [프로젝트 이름]

그럼 본인의 프로젝트가 이미지로 빌드되는 화면을 볼 수 있는데요.

프로젝트 이름은 무조건 lowercase로 해야하는거같습니다. 안그러면 repository name must be lowercase 라는 오류가 뜹니다.

 

🟦 docker container start

이미지를 만들었다면 실제로 물건을 만들어봐야 합니다.

프로젝트 이름의 이미지가 잘 생성되었다면 아래 명령어를 입력해 봅시다.

(window 에서 Docker Desktop은 반드시 실행되어야 합니다.)

docker run -d --name [컨테이너 이름] [프로젝트 이미지 이름]
  • -d: 는 detact 입니다. Run container in background and print counter ID(백그라운드로 컨테이너를 돌립니다. 그리고 id의 개수를 프린트해줍니다.)
  • -p: public list 입니다. Publish a container’s port(s) to the host ( 호스트의 포트를 정할 수 있다?)

자, 여기까지 잘 실행되었습니다. db도 띄웠고 서버도 따로 띄웠습니다. 하지만 문제가 생겼습니다.

 

👀 문제

아래와 같이 Connection 오류가 발생합니다.

Error: connect ECONNREFUSED 127.0.0.1:5432
 at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1146:16)

에러 로그에 나와있듯이 이는 접근하고자 하는 DB의 주소가 localhost (127.0.0.1) 이기 때문입니다.
Docker 입장에서 localhost는 내 PC일까요?
당연하게도 Docker 내부가 localhost 이기 때문에 현재 Docker 컨테이너 내부에서 PostgreSQL DB를 찾으려했지만 찾지 못하여 발생한 것입니다.
이를 해결하려면 DB의 접속 주소를 link된 DB로 인식할 수 있도록 코드 변경이 필요합니다.

기존에는 postgres 컨테이너만 돌리고 local로 server를 돌려서 서로간의 영역을 인지를 했습니다. 하지만 바로 컨테이너간 통신에, locahost를 사용할 수 없다고 합니다.

이유는 컨테이너는 개별 호스트처럼 이식되어 개별 컨테이너마다 localhost를 본인으로 지정하게 됩니다.

그래서 찾아보니 docker network를 같이하면 된다고 합니다.

(docker network에 대한 글)

하지만 위 방법으로 하면 명령어를 2번 치는것입니다. 옛날에 하던 방법과 똑같죠. 그래서 다른방법을 찾아봤습니다.

 

 

🟦 docker-compose

docker-compose란 여러 개의 컨테이너로부터 이루어진 서비스를 구축, 실행하는 순서를 자동으로 편리하게 관리를 간단히 하는 기능입니다.

컨테이너를 하나하나 명령어를 치지 않고 파일안에서 한꺼번에 관리할 수 있게합니다.

 

docker-compose.yml 파일

version: '3.8'

services:
  db:
    image: postgres
    ports:
      - '5432:5432'
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=test
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=1234
      - POSTGRES_INITDB_ARGS=--encoding=UTF-8

  app:
    build:
      context: .
      dockerfile: ./Dockerfile
    environment:
      - DB_HOST=db
      - DB_PORT=5432
      - DB_NAME=postgres
      - DB_USERNAME=postgres
      - DB_PASSWORD=1234
    depends_on:
      - db
    ports:
      - "3586:3586"
    volumes:
      - ./:/app/

volumes:
  db_data:

.yml 이란 확장자가 나오는데요. YAML(YAML Ain't Markup Language)은 사람이 쉽게 읽고 작성할 수 있는 데이터 직렬화 형식입니다. YAML은 계층적인 구조를 갖고 있으며, 들여쓰기를 통해 데이터의 계층 구조를 나타냅니다. 파이썬과 비슷하죠? 보기 쉽게 환경변수를 구성할 수 있습니다.

 

docker-compose 설정

원문

2. Docker Compose로 Nodejs 개발/배포환경 구성하기 - Docker Compose로 개선하기 (tistory.com)

원문을 꼭 보세요! 더 자세한 설명이 있습니다.

 

🟩 version: 3.8

🟩 service

  • docker-compose로 관리할 컨테이너를 명시합니다.
  • 컨테이너 = 서비스(services)
  • 명시한 순서대로 실행됩니다.

🟩 db 서비스 설정

image

  • 도커 이미지 입니다. 도커 공식 postgres 이미지를 사용합니다.

ports

  • 어떤 port로 db를 열지 설정합니다. 저는 5432포트로 접근하게끔 설정했습니다.

volumes

  • 컨테이너를 껏다 키면 db가 초기화 됩니다! 이를 방지하기 위함입니다.
  • : 데이터베이스 컨테이너 내부의 디렉터리를 로컬 컴퓨터의 디렉터리로 연결하였습니다. 이제 데이터베이스가 데이터를 저장할 파일 시스템으로 로컬 컴퓨터(/var/lib/postgresql/data)의 디렉터리를 사용합니다.

enviroment

  • docker run실행시 -e 옵션에 적었던 환경변수입니다. 환경변수는 컨테이너에 박혀서 실행됩니다.

🟩 app 서비스 설정

  • build
    • DB와 같이 이미지를 사용하는 것이 아니기 때문에 build를 사용합니다.
    • docker build 명령어를 수행합니다.
  • context
    • docker build 를 실행할 디렉토리입니다.
    • .로 했기 때문에 현재 위치가 됩니다.
  • dockerfile
    • 빌드에 사용될 Dockerfile을 선택합니다.
  • depends_on
    • 특정 서비스에 대한 의존도를 나타냅니다.
  • ports
    • 외부 포트와 컨테이너내 포트를 연결합니다.
    • docker run 명령어의 p 옵션과 동일합니다.
  • volumes
    • 로컬 PC의 디렉토리와 컨테이너 안의 디렉토리를 연결합니다.

docker-compose에서는 —link가 없더라도, 동일한 docker-compose.yml에 속해있는 services들은 서로 통신할 수 있는 지원합니다.

 

🟦 실행

명령어로 실행합니다.

docker-compose up

db와 app이 모두 실행되면 성공입니다.

-d 옵션을 붙이면 백그라운드 실행합니다.

docker-compose up -d

만약 Dockerfile도 변경되어서 이미지 생성부터 다시해아한다면 --build를 사용하면 됩니다.

docker-compose up -d--build

 

🟦 서비스 실행/종료

한번 실행된 docker 서비스를 실행/종료 합니다.

docker-compose stop
docker-compose start

이 둘을 합친 restart 옵션도 사용할 수 있습니다.

docker-compose restart

 

마무리

개발 속도를 빠르게 하기 위한 설정이였습니다. 배포할 때도 잘 동작하면 좋겠습니다.

 

참고

  1. Docker Compose 네트워크 | Engineering Blog by Dale Seo
  2. 1. Docker Compose로 Nodejs 개발/배포환경 구성하기 - Dockerfile로 구성하기 (tistory.com)
  3. 2. Docker Compose로 Nodejs 개발/배포환경 구성하기 - Docker Compose로 개선하기 (tistory.com)
  4. [Docker] docker compose 사용법 (tistory.com)
  5. Nestjs 프로젝트를 Docker로 배포하기 :: 코드 기어 Code Gear - 개발 강좌 (tistory.com)

 

 

728x90