
NestJS 프로젝트의 개발 환경을 구축해보자
Docker를 사용하여 데이터베이스를 독립적으로 관리하고, TypeORM을 통해 애플리케이션과 데이터베이스를 안전하게 연결하자
개발 환경을 담을 그릇인 Docker를 설치
https://www.docker.com/products/docker-desktop/
위의 사이트에서 도커를 설치해주고
Docker Desktop을 실행한다
Finish 버튼 누르고 회원가입하면 우선 기본 설치는 완료이다
터미널에서
docker -v
아래 명령어를 실행하여 버전이 잘 출력되는지 확인

docker-compose를 사용하여 우리 프로젝트만을 위한 독립된 데이터베이스 환경을 설계하자
프로젝트 최상위 폴더에 docker-compose.yml 작성
Docker에게 이런 사양의 MySQL 데이터베이스를 만들어줘 라고 지시하는 설계도 기능이다.
비밀번호는 .env 파일로 관리하자. docker-compose.yml에 비밀번호를 직접 적는 대신, .env 파일을 이용해 민감한 정보를 안전하게 관리합시다... 최상위 폴더에 .env 파일을 만들고, 이 파일은 반드시 .gitignore에 추가해서 Git 저장소에 올라가지 않도록 하자
DB_ROOT_PASSWORD=your_root_password DB_USER=your_db_user DB_PASSWORD=your_db_password루트 계정 비밀번호와 사용할 계정과 그 계정의 비밀번호를 정해서 설정해준다
# docker-compose.yml
version: '3.8'
services:
# 이 서비스의 별명입니다 (예: mysql_db)
mysql_db:
# Docker Hub에 있는 공식 mysql 8.0 버전을 사용
image: mysql:8.0
# 컨테이너가 예기치 않게 종료되면 항상 다시 시작
restart: always
# .env 파일의 변수를 사용하여 환경 변수 설정
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: 'mydatabase' # NestJS 프로젝트에서 사용할 DB 이름
MYSQL_USER: ${DB_USER} # NestJS 프로젝트에서 사용할 계정 이름
MYSQL_PASSWORD: ${DB_PASSWORD} # 해당 계정의 비밀번호
# 포트 설정
# 내 컴퓨터의 3306 포트와 컨테이너의 3306 포트를 연결
ports:
- '3306:3306'
# 데이터베이스 데이터를 저장할 공간 설정
# 컨테이너를 삭제해도 데이터는 보존됩니다
# 내 컴퓨터의 ./db_data 폴더와 MySQL 컨테이너 내부의 /var/lib/mysql 폴더를 실시간으로 동기화해라
volumes:
- ./db_data:/var/lib/mysql
volumes: - ./db_data:/var/lib/mysql설정 이유
- 데이터 영속성 (Persistence) docker-compose down으로 컨테이너를 삭제했다가 나중에 다시 docker-compose up으로 실행해도, db_data 폴더에 데이터가 그대로 남아있기 때문에 기존에 작업했던 내용이 모두 복구된다.
- 데이터 직접 확인 및 백업 컨테이너 내부에 들어가지 않고도 내 컴퓨터에서 실제 데이터 파일들을 직접 확인할 수 있다. 데이터베이스 전체를 백업하고 싶을 때 이 db_data 폴더를 복사하는 것만으로도 간단하게 처리할 수 있음.
- .gitignore에 추가하여 Git 저장소에 올라가지 않도록 관리
docker-compose.yml 파일이 있는 그 폴더에서 터미널을 열고 아래 명령어를 실행하면, Docker는 이 설계도를 읽어 이미지를 자동으로 다운로드하고 컨테이너를 생성하여 실행한다.
docker compose up -d
혹은
docker compose up -d mysql_db


새로운 프로젝트마다 별도의 docker-compose.yml을 만들고, 그 프로젝트만을 위한 완전히 독립된 새 컨테이너를 생성하는 것임!
Docker 컨테이너는 완벽하게 격리된 독립적인 환경.
만약 여러 프로젝트를 동시에 실행하려면, 포트가 겹치지 않도록 docker-compose.yml에서 포트 번호를 각각 다르게 설정해야 한다. (예: ports: - '3307:3306')
- 프로젝트 독립성: A 프로젝트의 DB를 망가뜨려도 B 프로젝트에는 아무런 영향이 없다.
- 버전 충돌 방지: A 프로젝트는 MySQL 8.0, B 프로젝트는 PostgreSQL 14를 쓰는 등, 프로젝트마다 다른 DB나 다른 버전을 충돌 없이 사용할 수 있다.
- 쉬운 협업: 새로운 팀원은 프로젝트를 내려받고 docker-compose up 명령어 하나만 실행하면 복잡한 DB 설치 과정 없이 즉시 개발을 시작할 수 있다.
이제 NestJS 애플리케이션이 Docker로 실행된 데이터베이스와 통신할 수 있도록 TypeORM을 설정하자
TypeORM은 ORM(Object-Relational Mapper)으로, TypeScript의 객체(Object) 와 MySQL 같은 관계형 데이터베이스의 테이블(Relation) 을 연결해주는 번역가 역할을 한다. TypeORM을 사용하면 복잡한 SQL 쿼리를 직접 작성하지 않고, 익숙한 TypeScript 코드로 데이터베이스를 안전하고 쉽게 다룰 수 있다.
NestJS 프로젝트 폴더로 이동하여 TypeORM 관련 패키지들을 설치하자
npm install @nestjs/typeorm typeorm mysql2
보안을 위해 NestJS 애플리케이션의 DB 연결 정보 또한 .env 파일을 통해 관리하자.
NestJS 프로젝트 폴더 내에 .env 파일을 생성하고 아래 내용을 작성.
docker-compose.yml에서 사용했던 정보와 동일하게 변수를 작성.
NestJS 프로젝트 폴더의 .gitignore에도 .env를 꼭 추가하자!
DB_HOST=localhost
DB_PORT=3306
DB_USERNAME=<docker-compose.yml와 맞춰주기>
DB_PASSWORD=<docker-compose.yml와 맞춰주기>
DB_DATABASE=<docker-compose.yml와 맞춰주기>
@nestjs/config 공식 패키지를 사용하여 .env 파일의 값을 읽어오고, 이 값을 TypeOrmModule에 전달하여 데이터베이스 연결을 설정하자
npm install @nestjs/config
// app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
// ConfigModule과 ConfigService를 import
import { ConfigModule, ConfigService } from '@nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [
// ConfigModule을 가장 먼저 임포트
ConfigModule.forRoot({
isGlobal: true, // 다른 모듈에서도 ConfigService를 사용할 수 있게 설정
}),
// TypeOrmModule을 비동기 방식(forRootAsync)으로 설정
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
// // useFactory에서 동적으로 설정을 생성
useFactory: (configService: ConfigService) => ({
type: 'mysql',
// configService.get('변수명')으로 .env 파일의 값을 가져옴
host: configService.get('DB_HOST'),
port: parseInt(configService.get('DB_PORT', '3306')),
username: configService.get('DB_USERNAME'),
password: configService.get('DB_PASSWORD'),
database: configService.get('DB_DATABASE'),
// 추후 엔티티(테이블) 클래스들을 여기에 등록
entities: [],
// synchronize: true는 개발 환경에서만 사용!
// 코드를 기반으로 DB 스키마를 자동으로 동기화해준다
// 프로덕션 환경에서는 데이터 손실 위험이 있어 false로 두고 마이그레이션을 사용해야 한다.
synchronize: true,
}),
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
모든 설정이 끝났다!
이 구조를 통해 안전하고 확장 가능하며, 협업하기 좋은 NestJS 개발 환경을 구축했다.
MySQLWorkbrench에서 Docker에 띄워진 MySQL을 연결해 본자
우선 Workbrench에서 MySQL Connections 옆의 플러스 버튼을 눌러 새로운 연결을 시도한다.

Test Connection 버튼을 눌렀을때 아래처럼 Seuccessfully made~ 라고 나오면 잘 접속된 것이다!

그럼 이제 OK 버튼 눌러서 연결을 생성하면 이렇게 새로운 연결이 Workbench에 생성된다.

해당 연결에 들어가면 연결에 사용된 MySQL의 계정 권한에 따라 DB를 조회, 수정을 할 수 있다. 나는 아직 아무 테이블도 만들지 않아서 비어있음.

MySQL Workbench 에서 ERD 작성하고
Forward engineering을 통해 데이터베이스 생성 쿼리문을 생성하고
실행하여 테이블을 넣어보자
File > New Model 클릭 후 Add Diagram 선택.

아래의 mydb가 사용할 스키마(데이터베이스) 이름인데, 더블클릭하여 변경할 수도 있다.

1:N 관계를 표현하는 선을 그을 때 먼저 클릭하는 테이블이 N이 되고, 나중에 누르는 테이블이 1이 된다.
다 그렸으면 File > Export > Forward Engineer 을 클릭하여 sql 스크립트를 생성하자

Output SQL Script File을 통해 sql문을 저장할 위치를 선택할 수 있음.
SQL Options는 처음 두 개만 선택해주었다. 각자 읽고 필요한 부분 선택하면 될듯
Continue 클릭

테이블 추출할거고
Continue 클릭

그럼 이렇게 sql script가 생성된다~
Finish 누르면 아까 지정한 위치에 스크립트가 저장됨

데이터베이스 이름을 아까 모델 생성하는 단계에서 바꾸지 않았다면(mydb) docker-compose.yml에서 설정한 이름과 일치시켜주자
MySQL Workbench가 생성한 스크립트는 기본적으로 mydb라는 스키마(데이터베이스)를 사용하도록 되어 있다. NestJS 프로젝트와 Docker 설정은 다른 데이터베이스를 사용하도록 되어 있다면 이 둘을 맞춰줘야함
간단하게 스크립트 열어서 Cmd + F 로 찾아서 replace All 해주면 된다ㅎ
그럼 이제 진짜 스크립트를 실행해보자
Docker 데이터베이스에 연결
데이터베이스나 테이블을 생성하는 초기 설정(DDL) 은 모든 권한을 가진 root 계정으로 하는 것이 일반적이다. 따로 생성한 계정은 NestJS 애플리케이션이 데이터를 읽고 쓰는(DML) 용도로 사용하는 것이 좋다.
스크립트 파일 실행
결과 확인
SQL 파일 저장
터미널에서 명령어 실행
cat ./init.sql | docker exec -i <컨테이너_이름> mysql -u root -p<root_비밀번호> <데이터베이스 이름>
지금처럼 SQL 스크립트로 테이블을 직접 만들었다면, TypeORM의
synchronize: true옵션은 개발 중 엔티티가 변경될 때 스키마를 자동으로 맞춰주는 보조적인 역할로 계속 유용하게 사용할 수 있다.