From 0d99630759ac6647acc5ccd5b836f80eb6c9d0cb Mon Sep 17 00:00:00 2001 From: Dropper-in Date: Sun, 19 Nov 2023 18:13:37 +0900 Subject: [PATCH 1/5] =?UTF-8?q?#129=20chore:=20=EA=B9=83=ED=97=99=EC=95=A1?= =?UTF-8?q?=EC=85=98=EC=9D=84=20=ED=86=B5=ED=95=9C=20EC2=20=EB=B0=B0?= =?UTF-8?q?=ED=8F=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/main.yml | 76 ++++++++++++++++++++++++++++++++++++++ appspec.yml | 17 +++++++++ deploy.sh | 5 +++ ecosystem.config.js | 17 +++++++++ package.json | 3 +- pages/api/challengers.js | 4 +- pages/api/image-upload.js | 2 +- 7 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/main.yml create mode 100644 appspec.yml create mode 100644 deploy.sh create mode 100644 ecosystem.config.js diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..fff57f9 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,76 @@ +name: Continuous Deploy with GitHub Actions + S3 & EC2 + +on: + push: + branches: + - main + - feature/* + pull_request: + branches: + - main + - feature/* +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout current commit (${{github.sha}}) + uses: actions/checkout@v3 + + - name: Set up Node + uses: actions/setup-node@v3 + with: + node-version: 20.x + + - name: Cache Dependencies + uses: actions/cache@v3 + id: cache + with: + # node_modules 폴더 검사 + path: node_modules + # 아래 키값으로 cache가 되있는지 확인 + key: npm-packages-${{ hashFiles('**/package-lock.json') }}\ + + - name: Generate Environment Variables File + env: + SECRET_KEY: ${{ secrets.SECRET_KEY }} + MONGODB_URL: ${{ secrets.MONGODB_URL }} + MY_AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }} + MY_AWS_SECRET_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_IMAGE_BUCKET: ${{ secrets.AWS_IMAGE_BUCKET }} + DEFAULT_PROFILE_IMG_URL: ${{ secrets.DEFAULT_PROFILE_IMG_URL }} + run: | + echo "SECRET_KEY: $SECRET_KEY" >> .env + echo "MONGODB_URL=$MONGODB_URL" >> .env + echo "MY_AWS_ACCESS_KEY=$MY_AWS_ACCESS_KEY" >> .env + echo "MY_AWS_SECRET_KEY=$MY_AWS_SECRET_KEY" >> .env + echo "DEFAULT_PROFILE_IMG_URL=$DEFAULT_PROFILE_IMG_URL" >> .env + + - name: Install Dependencies + if: steps.cache.outputs.cache-hit != 'true' + run: npm ci + + - name: Build Next App + run: | + npm run build + + - name: Zip Build File + run: zip -qq -r ./$GITHUB_SHA.zip . -x "node_modules/*" + shell: bash + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Upload to S3 + run: | + aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://${{ secrets.AWS_S3_BUCKET }}/$GITHUB_SHA.zip + + - name: Code Deploy # S3에 올라간 zip 파일을 CodeDeploy로 가져옴 + run: aws deploy create-deployment + --application-name ${{ secrets.CodeDeploy_APPLICATION }} + --deployment-config-name CodeDeployDefault.AllAtOnce # CodeDeploy에서 설정한 배포 설정 + --deployment-group-name ONEHOUR + --s3-location bucket=${{ secrets.AWS_S3_BUCKET }},bundleType=zip,key=$GITHUB_SHA.zip # Code Deploy가 S3에서 프로젝트를 찾을 수 있도록 경로 지정. \ No newline at end of file diff --git a/appspec.yml b/appspec.yml new file mode 100644 index 0000000..0e43f72 --- /dev/null +++ b/appspec.yml @@ -0,0 +1,17 @@ +version: 0.0 +os: linux # Ubuntu니까 linux로 설정. + +files: + - source: / + destination: /home/ubuntu/deploy # EC2 인스턴스 안에 프로젝트를 저장할 경로. + overwrite: yes +permissions: # EC2 인스턴스에 프로젝트를 저장하기 위한 권한 설정. + - object: /home/ubuntu/deploy # EC2 인스턴스 안에 프로젝트를 저장할 경로. + owner: ubuntu + group: ubuntu + mode: 755 +hooks: + AfterInstall: # 배포 완료 후 실행할 동작 설정. + - location: ./deploy.sh # deploy.sh를 실행. + timeout: 60 # 제한 시간 1000초 으로 설정. 1000초가 넘어가면 실패함. + runas: ubuntu # ubuntu 권한으로 실행. diff --git a/deploy.sh b/deploy.sh new file mode 100644 index 0000000..be9b30a --- /dev/null +++ b/deploy.sh @@ -0,0 +1,5 @@ +REPOSITORY=/home/ubuntu/deploy + +cd $REPOSITORY + +npm run deploy \ No newline at end of file diff --git a/ecosystem.config.js b/ecosystem.config.js new file mode 100644 index 0000000..daa550b --- /dev/null +++ b/ecosystem.config.js @@ -0,0 +1,17 @@ +module.exports = { + apps: [ + { + name: "ONEHOUR", // 앱의 이름 + script: "./node_modules/next/dist/bin/next", // Next.js 스크립트 경로 + args: "start", // Next.js 앱을 시작할 때 사용할 인수 + exec_mode: "cluster", // 실행 모드: cluster 또는 fork 중 선택 + instances: "2", // 클러스터 모드에서 실행할 인스턴스 수 (CPU 코어 수만큼) + autorestart: true, // 프로세스 자동 재시작 활성화 + watch: true, // 파일 변경 감지 활성화 (개발 중에만 활용) + max_memory_restart: "1G", // 1GB 이상 메모리 사용 시 재시작 + env: { + NODE_ENV: "production", // Node.js 환경 설정 + }, + }, + ], +}; diff --git a/package.json b/package.json index 1eb0d94..a58fc24 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "deploy": "pm2 start ecosystem.config.js --env production" }, "dependencies": { "@redux-devtools/extension": "^3.2.5", diff --git a/pages/api/challengers.js b/pages/api/challengers.js index 73429e1..6f073a0 100644 --- a/pages/api/challengers.js +++ b/pages/api/challengers.js @@ -27,7 +27,7 @@ export default async function handler(req, res) { } } else if (req.method === "POST") { try { - let { postTitle, postContent, postImgUrl, ...posts } = req.body; + let { postTitle, postContent, postImgUrl } = req.body; // 1. 헤더에 있는 엑세스토큰을 디코드하여 현재 로그인 중인 유저 ID를 얻음 let atHeader = req.headers["authorization"]; let acToken = atHeader.substr(7); @@ -55,7 +55,7 @@ export default async function handler(req, res) { // 4. 그 유저 필드의 이메일과 닉네임 + 게시글 제목과 본문 내용 + 날짜 정보를 newPost 변수에 객체로 저장 // default post img 로 변경해야함 - let defaultImgUrl = `https://${process.env.MY_AWS_BUCKET_NAME}.s3.ap-northeast-2.amazonaws.com/default-profile.jpg`; + let defaultImgUrl = process.env.DEFAULT_PROFILE_IMG_URL; if (postImgUrl === "") { postImgUrl = defaultImgUrl; diff --git a/pages/api/image-upload.js b/pages/api/image-upload.js index 0987c11..b064248 100644 --- a/pages/api/image-upload.js +++ b/pages/api/image-upload.js @@ -12,7 +12,7 @@ export default async function handler(req, res) { const s3 = new aws.S3(); const urlResponse = await s3.createPresignedPost({ // S3 버킷의 presigned Url 생성 - Bucket: process.env.MY_AWS_BUCKET_NAME, + Bucket: process.env.AWS_IMAGE_BUCKET, Fields: { key: imgType + "/" + fileName }, // 파일 저장 경로 - aws의 presigned Url을 설정할 때 사용됨 Expires: 60, // seconds Conditions: [ From dc1b03e1131f441dd0035666d7295355b7f71c41 Mon Sep 17 00:00:00 2001 From: Dropper-in Date: Mon, 27 Nov 2023 22:39:54 +0900 Subject: [PATCH 2/5] =?UTF-8?q?#129=20test:=20Github=20Action=20=EB=B0=B0?= =?UTF-8?q?=ED=8F=AC=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/main.yml | 8 ++------ components/navigator/Navigator.tsx | 18 ++++++------------ 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fff57f9..79a0cde 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -68,9 +68,5 @@ jobs: run: | aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://${{ secrets.AWS_S3_BUCKET }}/$GITHUB_SHA.zip - - name: Code Deploy # S3에 올라간 zip 파일을 CodeDeploy로 가져옴 - run: aws deploy create-deployment - --application-name ${{ secrets.CodeDeploy_APPLICATION }} - --deployment-config-name CodeDeployDefault.AllAtOnce # CodeDeploy에서 설정한 배포 설정 - --deployment-group-name ONEHOUR - --s3-location bucket=${{ secrets.AWS_S3_BUCKET }},bundleType=zip,key=$GITHUB_SHA.zip # Code Deploy가 S3에서 프로젝트를 찾을 수 있도록 경로 지정. \ No newline at end of file + - name: Code Deploy + run: aws deploy create-deployment --application-name ${{ secrets.CODEDEPLOY_APPLICATION }} --deployment-config-name CodeDeployDefault.AllAtOnce --deployment-group-name ONEHOUR --s3-location bucket=${{ secrets.AWS_S3_BUCKET }},bundleType=zip,key=$GITHUB_SHA.zip diff --git a/components/navigator/Navigator.tsx b/components/navigator/Navigator.tsx index 3fb5405..188cae0 100644 --- a/components/navigator/Navigator.tsx +++ b/components/navigator/Navigator.tsx @@ -84,8 +84,7 @@ const Navigator = (props: { children: ReactNode }) => { onClick={() => { router.push("/dashboard"); }} - className={styles.logoWrapper} - > + className={styles.logoWrapper}> logoImage
@@ -111,18 +110,15 @@ const Navigator = (props: { children: ReactNode }) => { router.push("/dashboard/challenges"); }} className={`${ - pathname?.includes("challenges") && - styles.challengeButtonSelected - } ${styles.challengeButton}`} - > + pathname?.includes("ongoing") && styles.challengeButtonSelected + } ${styles.challengeButton}`}>

{pathname?.includes("challenges") ? "LET’S GO !" : "START CHALLENGE"}

+ className={styles.challengeIcon}>
@@ -133,8 +129,7 @@ const Navigator = (props: { children: ReactNode }) => { href={menu.path} className={`${styles.menuList} ${ menu.path === pathname && styles.selected - }`} - > + }`}> {menu.icon}
{menu.name}
@@ -150,8 +145,7 @@ const Navigator = (props: { children: ReactNode }) => { key={index} onClick={() => { if (menu === "로그아웃") onLogout(); - }} - > + }}>
{menu}
))} From 46a7c2376789ff9140cd3e0d48ee97197e3fa911 Mon Sep 17 00:00:00 2001 From: Dropper-in Date: Fri, 1 Dec 2023 16:31:57 +0900 Subject: [PATCH 3/5] =?UTF-8?q?#129=20fix:=20=EC=95=A1=EC=85=98=20?= =?UTF-8?q?=EC=8B=A4=ED=96=89=20=EA=B7=9C=EC=B9=99=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/main.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 79a0cde..19fa7ce 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,12 +3,10 @@ name: Continuous Deploy with GitHub Actions + S3 & EC2 on: push: branches: - - main - feature/* pull_request: branches: - main - - feature/* jobs: build: runs-on: ubuntu-latest From 054defb1a8ef7ea8ffb03be89deec91cf04edb1d Mon Sep 17 00:00:00 2001 From: Dropper-in Date: Fri, 1 Dec 2023 19:35:47 +0900 Subject: [PATCH 4/5] =?UTF-8?q?#129=20chore:=20EC2=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A6=BD=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/main.yml | 9 ++++++--- appspec.yml | 21 +++++++++++---------- deploy.sh | 6 +++++- ecosystem.config.js | 5 +++-- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 19fa7ce..0a7e07a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,6 +36,7 @@ jobs: MY_AWS_SECRET_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} AWS_IMAGE_BUCKET: ${{ secrets.AWS_IMAGE_BUCKET }} DEFAULT_PROFILE_IMG_URL: ${{ secrets.DEFAULT_PROFILE_IMG_URL }} + run: | echo "SECRET_KEY: $SECRET_KEY" >> .env echo "MONGODB_URL=$MONGODB_URL" >> .env @@ -50,9 +51,11 @@ jobs: - name: Build Next App run: | npm run build + env: + CI: false - name: Zip Build File - run: zip -qq -r ./$GITHUB_SHA.zip . -x "node_modules/*" + run: zip -qq -r ./ONEHOUR.zip . -x "node_modules/*" shell: bash - name: Configure AWS Credentials @@ -64,7 +67,7 @@ jobs: - name: Upload to S3 run: | - aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://${{ secrets.AWS_S3_BUCKET }}/$GITHUB_SHA.zip + aws s3 cp --region ap-northeast-2 ./ONEHOUR.zip s3://${{ secrets.AWS_S3_BUCKET }}/ONEHOUR.zip - name: Code Deploy - run: aws deploy create-deployment --application-name ${{ secrets.CODEDEPLOY_APPLICATION }} --deployment-config-name CodeDeployDefault.AllAtOnce --deployment-group-name ONEHOUR --s3-location bucket=${{ secrets.AWS_S3_BUCKET }},bundleType=zip,key=$GITHUB_SHA.zip + run: aws deploy create-deployment --application-name ${{ secrets.CODEDEPLOY_APPLICATION }} --deployment-config-name CodeDeployDefault.AllAtOnce --deployment-group-name ONEHOUR --s3-location bucket=${{ secrets.AWS_S3_BUCKET }},bundleType=zip,key=ONEHOUR.zip diff --git a/appspec.yml b/appspec.yml index 0e43f72..ad31454 100644 --- a/appspec.yml +++ b/appspec.yml @@ -1,17 +1,18 @@ version: 0.0 -os: linux # Ubuntu니까 linux로 설정. +os: linux files: - source: / - destination: /home/ubuntu/deploy # EC2 인스턴스 안에 프로젝트를 저장할 경로. + destination: /home/ubuntu/deploy overwrite: yes -permissions: # EC2 인스턴스에 프로젝트를 저장하기 위한 권한 설정. - - object: /home/ubuntu/deploy # EC2 인스턴스 안에 프로젝트를 저장할 경로. - owner: ubuntu - group: ubuntu +file_exists_behavior: OVERWRITE +permissions: + - object: /home/ubuntu/deploy + owner: root + group: root mode: 755 hooks: - AfterInstall: # 배포 완료 후 실행할 동작 설정. - - location: ./deploy.sh # deploy.sh를 실행. - timeout: 60 # 제한 시간 1000초 으로 설정. 1000초가 넘어가면 실패함. - runas: ubuntu # ubuntu 권한으로 실행. + AfterInstall: + - location: ./deploy.sh + timeout: 1000 + runas: root diff --git a/deploy.sh b/deploy.sh index be9b30a..f30463f 100644 --- a/deploy.sh +++ b/deploy.sh @@ -2,4 +2,8 @@ REPOSITORY=/home/ubuntu/deploy cd $REPOSITORY -npm run deploy \ No newline at end of file +sudo npm install + +pm2 kill + +sudo npm run deploy \ No newline at end of file diff --git a/ecosystem.config.js b/ecosystem.config.js index daa550b..827b1c4 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -2,14 +2,15 @@ module.exports = { apps: [ { name: "ONEHOUR", // 앱의 이름 - script: "./node_modules/next/dist/bin/next", // Next.js 스크립트 경로 + script: "npm", // Next.js 스크립트 경로 args: "start", // Next.js 앱을 시작할 때 사용할 인수 exec_mode: "cluster", // 실행 모드: cluster 또는 fork 중 선택 instances: "2", // 클러스터 모드에서 실행할 인스턴스 수 (CPU 코어 수만큼) + interpreter: "bash", autorestart: true, // 프로세스 자동 재시작 활성화 watch: true, // 파일 변경 감지 활성화 (개발 중에만 활용) max_memory_restart: "1G", // 1GB 이상 메모리 사용 시 재시작 - env: { + env_prodection: { NODE_ENV: "production", // Node.js 환경 설정 }, }, From 28b030a6c730dfdc79055df65ebc56694207761f Mon Sep 17 00:00:00 2001 From: Dropper-in Date: Sun, 3 Dec 2023 20:02:10 +0900 Subject: [PATCH 5/5] =?UTF-8?q?#129=20chore:=20=ED=99=98=EA=B2=BD=20?= =?UTF-8?q?=EB=B3=80=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/main.yml | 2 ++ ecosystem.config.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0a7e07a..9abf4ee 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,6 +36,7 @@ jobs: MY_AWS_SECRET_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} AWS_IMAGE_BUCKET: ${{ secrets.AWS_IMAGE_BUCKET }} DEFAULT_PROFILE_IMG_URL: ${{ secrets.DEFAULT_PROFILE_IMG_URL }} + DEFAULT_POST_IMG_URL: ${{ secrets.DEFAULT_POST_IMG_URL }} run: | echo "SECRET_KEY: $SECRET_KEY" >> .env @@ -43,6 +44,7 @@ jobs: echo "MY_AWS_ACCESS_KEY=$MY_AWS_ACCESS_KEY" >> .env echo "MY_AWS_SECRET_KEY=$MY_AWS_SECRET_KEY" >> .env echo "DEFAULT_PROFILE_IMG_URL=$DEFAULT_PROFILE_IMG_URL" >> .env + echo "NEXT_PUBLIC_DEFAULT_POST_IMG=$DEFAULT_POST_IMG_URL" >> .env - name: Install Dependencies if: steps.cache.outputs.cache-hit != 'true' diff --git a/ecosystem.config.js b/ecosystem.config.js index 827b1c4..ca07b3c 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -9,7 +9,7 @@ module.exports = { interpreter: "bash", autorestart: true, // 프로세스 자동 재시작 활성화 watch: true, // 파일 변경 감지 활성화 (개발 중에만 활용) - max_memory_restart: "1G", // 1GB 이상 메모리 사용 시 재시작 + max_memory_restart: "2G", // 2GB 이상 메모리 사용 시 재시작 env_prodection: { NODE_ENV: "production", // Node.js 환경 설정 },