Skip to content

Commit

Permalink
Merge pull request #25 from sopt-makers/develop
Browse files Browse the repository at this point in the history
[Feat]: 공홈 v2 스프링부트 리팩토링 서버 프로덕션 배포 & 공홈 어드민
  • Loading branch information
Lim-Changi authored Jan 21, 2025
2 parents 7ae5633 + 435df92 commit 365c148
Show file tree
Hide file tree
Showing 225 changed files with 8,140 additions and 2 deletions.
30 changes: 30 additions & 0 deletions .github/ISSUE_TEMPLATE/issue-템플릿.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
name: Issue 템플릿
about: 이슈 템플릿 ver 1.0
title: ''
labels: ''
assignees: ''

---

<!---
❗️ 이슈 제목은 아래의 형식을 맞춰주세요
- `[Feat]` : 기능 추가 구현
- `[Fix]` : 코드 수정, 버그/오류 해결
- `[Performance]` : 개선할 성능 이슈
- `[Docs]` : README 등의 문서 수정
- `[Deploy]` : 배포 관련
- `[Refactor]` : 코드 리팩토링(기능 변경 없이 코드만 수정할 때)
- `[Test]`: 테스트 추가/수정
- `[Hotfix]` : 급한 핫픽스
-->

## ✨ 이슈 내용

-

## ✅ 체크리스트

- [ ] Assignees / Labels 선택
- [ ]
- [ ]
13 changes: 13 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
### 관련 이슈가 있다면 적어주세요.

## 📌 개발 이유

## 💻 수정 사항

## 🧪 테스트 방법

## ⛳️ 고민한 점 || 궁굼한 점

## 🎯 리뷰 포인트

## 📁 레퍼런스
49 changes: 49 additions & 0 deletions .github/workflows/cd.develop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Develop deploy workflow

on:
workflow_dispatch:
push:
branches:
- 'develop'

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2

- 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_KEY }}
aws-region: ${{ secrets.AWS_REGION }}

- name: Push Image to AWS ECR Public Repo
id: ecr-image-push
run: |
aws ecr-public get-login-password --region ${{ secrets.AWS_PUBLIC_REPO_REGION }} | docker login --username AWS --password-stdin public.ecr.aws/${{ secrets.AWS_ACCOUNT_ID }}
docker build -t ${{ secrets.DEV_ECR_REPO }}:latest .
docker tag ${{ secrets.DEV_ECR_REPO }}:latest public.ecr.aws/${{ secrets.AWS_ACCOUNT_ID }}/${{ secrets.DEV_ECR_REPO }}:latest
docker push public.ecr.aws/${{ secrets.AWS_ACCOUNT_ID }}/${{ secrets.DEV_ECR_REPO }}:latest
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: ssh command deploy
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ubuntu
key: ${{ secrets.PEM_KEY }}
script: |
sudo docker stop spring-dev-server
sudo docker rm spring-dev-server
sudo docker rm -f $(docker ps -qa)
sudo docker image prune -a -f
sudo docker pull public.ecr.aws/${{ secrets.AWS_ACCOUNT_ID }}/${{ secrets.DEV_ECR_REPO }}:latest
sudo docker run --name spring-dev-server --env-file .env -d -p 8080:8080 -t public.ecr.aws/${{ secrets.AWS_ACCOUNT_ID }}/${{ secrets.DEV_ECR_REPO }}:latest
49 changes: 49 additions & 0 deletions .github/workflows/cd.production.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: production deploy workflow

on:
workflow_dispatch:
push:
branches:
- 'main'

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2

- 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_KEY }}
aws-region: ${{ secrets.AWS_REGION }}

- name: Push Image to AWS ECR Public Repo
id: ecr-image-push
run: |
aws ecr-public get-login-password --region ${{ secrets.AWS_PUBLIC_REPO_REGION }} | docker login --username AWS --password-stdin public.ecr.aws/${{ secrets.AWS_ACCOUNT_ID }}
docker build -t ${{ secrets.PROD_ECR_REPO }}:latest .
docker tag ${{ secrets.PROD_ECR_REPO }}:latest public.ecr.aws/${{ secrets.AWS_ACCOUNT_ID }}/${{ secrets.PROD_ECR_REPO }}:latest
docker push public.ecr.aws/${{ secrets.AWS_ACCOUNT_ID }}/${{ secrets.PROD_ECR_REPO }}:latest
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: ssh command deploy
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.PROD_HOST }}
username: ubuntu
key: ${{ secrets.PEM_KEY }}
script: |
sudo docker stop spring-prod-server
sudo docker rm spring-prod-server
sudo docker rm -f $(docker ps -qa)
sudo docker image prune -a -f
sudo docker pull public.ecr.aws/${{ secrets.AWS_ACCOUNT_ID }}/${{ secrets.PROD_ECR_REPO }}:latest
sudo docker run --name spring-prod-server --env-file .env -d -p 8080:8080 -t public.ecr.aws/${{ secrets.AWS_ACCOUNT_ID }}/${{ secrets.PROD_ECR_REPO }}:latest
48 changes: 48 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,51 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*

# IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

HELP.md
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
logs

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/


### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/

### VS Code ###
.vscode/

### config yml ###
.env

### Some additional ignores
*.DS_Store


### Application Properties ###
src/main/resources/application.yml

23 changes: 23 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
FROM openjdk:17-jdk-slim AS build
WORKDIR /app
COPY . /app
RUN apt-get update && apt-get install -y curl unzip
RUN ./gradlew build

FROM openjdk:17-jdk-slim AS production
WORKDIR /app

# Install Chrome and dependencies
RUN apt-get update && apt-get install -y \
chromium \
chromium-driver \
xvfb \
&& rm -rf /var/lib/apt/lists/*

# Set Chrome environment variables
ENV CHROME_BIN=/usr/bin/chromium
ENV CHROMEDRIVER_BIN=/usr/bin/chromedriver

COPY --from=build /app/build/libs/*.jar app.jar

ENTRYPOINT ["java","-jar","/app/app.jar"]
61 changes: 59 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,59 @@
# sopt.org-backend-spring
Sopt 공식홈페이지 서버 - Spring Boot
# README

## Description
- Sopt Official Spring Boot 공홈 API 서버 입니다.
- Package Manager는 ```Gradle``` 을 사용합니다.
- 기본적으로, 모든 연결된 API 앞에 /v2 가 붙습니다. ```servlet context-path```
- 프로젝트 내부적에서 routing 추가 X

## INDEX
1. [Getting Started](#Getting-started)
2. [Project Structure](#Project Structure)
3. [Deploy_Pipeline](#Deploy-Pipeline)

# Getting-started
### 서버 실행 환경
- JDK 17
- Spring Boot 3.2.3
### 서버 환경 변수
- application-env.yml 에서 로컬에 있는 .env 값을 읽어와서 세팅합니다.
> env 환경 변수는 담당자에게 공유 받으세요.
### OpenAPI
> /v2/api-docs
# Project Structure

아키텍처는 다음과 같이 형성되어있습니다.
## Architecture
![Sopt_Official_diagram drawio](https://github.com/user-attachments/assets/16103a1c-61c7-4d19-9e81-709aa9e29fc7)

- 인스턴스는 EC2 내부에서 동작합니다.
- EC2 내부에 Docker container가 존재합니다.
- NestJS 의 경우, 3000:3000으로 포워딩 및 / route 에 매핑되어 있습니다.
- Spring Boot 의 경우, 8080:8080으로 포워딩 및 /v2 route 에 매핑되어 있습니다.
- > Production 레벨의 경우 아직 Spring Boot 셋팅은 완료되지 않았습니다.
- Docker image는 AWS Public ECR 에서 관리하고 있고, 인수인계 시 AWS 계정에 PublicECR 관련 IAM Role 을 부여받아야 합니다.

Dev, Prod 모두 동일한 구조를 형성하고 있고, 리소스 차이밖에 없습니다.

## Deploy-Pipeline
- deploy pipeline은 github action을 이용하여 구성되어있습니다.
- github action은 ```./github/workflows``` 에서 확인할 수 있습니다.
- workflow 파일은 총 3가지가 있고, 각각 다음과 같은 역할을 합니다.
1. ```cd.develop.yml``` : develop 브랜치에 푸시(또는 머지)가 되었을때마다 수행합니다. develop 서버에 배포가 됩니다.
- ```cd.***.yml``` workflow는 다음과 같은 동작을 합니다.
1. docker image를 빌드합니다.
2. docker image를 ECR 에 push합니다.
3. EC2에 ssh로 접속하여 ECR 에서 이미지를 pull합니다.
4. EC2에서 실행중인 container 를 종료합니다.
5. spring-server docker container 를 실행합니다.
> GitAction 관련 Secret은, GitHub 관리자에게 문의하여 Owner권한을 획득 후, Repository secret에서 설정하시기 바랍니다. 자세한 설명은 별도로 공유드린 문서에서 확인 하실 수 있습니다.







93 changes: 93 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.3'
id 'io.spring.dependency-management' version '1.1.4'
}

group = 'sopt.org'
version = '0.0.1-SNAPSHOT'

java {
sourceCompatibility = '17'
}

test {
systemProperty 'spring.profiles.active', 'dev'
}

ext {
set('springCloudVersion', "2023.0.1")
}

def queryDslVersion = "5.1.0"

repositories {
mavenCentral()
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation "org.springframework.boot:spring-boot-starter-data-jpa"
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-cache'

implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:4.1.1'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'

// swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'

// lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor "org.projectlombok:lombok-mapstruct-binding:0.2.0"
testCompileOnly "org.projectlombok:lombok"
testAnnotationProcessor 'org.projectlombok:lombok'

// QueryDsl
implementation "com.querydsl:querydsl-jpa:${queryDslVersion}:jakarta"
annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}:jakarta"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"

// AWS S3
implementation 'software.amazon.awssdk:s3:2.25.27'

// JWT
implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.3'

// Caffeine cache
implementation 'com.github.ben-manes.caffeine:caffeine'

// Jsoup for HTML parsing
implementation 'org.jsoup:jsoup:1.15.4'

// Selenium
implementation 'org.seleniumhq.selenium:selenium-java:4.8.1'
implementation 'org.seleniumhq.selenium:selenium-chrome-driver:4.8.1'
implementation 'io.github.bonigarcia:webdrivermanager:5.3.2'

runtimeOnly 'com.h2database:h2'
runtimeOnly 'org.postgresql:postgresql'
}

dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}

tasks.named('test') {
useJUnitPlatform()
}

def querydslDir = "$buildDir/generated/querydsl"

sourceSets {
main.java.srcDir querydslDir
}
Binary file added gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
Loading

0 comments on commit 365c148

Please sign in to comment.