From a95a173c29946b4eaebd594b37fbe3e29725fc9b Mon Sep 17 00:00:00 2001 From: scarf Date: Sat, 5 Oct 2024 18:18:47 +0900 Subject: [PATCH 1/4] build: dev dockerfile --- README.md | 7 +++++++ backend/Dockerfile.dev | 6 ++++++ backend/package.json | 3 ++- compose-dev.yml | 27 +++++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 backend/Dockerfile.dev create mode 100644 compose-dev.yml diff --git a/README.md b/README.md index 9d8cd16..8a0d584 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,9 @@ # backend-nest + 6차 개발팀은 nestjs 로 새로 작성하기로 했습니다 + +## 개발용 compose 실행 방법 + +```sh +$ docker compose -f compose-dev.yml up --remove-orphans +``` diff --git a/backend/Dockerfile.dev b/backend/Dockerfile.dev new file mode 100644 index 0000000..e070061 --- /dev/null +++ b/backend/Dockerfile.dev @@ -0,0 +1,6 @@ +FROM node:22-slim AS base +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +RUN corepack enable + +WORKDIR /app diff --git a/backend/package.json b/backend/package.json index 5199d2d..1554d0b 100644 --- a/backend/package.json +++ b/backend/package.json @@ -76,5 +76,6 @@ ], "coverageDirectory": "../coverage", "testEnvironment": "node" - } + }, + "packageManager": "pnpm@9.12.0+sha512.4abf725084d7bcbafbd728bfc7bee61f2f791f977fd87542b3579dcb23504d170d46337945e4c66485cd12d588a0c0e570ed9c477e7ccdd8507cf05f3f92eaca" } diff --git a/compose-dev.yml b/compose-dev.yml new file mode 100644 index 0000000..6447e92 --- /dev/null +++ b/compose-dev.yml @@ -0,0 +1,27 @@ +services: + database: + platform: linux/x86_64 + container_name: database + image: mysql:8.0 + environment: + - TZ=Asia/Seoul + + ports: + - 3306:3306 + + env_file: .env + + backend: + container_name: backend + restart: on-failure + build: + context: backend + dockerfile: Dockerfile.dev + + entrypoint: ["pnpm", "run", "start:dev"] + volumes: + - ./backend:/app + - ./backend/logs:/app/backend/logs + ports: + - 3000:3000 + env_file: .env From 2fd83bfe3bc7bde6edb851ec0b8423b00b76985a Mon Sep 17 00:00:00 2001 From: scarf Date: Tue, 8 Oct 2024 21:34:39 +0900 Subject: [PATCH 2/4] =?UTF-8?q?docs:=20`.env`=20=EC=98=88=EC=A0=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 8 ++++++++ .gitignore | 3 +++ 2 files changed, 11 insertions(+) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..d7f1b25 --- /dev/null +++ b/.env.example @@ -0,0 +1,8 @@ +# 42seoul_club_42jiphyeonjeon_dev 캔버스 참고: +# https://42born2code.slack.com/canvas/C03BAMF3727 + +MYSQL_DATABASE=jip_serv +MYSQL_USER=saseo +MYSQL_PASSWORD= +MYSQL_ROOT_PASSWORD= +MYSQL_HOST="127.0.0.1" diff --git a/.gitignore b/.gitignore index 2079630..9f15018 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ ### Node ### node_modules/ + +.env* +!.env.example From 4bab39473737a6c43a40cf0408fd62c90bfec088 Mon Sep 17 00:00:00 2001 From: scarf Date: Tue, 8 Oct 2024 21:35:17 +0900 Subject: [PATCH 3/4] =?UTF-8?q?build:=20compose=20=EB=82=B4=EC=97=90?= =?UTF-8?q?=EC=84=9C=20DB=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 컨테이너간에는 컨테이너명으로 DB에 접근해야 함, 참고: https://old.reddit.com/r/docker/comments/jsshgu/help_nodjs_mysql_dockercompose_connect/gc1ktqr/ --- compose-dev.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compose-dev.yml b/compose-dev.yml index 6447e92..c36a787 100644 --- a/compose-dev.yml +++ b/compose-dev.yml @@ -24,4 +24,6 @@ services: - ./backend/logs:/app/backend/logs ports: - 3000:3000 + environment: + - MYSQL_HOST=database env_file: .env From 9ea516b46cf533e4cd88d85c3e2757240109b3ac Mon Sep 17 00:00:00 2001 From: scarf Date: Tue, 8 Oct 2024 21:40:16 +0900 Subject: [PATCH 4/4] =?UTF-8?q?docs:=20docker=20compose=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EB=B2=95=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++- package.json | 2 +- swagger.webp | Bin 0 -> 20334 bytes 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 swagger.webp diff --git a/README.md b/README.md index 8a0d584..10b44dc 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,66 @@ 6차 개발팀은 nestjs 로 새로 작성하기로 했습니다 -## 개발용 compose 실행 방법 +## 개발 환경 설정 + +### 환경 변수 + +[.env.example](./.env.example)의 내용을 참고하여 루트 디렉토리에 `.env` 파일을 생성합니다. + +### 백엔드 + +```sh +$ brew install corepack +$ corepack enable +``` + +[corepack](https://github.com/nodejs/corepack?tab=readme-ov-file#how-to-install)으로 pnpm을 설치합니다. + +> [!NOTE] +> mac OS 환경에서는 `corepack` 패키지가 `yarn`과 `pnpm` 패키지와 충돌이 있을 수 있습니다. +> 이 경우 두 패키지를 모두 삭제하고 `corepack`을 설치해야 합니다. + +```sh +$ pnpm install +``` + +프로젝트 의존성을 설치합니다. + +### DB ```sh $ docker compose -f compose-dev.yml up --remove-orphans +# (다른 터미널에서) +$ docker compose -f compose-dev.yml exec database /bin/sh +# mysql -h 127.0.0.1 -P 3306 -u root -p +mysql> use jip_serv; +mysql> source /내려받은/DB/덤프/파일/경로.sql; ``` + +초기 실행 시 [DB 덤프 파일](https://discord.com/channels/1277878039090565139/1277878039593619468/1278599701532377088)을 사용해 [데이터베이스를 초기화해야 합니다.](https://stackoverflow.com/questions/17666249/how-to-import-an-sql-file-using-the-command-line-in-mysql) + +``` +mysql> show databases; ++--------------------+ +| Database | ++--------------------+ +| information_schema | +| jip_serv | +| performance_schema | ++--------------------+ +3 rows in set (0.01 sec) +``` + +다음과 같이 데이터베이스가 생성되어 있는지 확인합니다. + +### docker compose 실행 + +```sh +$ pnpm dev +``` + +위 명령어로 개발용 docker compose를 실행합니다. + +![](./swagger.webp) + + 경로에 접근하여 API 명세가 올바르게 표시되는지 확인합니다. diff --git a/package.json b/package.json index b08d846..605553f 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "6차 개발팀은 nestjs 로 새로 작성하기로 했습니다", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "dev": "docker compose -f compose-dev.yml up --remove-orphans" }, "keywords": [], "author": "", diff --git a/swagger.webp b/swagger.webp new file mode 100644 index 0000000000000000000000000000000000000000..36fe263c068ba463e0c2802b33bcd7a99147562d GIT binary patch literal 20334 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 literal 0 HcmV?d00001