무스마 백엔드 살펴보기 - 개발환경 세팅부터 배포까지 (1/2)
민경환 사원
무스마 백엔드 살펴보기 - 개발환경 세팅부터 배포까지 (1/2)
글을 쓴 이유
저는 대학생 때부터 무스마에 입사하기 전까지 Java를 이용하여 주로 개발을 하였고 당연히 Java/Spring을 이용하는 회사에 입사를 할 줄 알았습니다. 감사하게도 언어는 도구일 뿐이라며 무스마 SW 개발팀에서 입사 제안을 해주셨고 작년 12월부터 Node.js 백엔드 개발자로 입사하여 재미있는 회사 생활을 하고 있습니다.
입사 이틀째에 설레는 마음으로 프로젝트를 VSCode에 불러왔을 때 정말 당황했었는데요. 자바스크립트와 Node.js 관련 지식이 전무했던 저는 수많은 파일 및 옵션들이 무엇을 의미하는지 정말 하~나도 몰랐고 개발부터 배포까지 어떻게 진행되는지 이해가 잘 가지 않았기 때문입니다.
그래서
- Typescript, Node.js에 익숙하지 않고
- 수많은 파일이 뭔지 하나도 모르겠지만
- 대충이라도 알고 싶고 실습도 좀 해보고 싶어!
하는 분들 및 앞으로 합류하실 무스마 크루의 개발자분들을 위하여 작성하게 되었습니다.
모든 코드는 GitHub에서 확인하실 수 있습니다.
개발환경 세팅
패키지 설치
NVM 설치
NVM
을 이용하면 Node.js 설치하면 다양한 버전을 설치 및 변경이 가능해집니다.
brew install nvm
mkdir ~/.nvm
vi ~/.zhrc # 아래 내용을 붙여넣는다.
export NVM_DIR="$HOME/.nvm"
[ -s "/usr/local/opt/nvm/nvm.sh" ] && . "/usr/local/opt/nvm/nvm.sh" # This loads nvm
[ -s "/usr/local/opt/nvm/etc/bash_completion.d/nvm" ] && . "/usr/local/opt/nvm/etc/bash_completion.d/nvm" # This loads nvm bash_completion
zsh compinit: insecure directories, run compaudit for list.
에러가 발생할 경우,
cd /usr/local/share/zsh
sudo chmod -R 755 ./site-functions
Node.js(LTS) 설치
nvm install 14 # LTS 버전 확인 후 입력
Yarn 설치
무스마에서는 Node Package Manager로 yarn
을 사용하고 있습니다.
그 이유는
- 패키지 다운로드 속도가 더 빠르고
- 기능이 더 많기 때문에 (workspaces 등)
npm install -g yarn
Nest CLI 설치
Nest
는 타입스크립트로 빌드되는 Node.js 서버측 애플리케이션을 구축하기 위한 프레임워크입니다.
CLI를 이용하여 빠르고 간편하게 프로젝트를 생성할 수 있으므로 설치합니다.
npm install -g @nestjs/cli
패키지 매니저로
yarn
을 쓰면서 왜npm
으로 다운로드 하냐? 라는 의문을 가지실 수 있는데요.
yarn
을 이용하여@nestjs/cli
를 글로벌로 다운로드 하면 생기는 이슈가 있습니다.
VS Code 설치
Jetbrains사의 IntelliJ
, Webstrom
등을 사용하셔도 상관 없으나 무스마에서는 VS Code
를 적극적으로 사용하고 있습니다.
brew install --cask visual-studio-code
Docker 설치
brew install --cask docker
Kubectl 설치
brew install kubectl
minikube 설치
무스마 SW 개발팀은 워크로드를 Amazon EKS에 배포합니다.
듀토리얼을 EKS
로 진행하기에는 비용적으로, 시간적으로 무리가 있으므로 쿠버네티스를 로컬에서 실행할 수 있도록 minikube
를 설치합니다.
brew install minikube
Lens 설치
쿠버네티스 클러스터를 제어하는 데 필요한 유일한 IDE입니다.
minikube
가 기본적으로 제공해주는 대시보드가 있으나 더 아름답고 사용하기 편하기에 사용하고있습니다.
brew install --cask lens
GitHub Personal access tokens 발급받기
여기를 참고하여 wrtie:packages
스코프를 선택한 뒤 Personal access tokens을 발급받습니다.
토큰은 도커 이미지 푸시, 풀을 위해 사용하는 GitHub Container Registry
와 무스마에서 생성한 eslint
를 다운받을 때 사용됩니다.
발급받은 토큰을 ~/.npmrc
에 저장합니다.
vi ~/.npmrc
//npm.pkg.github.com/:_authToken=[GITHUB_PERSONAL_ACCESS_TOKENS]
VSCode Extension 설치
Extensions: Marketplace
에서 Extension
을 설치합니다.
ESLint
Prettier - Code formatter
프로젝트 생성
개발환경 세팅이 끝났으니 본격적으로 시작해보겠습니다.
musma 프로젝트 생성
Nest CLI
를 이용하여 musma
프로젝트를 생성합니다.
package manager로
yarn
을 선택해주세요.
nest new musma
musma-eslint 적용
.npmrc 생성
프로젝트 루트에 .npmrc
파일을 생성합니다.
echo @musma:registry=https://npm.pkg.github.com/ >> .npmrc
.npmrc
파일을 생성함으로써 pakcage.json
파일의 dependency
에 @musma/eslint-config
와 같이 @musma
가 붙는 패키지가 있다면,
공식 npm 저장소 http://registry.npmjs.org/ 대신에 GitHub Package Registry https://npm.pkg.github.com/에서 찾아서 다운로드 하게 됩니다.
읽어보세요
[무스마 기술블로그] GitHub 패키지 저장소 호스팅: GitHub Package Registry 시작하기
.eslintrc.js 변경 및 .prettierrc 제거
Nest CLI
를 이용하면 ESLint를 구성할 수 있는 설정파일인 .eslintrc.js
와 코드를 정렬해주는 Code Formatter인 Prettier를 적용할 수 있는 .prettierrc
파일을 생성해주는데요.
.prettierrc
설정은 다운로드 할 @musma/eslint-config
에 들어있기 때문에 제거합니다.
rm .prettierrc
.eslintrc.js
는 아래와 같이 변경합니다.
module.exports = {
extends: [
'@musma',
],
}
@musma/eslint-config
에 적용된 세부적인 룰이 궁금하시다면 여기에서 확인하실 수 있습니다.
.eslintignore 생성
.eslintignore
파일을 생성하여 규칙 적용이 필요없는 node_modules
, *.js
, *d.ts
파일을 제외합니다.
vi .eslintignore
**/node_modules
**/*.js
**/*.d.ts
@musma/eslint-config 적용
@musma/eslint-config
를 설치합니다.
yarn add @musma/eslint-config --dev --update-checksums
필요없는 의존성 제거
아래의 의존성들은 musma/eslint-config
에 설치되어 있으므로 제거합니다.
- @typescript-eslint/eslint-plugin
- @typescript-eslint/parser
- eslint
- eslint-config-prettier
- eslint-plugin-prettier
- prettier
yarn remove @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint eslint-config-prettier eslint-plugin-prettier prettier
settings.json 생성
save 버튼을 누를 때 마다 prettier
가 적용되도록 settings.json
을 생성합니다.
mkdir .vscode
vi .vscode/settings.json
{
"eslint.codeAction.showDocumentation": {
"enable": true
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"editor.formatOnSave": true,
"eslint.alwaysShowStatus": true
}
ESLint, Prettier 테스트
접근제한자가 없으므로 app.controller.ts
파일이 오류가 나고 있을텐데요.
getHello
함수에 public
을 붙여주고 저장을 눌러서 아래와 같이 변경되면 성공입니다.
import { Controller, Get } from '@nestjs/common'
import { AppService } from './app.service'
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
public getHello(): string {
return this.appService.getHello()
}
}
Hello World! 테스트
서버를 실행시켜 Hello World!
를 정상적으로 응답하는지 테스트해보겠습니다.
yarn start
curl -XGET 'localhost:3000'
Hello World!
기능 구현
app.controller.ts
에 간단한 GET
, POST
요청을 구현해보겠습니다.
타입 생성
파라미터 및 반환값으로 사용할 타입 두 가지를 생성합니다.
type ResponseType = {
type: string
data: string
}
type PostBodyType = {
data: string
}
GET
GET
요청에 대한 getRequest 함수를 구현합니다.
@Get('/get')
public getRequest(): ResponseType {
return { type: 'GET', data: 'getResponse' }
}
POST
POST
요청에 대한 postRequest 함수를 구현합니다.
@Post('/post')
public postRequest(@Body() body: PostBodyType): ResponseType {
return { type: 'POST', data: body.data }
}
테스트
생성한 GET
, POST
요청을 테스트해보겠습니다.
yarn start
GET
curl -XGET 'localhost:3000/get'
{"type":"GET","data":"getResponse"}
POST
curl -XPOST -H "Content-type: application/json" -d '{ "data": "postResponse" }' 'localhost:3000/post'
{"type":"POST","data":"postResponse"}
바이너리 생성
무스마 개발팀에서는 Node.js 프로젝트를 도커 이미지로 생성하여 배포하고있습니다.
Node.js 프로젝트를 도커 이미지로 생성할 때는 크게 두 가지가 있는데요.
node
이미지를 사용하는 방법- 실행 파일을 만들어 리눅스 이미지에서 실행하는 방법
두 가지 방법 모두 장단점이 있지만 1번의 방법보다 2번의 방법이 배포할 때 쉽고 간편하므로 2번을 이용하고 있습니다.
이번에는 pkg
를 이용하여 Node.js 프로젝트를 하나의 바이너리로 생성하는 방법을 알아보겠습니다.
pkg 설치
pkg
를 devDependencies
에 설치합니다.
yarn add pkg --dev
엔트리 포인트 등록
pkg
를 이용하여 하나의 바이너리를 만들기 위해서는 엔트리 포인트 지정이 필요한데요.
이는 pakcage.json
의 bin
프로퍼티를 이용하여 지정이 가능합니다.
해당 내용은 pkg에서 확인하실 수 있습니다.
package.json
에 아래와 같이 bin
프로퍼티와 엔트리 포인트를 추가합니다.
{
...
"bin": "dist/main.js",
...
}
스크립트 등록
pkg
명령어를 이용하기 위한 스크립트를 생성합니다.
현재 macOS-Bigsur
환경에서 실습을 진행하고 있으므로 이에 맞춰서 패키징을 해보겠습니다.
target 옵션에 대한 자세한 내용은 여기에서 확인하실 수 있습니다.
{
"scripts": {
"build:pkg": "pkg . --target node14-macos-x64 --output dist/server",
}
바이너리 생성
등록한 스크립트를 이용하여 바이너리를 생성합니다.
yarn build:pkg
$ pkg . --target node14-macos-x64 --output dist/server
> pkg@5.3.3
> Fetching base Node.js binaries to PKG_CACHE_PATH
fetched-v14.17.6-macos-x64 [====================] 100%
✨ Done in 17.26s.
결과는 output
옵션에 적힌대로 dist
폴더에 server
라는 이름으로 생성됩니다.
ls dist
app.controller.d.ts app.service.js
app.controller.js app.service.js.map
app.controller.js.map main.d.ts
app.module.d.ts main.js
app.module.js main.js.map
app.module.js.map server
app.service.d.ts tsconfig.build.tsbuildinfo
바이너리 실행 및 테스트
생성된 바이너를 실행해보겠습니다.
dist/server
[Nest] 11971 - 2021-10-07 2:40:37 PM LOG [NestFactory] Starting Nest application...
[Nest] 11971 - 2021-10-07 2:40:37 PM LOG [InstanceLoader] AppModule dependencies initialized +14ms
[Nest] 11971 - 2021-10-07 2:40:37 PM LOG [RoutesResolver] AppController {/}: +1ms
[Nest] 11971 - 2021-10-07 2:40:37 PM LOG [RouterExplorer] Mapped {/, GET} route +1ms
[Nest] 11971 - 2021-10-07 2:40:37 PM LOG [RouterExplorer] Mapped {/get, GET} route +1ms
[Nest] 11971 - 2021-10-07 2:40:37 PM LOG [RouterExplorer] Mapped {/post, POST} route +0ms
[Nest] 11971 - 2021-10-07 2:40:37 PM LOG [NestApplication] Nest application successfully started +1ms
GET
요청을 테스트해보겠습니다.
curl -XGET 'localhost:3000/get'
{"type":"GET","data":"getResponse"}
정상적으로 작동하는 것을 확인할 수 있습니다.
정리
프로젝트를 배포하기 전 까지의 과정을 알아보았습니다.
- 패키지 설치
- 프로젝트 생성
- 기능 구현
- 바이너리 생성
이 다음 시간에는 도커 이미지 생성 ~ 프로젝트 배포까지 다루어보겠습니다.
무스마 백엔드 살펴보기 - 개발환경 세팅부터 배포까지 (2/2) 편에서 계속됩니다.