Skip to content
Merged
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
20 changes: 20 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Dependencies
node_modules

# Environment
.env
.env.test

/generated/prisma
uploads/
.dest
coverage

# sprint sub
infra
http

# Docker
Dockerfile
.dockerignore
docker-compose.yaml
2 changes: 1 addition & 1 deletion .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ AWS_S3_ACCESS_KEY_ID='access key'
AWS_S3_SECRET_KEY_ID='secret access key'

#ENV
ENV='production | develop'
NODE_ENV='production | develop'

#Using .env list
# .env
Expand Down
28 changes: 28 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: cd

on:
push:
branches:
- main

jobs:
AWS_deploy:
runs-on: ubuntu-latest
environment: AWS_Deploy
steps:
# EC2 배포
- name: Deploy to EC2
uses: appleboy/ssh-action@v1.2.2
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USER }}
key: ${{ secrets.EC2_PRIVATE_KEY }}
port: 22
script: |
cd ~/3-sprint-mission # EC2 인스턴스 내 프로젝트 경로로 진입
git pull origin main # 코드 최신화
npm install
npm run build # ts -> js
npm run prisma:migrate # Prisma 마이그레이션
pm2 restart codeit-sprint10 # 이전 스프린트10때 프로세스 이름을 codeit-sprint10으로 설정했음
echo "✅ Deployment successful!"
49 changes: 49 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: ci

on:
pull_request:
branches: [main, 천수]

jobs:
test:
runs-on: ubuntu-latest
env:
DATABASE_URL: postgresql://postgres:test_password@localhost:5432/test_db?schema=public
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

db host 도 환경변수로 처리하는 것이 안전합니다!

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기 있는 모든 민감한 정보들은 환경변수로 처리하시는게 좋을 것 같습니다.
db host, jwt_secret db_password 등

JWT_SECRET: test_secret
PORT: 3000
NODE_ENV: develop #production만 아니면 로직은 동일

services:
postgres:
image: postgres
env:
POSTGRES_PASSWORD: test_password
POSTGRES_DB: test_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432

steps:
- name: Checkout code
uses: actions/checkout@v5

- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: 22

- name: Install dependencies
run: npm ci

- name: Type Check
run: npx tsc --noEmit

- name: Prisma migrate
run: npm run prisma:migrate

- name: Run Tests
run: npm run jest:test
21 changes: 21 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# node js 환경 준비
FROM node:22.16.0

# 소스코드 다운로드
COPY . /panda-market

# 소스코드 디렉토리 이동
WORKDIR /panda-market

# 의존성 패키지 설치 (npm ci)
RUN npm ci

# 소스코드 빌드
RUN npm run build

# 환경 변수 정의
ENV PORT=3000
ENV NODE_ENV='develop'

# 서버 실행
CMD sh -c "npm run prisma:migrate && npm run start"
35 changes: 34 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,4 +308,37 @@
- 환경변수를 통해, 운영 환경이라면 multer-s3를 이용하여 운영 환경시에는 aws를 사용하도록 수정하였습니다.
- AWS 프리티어 사용이 불가하여 제출을 최대한 늦게 하였습니다.
- 요구사항 자체는 프리티어에서 사용 가능한 인스턴스 유형을 사용하였습니다
- pm2의 ecosystem.config.js는 강의 시간에 다루지 않았던 내용이라 간단하게 찾아보고 적용을 해보았습니다. 적절하지 않은 설정이 있거나 보완할 수 있는 내용이 있는지 궁금합니다.
- pm2의 ecosystem.config.js는 강의 시간에 다루지 않았던 내용이라 간단하게 찾아보고 적용을 해보았습니다. 적절하지 않은 설정이 있거나 보완할 수 있는 내용이 있는지 궁금합니다.

---
# 스프린트 미션 11

## 미션 목표

- Github Actions로 테스트, 배포 자동화
- Docker 이미지 만들기

## ✅ 요구사항

### Github Actions 활용

- [x] 브랜치에 pull request가 발생하면 테스트를 실행하는 액션을 구현해 주세요.
- [x] main 브랜치에 push가 발생하면 AWS 배포를 진행하는 액션을 구현해 주세요.
- [x] 개인 Github 리포지터리에서 Actions 동작을 확인해 보세요.

### Docker 이미지 만들기

다음을 만족하는 Dockerfile과 docker-compose.yaml을 작성해 주세요.
- [x] Express 서버를 실행하는 Dockerfile을 작성해 주세요.
- [x] Express 서버가 파일 업로드를 처리하는 폴더는 Docker의 Volume을 활용하도록 구현해 주세요.
- [x] 데이터베이스는 Postgres 이미지를 사용해 연결하도록 구현해 주세요.
- [x] 실행된 Express 서버 컨테이너는 호스트 머신에서 3000번 포트로 접근 가능하도록 구현해 주세요.

---

## 멘토에게
- CI/CD에서 사용하는 환경 변수는 github의 enviroment secret기능을 활용하여 원하는 환경에 맞게 변수를 구분하였습니다.
- CI에서 push시 테스트를 실행하는 액션에 대해 브랜치 조건이 없었기에 제 이름이 들어간 브랜치는 모두 수행되도록 작성하였습니다.
- Docker-compose.yaml에서 depend_on과 service_healthy를 추가하여 postgres가 정상적으로 동작이 확인 되었을때 백엔드 서버가 실행되도록 구현하였습니다.
- 학습을 위해 Docker-compose.yaml에서 env_file과 environment를 사용하는 방법을 구성해보았습니다. 보안을 위해서라면 env_file에 전부 넣는게 맞다는 생각이 드는데 이부분은 어떻게 생각하시는지 궁금합니다.
- CD시 docker를 활용해서 배포하는 방법이 궁금합니다. (ec2에서 docker를 설정하는 등)
50 changes: 50 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: panda-market
services:
panda-market-app:
image: seracine/panda-market-app:1.0.0
restart: always # 에러 발생시 재시작
build:
tags:
- seracine/panda-market-app:1.0.0
- seracine/panda-market-app:latest
dockerfile: Dockerfile
pull: true
context: .
container_name: panda-market-app
ports:
- "3000:3000"
networks:
- panda-network
volumes:
- panda-app-volume:/panda-market/uploads
env_file: # env 파일로 환경변수 주입
- .env
depends_on:
panda-market-postgres-db:
condition: service_healthy
panda-market-postgres-db:
image: postgres
restart: always # 에러 발생시 재시작
container_name: panda-market-postgres
volumes:
- panda-db-volume:/var/lib/postgresql/data
networks:
- panda-network
environment: # 환경변수 파라미터 직접 전달
- POSTGRES_PASSWORD=1234
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 1m30s
timeout: 30s
retries: 5
start_period: 30s

networks:
panda-network:
name: panda-network

volumes:
panda-app-volume:
name: panda-app-volume
panda-db-volume:
name: panda-db-volume
4 changes: 2 additions & 2 deletions src/services/imageUpload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import multerS3 from 'multer-s3'

let storage

if (process.env.ENV === 'production') { //배포 환경일 때는 AWS로
if (process.env.NODE_ENV === 'production') { //배포 환경일 때는 AWS로
const s3ClientParams = {
region: process.env.AWS_S3_REGION ?? '',
credentials: {
Expand Down Expand Up @@ -84,7 +84,7 @@ function uploadImage(req: Request, res: Response) { // 유효성 검사 실패
}

console.log(file)
if (process.env.ENV === 'production' && 'location' in file) { // Express.MulterS3.File 타입에 있는 location이 있는지 확인
if (process.env.NODE_ENV === 'production' && 'location' in file) { // Express.MulterS3.File 타입에 있는 location이 있는지 확인
res.json({ message: 'Finish Upload', path: file.location })
} else {
res.json({ message: 'Finish Upload', path: `/images/${file.filename}` })
Expand Down