diff --git a/.github/workflows/developDeploy.yml b/.github/workflows/developDeploy.yml new file mode 100644 index 0000000..e60bc4a --- /dev/null +++ b/.github/workflows/developDeploy.yml @@ -0,0 +1,82 @@ +name: Server Development Server CI&CD Work Flow +on: + push: + branches: + - dev + +jobs: + devlop_CICD: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [16.13.2] # 개발환경과 동일하게 맞춤 + + steps: + # 브랜치에 checkout해 코드를 가져온다 + - name: Checkout source code. + uses: actions/checkout@v2 + + # node 설치 및 버전 확인한다. + - name: Node.js ${{ matrix.node-version }} install + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Check Npm -v + run: npm -v + + # npm ci를 통해 npm install 진행 + - name: Npm CI + run: npm ci + + #lint 통과 확인 + - name: Check ESLint + run: npm run lint + + # .env 파일 생성 + - name: Create .env file + run: | + touch .env + echo PORT=${{ secrets.PORT }} >> .env + + echo DB_DEV_HOST=${{ secrets.DB_DEV_HOST }} >> .env + echo DB_DEV_USER=${{ secrets.DB_DEV_USER }} >> .env + echo DB_DEV_PASSWORD=${{ secrets.DB_DEV_PASSWORD }} >> .env + echo DB_DEV_NAME=${{ secrets.DB_DEV_NAME }} >> .env + echo DB_PORT=${{ secrets.DB_PORT }} >> .env + + echo WISHBOARD_GMAIL_ID=${{ secrets.WISHBOARD_GMAIL_ID }} >> .env + echo WISHBOARD_GMAIL_PW=${{ secrets.WISHBOARD_GMAIL_PW }} >> .env + + echo JWT_SECRET_KEY=${{ secrets.JWT_SECRET_KEY }} >> .env + + echo SLACK_API_TOKEN=${{ secrets.SLACK_API_TOKEN }} >> .env + + echo AWS_ACCESS_KEY=${{ secrets.AWS_S3_IMAGE_ACCESS_KEY }} >> .env + echo AWS_SECRET_KEY=${{ secrets.AWS_S3_IMAGE_SECRET_KEY }} >> .env + echo BUCKET_NAME=${{ secrets.AWS_S3_IMAGE_BUCKET_NAME }} >> .env + + # 빌드하여 S3에 업로드 + - name: Run build (dev) + run: | + npm run build --if-present + + # S3에 빌드 파일 저장 + - name: zip file + run: zip -r wishboard-dev.zip ./dist ./scripts ./appspec.yml + + - name: AWS configure credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_DEPLOY_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_DEPLOY_SECRET_ACCESS_KEY }} + aws-region: ap-northeast-2 + + - name: upload to S3 + run: aws s3 cp --region ap-northeast-2 ./wishboard-dev.zip s3://wishboard-dev-build/deploy/ + + - name: deploy with AWS codeDeploy + run: aws deploy create-deployment + --application-name wishboard-dev-codedeploy + --deployment-config-name CodeDeployDefault.OneAtATime + --deployment-group-name GROUP + --s3-location bucket=wishboard-dev-build,bundleType=zip,key=deploy/wishboard-dev.zip diff --git a/.github/workflows/prCheck.yml b/.github/workflows/prCheck.yml new file mode 100644 index 0000000..dd6de88 --- /dev/null +++ b/.github/workflows/prCheck.yml @@ -0,0 +1,62 @@ +name: Server PR Check Work Flow +on: + pull_request: + branches: + - main + - dev + +jobs: + PR_Check: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [16.13.2] # 개발환경과 동일하게 맞춤 + + steps: + # 브랜치에 checkout해 코드를 가져온다 + - name: Checkout source code. + uses: actions/checkout@v2 + + # node 설치 및 버전 확인한다. + - name: Node.js ${{ matrix.node-version }} install + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Check Npm -v + run: npm -v + + # npm ci를 통해 npm install 진행 + - name: Npm CI + run: npm ci + + #lint 통과 확인 + - name: Check ESLint + run: npm run lint + + # .env 파일 생성 + - name: Create .env file + run: | + touch .env + echo PORT=${{ secrets.PORT }} >> .env + + echo DB_HOST=${{ secrets.DB_DEV_HOST }} >> .env + echo DB_USER=${{ secrets.DB_DEV_USER }} >> .env + echo DB_PASSWORD=${{ secrets.DB_DEV_PASSWORD }} >> .env + echo DB_NAME=${{ secrets.DB_DEV_NAME }} >> .env + echo DB_PORT=${{ secrets.DB_PORT }} >> .env + + echo WISHBOARD_GMAIL_ID=${{ secrets.WISHBOARD_GMAIL_ID }} >> .env + echo WISHBOARD_GMAIL_PW=${{ secrets.WISHBOARD_GMAIL_PW }} >> .env + + echo JWT_SECRET_KEY=${{ secrets.JWT_SECRET_KEY }} >> .env + + echo SLACK_API_TOKEN=${{ secrets.SLACK_API_TOKEN }} >> .env + + echo AWS_ACCESS_KEY=${{ secrets.AWS_S3_IMAGE_ACCESS_KEY }} >> .env + echo AWS_SECRET_KEY=${{ secrets.AWS_S3_IMAGE_SECRET_KEY }} >> .env + echo BUCKET_NAME=${{ secrets.AWS_S3_IMAGE_BUCKET_NAME }} >> .env + + - name: Run build + run: | + echo NODE_ENV="development" >> .env + npm run build --if-present diff --git a/.github/workflows/serverCICD.yml b/.github/workflows/productDeploy.yml similarity index 50% rename from .github/workflows/serverCICD.yml rename to .github/workflows/productDeploy.yml index 640ec9e..96a8f64 100644 --- a/.github/workflows/serverCICD.yml +++ b/.github/workflows/productDeploy.yml @@ -1,18 +1,11 @@ -# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions - -name: ServerCICD +name: Server Production Server CI&CD Work Flow on: push: - branches: - - dev - pull_request: branches: - main - - dev jobs: - CICD: + prod_CICD: runs-on: ubuntu-latest strategy: matrix: @@ -49,6 +42,7 @@ jobs: echo DB_USER=${{ secrets.DB_USER }} >> .env echo DB_PASSWORD=${{ secrets.DB_PASSWORD }} >> .env echo DB_NAME=${{ secrets.DB_NAME }} >> .env + echo DB_PORT=${{ secrets.DB_PORT }} >> .env echo WISHBOARD_GMAIL_ID=${{ secrets.WISHBOARD_GMAIL_ID }} >> .env echo WISHBOARD_GMAIL_PW=${{ secrets.WISHBOARD_GMAIL_PW }} >> .env @@ -61,21 +55,17 @@ jobs: echo AWS_SECRET_KEY=${{ secrets.AWS_S3_IMAGE_SECRET_KEY }} >> .env echo BUCKET_NAME=${{ secrets.AWS_S3_IMAGE_BUCKET_NAME }} >> .env - # main 브랜치에 대한 PR만 빌드하여 S3에 업로드 + # 빌드하여 S3에 업로드 - name: Run build (main) - if: ${{ github.base_ref == 'main' }} run: | - echo NODE_ENV="production" >> .env npm run build:production --if-present - name: Copy ecosystem.config.js - if: ${{ github.base_ref == 'main' }} run: | cp ./ecosystem.config.js ./dist - # aws s3에 빌드 파일 저장 + # S3에 빌드 파일 저장 - name: Build file upload to S3 and PM2 script - if: ${{ github.base_ref == 'main' }} env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} @@ -84,41 +74,3 @@ jobs: --recursive \ --region ap-northeast-2 \ dist s3://wishboard-server-build - - #** artifact 저장 기한을 정했지만 요금 제한으로 job간 이동 없이 바로 업로드 하도록 코드 수정 - # deploy: - # needs: build - # if: ${{ github.base_ref == 'main' }} - # runs-on: ubuntu-latest - # steps: - # # build job에서 빌드한 파일(./dist/server.js) 가져오기 - # - name: Sharing files between jobs. - # uses: actions/download-artifact@v3 - # with: - # name: dist - # # aws s3에 빌드 파일 저장 - # # ** 파일 이름이 동일해서 알아서 덮임 - # - name : Build file upload to S3 and PM2 script - # env: - # AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - # AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - # run: | - # mkdir dist - # mv ecosystem.config.js server.js server.js.LICENSE.txt ./dist - # ls -al - # aws s3 cp \ - # --recursive \ - # --region ap-northeast-2 \ - # dist s3://wishboard-server-build - # ** time out 문제로 우선 주석처리 후 직접 진행으로 변경 - # # aws ec2에 접속 - # - name : Connect and Build file download to EC2 and PM2 script - # uses: appleboy/ssh-action@master - # with: - # key: ${{ secrets.AWS_EC2_SSH_KEY }} - # host: ${{ secrets.AWS_HOST }} - # username: ${{ secrets.AWS_USRENAME }} - # script: | - # pwd - # cd ./wishboard-server-product - # ./pm2-deploy.sh diff --git a/appspec.yml b/appspec.yml new file mode 100644 index 0000000..ef08deb --- /dev/null +++ b/appspec.yml @@ -0,0 +1,18 @@ +version: 0.0 +os: linux +files: + - source: / + destination: /home/ubuntu/build + overwrite: yes + +permissions: + - object: /home/ubuntu + pattern: '**' + owner: ubuntu + group: ubuntu + +hooks: + AfterInstall: + - location: scripts/after-deploy.sh + timeout: 300 + runas: ubuntu diff --git a/package-lock.json b/package-lock.json index c1b03cf..b2f6a2f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2322,9 +2322,9 @@ } }, "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -3556,12 +3556,12 @@ } }, "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dev": true, "dependencies": { - "is-core-module": "^2.8.1", + "is-core-module": "^2.9.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -4045,15 +4045,6 @@ "source-map": "^0.6.0" } }, - "node_modules/terser/node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", @@ -6301,9 +6292,9 @@ "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" }, "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", "dev": true, "requires": { "has": "^1.0.3" @@ -7231,12 +7222,12 @@ "dev": true }, "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dev": true, "requires": { - "is-core-module": "^2.8.1", + "is-core-module": "^2.9.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } @@ -7554,14 +7545,6 @@ "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } } } diff --git a/package.json b/package.json index 38ff90a..f17bc6f 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "main": "app.js", "scripts": { "lint": "eslint .", - "build": "webpack --config ./webpack.config.js --mode development", - "build:production": "webpack --config ./webpack.config.js --mode production", + "build": "webpack --config ./webpack.config.js --mode=development", + "build:production": "webpack --config ./webpack.prod.config.js --mode=production", "start": "node dist/server.js" }, "repository": { diff --git a/scripts/after-deploy.sh b/scripts/after-deploy.sh new file mode 100644 index 0000000..3aa4240 --- /dev/null +++ b/scripts/after-deploy.sh @@ -0,0 +1,10 @@ +#!/bin/bash +REPOSITORY=/home/ubuntu/build + +cd $REPOSITORY + +cd dist + +sudo /usr/bin/pm2 del server + +sudo /usr/bin/pm2 start server.js diff --git a/src/config/db.js b/src/config/db.js index 165cecb..ea4e558 100644 --- a/src/config/db.js +++ b/src/config/db.js @@ -12,21 +12,35 @@ const TAG_PROTOCOL_CONNECTION_LOST = 'Database connection was closed.'; const TAG_ER_CON_COUNT_ERROR = 'Database has too many connections.'; const TAG_ECONNREFUSED = 'Database connection was refused.'; -const pool = mysql.createPool({ - host: process.env.DB_HOST, - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, - port: process.env.DB_PORT, - database: process.env.DB_NAME, - connectionLimit: 50, -}); +let pool; +if (process.env.NODE_ENV === 'development') { + logger.info('connect dev database'); + pool = mysql.createPool({ + host: process.env.DB_DEV_HOST, + user: process.env.DB_DEV_USER, + password: process.env.DB_DEV_PASSWORD, + port: process.env.DB_PORT, + database: process.env.DB_DEV_NAME, + connectionLimit: 50, + }); +} else { + logger.info('connect product database'); + pool = mysql.createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + port: process.env.DB_PORT, + database: process.env.DB_NAME, + connectionLimit: 50, + }); +} logger.info(TAG_SUCCESS); // eslint-disable-next-line valid-jsdoc /** * TODO refactoring - * TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received undefined + * TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be of type string or an instance of , , or Array or an Array-like Object. Received undefined **/ const generateSQL = async (str, args) => { console.log(typeof str); diff --git a/src/middleware/handleError.js b/src/middleware/handleError.js index b26898b..d420a9e 100644 --- a/src/middleware/handleError.js +++ b/src/middleware/handleError.js @@ -6,7 +6,11 @@ const multer = require('multer'); const { ErrorMessage } = require('../utils/response'); const handleErrors = (err, req, res, next) => { - logger.error(err); + if (process.env.NODE_ENV === 'production') { + logger.error(err); + } else { + logger.error(err.stack); + } //* multer 에러 확인용 log if (err instanceof multer.MulterError) { diff --git a/webpack.config.js b/webpack.config.js index 5e8038f..284472f 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -7,7 +7,6 @@ dotenv.config({ }); module.exports = { - mode: process.env.NODE_ENV, target: 'node', entry: './src/app.js', output: { @@ -16,16 +15,14 @@ module.exports = { }, plugins: [ new webpack.DefinePlugin({ - 'process.env.NODE_ENV': - process.env.NODE_ENV === 'development' - ? JSON.stringify('development') - : JSON.stringify('production'), 'process.env.PORT': JSON.stringify(process.env.PORT), - 'process.env.DB_HOST': JSON.stringify(process.env.DB_HOST), - 'process.env.DB_USER': JSON.stringify(process.env.DB_USER), - 'process.env.DB_PASSWORD': JSON.stringify(process.env.DB_PASSWORD), + 'process.env.DB_DEV_HOST': JSON.stringify(process.env.DB_DEV_HOST), + 'process.env.DB_DEV_USER': JSON.stringify(process.env.DB_DEV_USER), + 'process.env.DB_DEV_PASSWORD': JSON.stringify( + process.env.DB_DEV_PASSWORD, + ), 'process.env.DB_PORT': JSON.stringify(process.env.DB_PORT), - 'process.env.DB_NAME': JSON.stringify(process.env.DB_NAME), + 'process.env.DB_DEV_NAME': JSON.stringify(process.env.DB_DEV_NAME), 'process.env.JWT_SECRET_KEY': JSON.stringify(process.env.JWT_SECRET_KEY), 'process.env.WISHBOARD_GMAIL_ID': JSON.stringify( process.env.WISHBOARD_GMAIL_ID, diff --git a/webpack.prod.config.js b/webpack.prod.config.js new file mode 100644 index 0000000..9d627ee --- /dev/null +++ b/webpack.prod.config.js @@ -0,0 +1,39 @@ +const path = require('path'); +const webpack = require('webpack'); +const dotenv = require('dotenv'); + +dotenv.config({ + path: './.env', +}); + +module.exports = { + target: 'node', + entry: './src/app.js', + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'server.js', + }, + plugins: [ + new webpack.DefinePlugin({ + 'process.env.PORT': JSON.stringify(process.env.PORT), + 'process.env.DB_HOST': JSON.stringify(process.env.DB_HOST), + 'process.env.DB_USER': JSON.stringify(process.env.DB_USER), + 'process.env.DB_PASSWORD': JSON.stringify(process.env.DB_PASSWORD), + 'process.env.DB_PORT': JSON.stringify(process.env.DB_PORT), + 'process.env.DB_NAME': JSON.stringify(process.env.DB_NAME), + 'process.env.JWT_SECRET_KEY': JSON.stringify(process.env.JWT_SECRET_KEY), + 'process.env.WISHBOARD_GMAIL_ID': JSON.stringify( + process.env.WISHBOARD_GMAIL_ID, + ), + 'process.env.WISHBOARD_GMAIL_PW': JSON.stringify( + process.env.WISHBOARD_GMAIL_PW, + ), + 'process.env.AWS_ACCESS_KEY': JSON.stringify(process.env.AWS_ACCESS_KEY), + 'process.env.AWS_SECRET_KEY': JSON.stringify(process.env.AWS_SECRET_KEY), + 'process.env.BUCKET_NAME': JSON.stringify(process.env.BUCKET_NAME), + }), + ], + stats: { + errorDetails: true, + }, +};