Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#129 chore: 깃헙액션을 통한 EC2 배포 #130

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Continuous Deploy with GitHub Actions + S3 & EC2

on:
push:
branches:
- feature/*
pull_request:
branches:
- main
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 }}
DEFAULT_POST_IMG_URL: ${{ secrets.DEFAULT_POST_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
echo "NEXT_PUBLIC_DEFAULT_POST_IMG=$DEFAULT_POST_IMG_URL" >> .env

- name: Install Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: npm ci

- name: Build Next App
run: |
npm run build
env:
CI: false

- name: Zip Build File
run: zip -qq -r ./ONEHOUR.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 ./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=ONEHOUR.zip
18 changes: 18 additions & 0 deletions appspec.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version: 0.0
os: linux

files:
- source: /
destination: /home/ubuntu/deploy
overwrite: yes
file_exists_behavior: OVERWRITE
permissions:
- object: /home/ubuntu/deploy
owner: root
group: root
mode: 755
hooks:
AfterInstall:
- location: ./deploy.sh
timeout: 1000
runas: root
18 changes: 6 additions & 12 deletions components/navigator/Navigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,7 @@ const Navigator = (props: { children: ReactNode }) => {
onClick={() => {
router.push("/dashboard");
}}
className={styles.logoWrapper}
>
className={styles.logoWrapper}>
<Image src={logo} height={35} alt="logoImage"></Image>
</div>
<hr className={styles.breakline}></hr>
Expand All @@ -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}`}>
<p>
{pathname?.includes("challenges")
? "LET’S GO !"
: "START CHALLENGE"}
</p>
<IoIosCheckmarkCircle
className={styles.challengeIcon}
></IoIosCheckmarkCircle>
className={styles.challengeIcon}></IoIosCheckmarkCircle>
</div>
<hr className={styles.breakline}></hr>
<div className={styles.menuWrapper}>
Expand All @@ -133,8 +129,7 @@ const Navigator = (props: { children: ReactNode }) => {
href={menu.path}
className={`${styles.menuList} ${
menu.path === pathname && styles.selected
}`}
>
}`}>
{menu.icon}
<div className={styles.menuText}>{menu.name}</div>
</Link>
Expand All @@ -150,8 +145,7 @@ const Navigator = (props: { children: ReactNode }) => {
key={index}
onClick={() => {
if (menu === "로그아웃") onLogout();
}}
>
}}>
<div>{menu}</div>
</div>
))}
Expand Down
9 changes: 9 additions & 0 deletions deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
REPOSITORY=/home/ubuntu/deploy

cd $REPOSITORY

sudo npm install

pm2 kill

sudo npm run deploy
18 changes: 18 additions & 0 deletions ecosystem.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
apps: [
{
name: "ONEHOUR", // 앱의 이름
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: "2G", // 2GB 이상 메모리 사용 시 재시작
env_prodection: {
NODE_ENV: "production", // Node.js 환경 설정
},
},
],
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
4 changes: 2 additions & 2 deletions pages/api/challengers.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion pages/api/image-upload.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
Expand Down
Loading