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

Actions workflow 수정 #16

Merged
merged 25 commits into from
Jan 3, 2025
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
100 changes: 75 additions & 25 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
workflows: ["Kotlin Lint Check"] # lint.yml이 끝난 후 실행
types:
- completed

jobs:
build:
runs-on: ubuntu-latest
Expand All @@ -14,45 +15,94 @@ jobs:
- name: Checkout code
uses: actions/checkout@v3

# 2. AWS 인증
- name: Log in to Amazon ECR
uses: aws-actions/amazon-ecr-login@v1
- name: Install Docker Compose
run: |
sudo apt-get update
sudo apt-get install -y docker-compose

# # 2. Docker Compose로 DB 시작
# - name: Start Database with Docker Compose
# run: |
# docker-compose up -d mysql
# working-directory: .

# 2. Gradle 빌드
- name: Build project
run: |
SPRING_PROFILES_ACTIVE=prod ./gradlew build

# 3. 빌드 결과 확인
- name: Verify build artifacts
run: ls -R build/libs

# 4. Docker 빌드 컨텍스트 준비
- name: Prepare Docker context
run: cp build/libs/*.jar .

# 5. AWS 자격 증명 설정
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v3
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-2

# 3. 도커 이미지 빌드
# 6. AWS ECR 로그인
- name: Log in to Amazon ECR
uses: aws-actions/amazon-ecr-login@v1

# 7. 도커 이미지 빌드
- name: Build Docker image
run: |
docker build -t memo-with-tags-backend:latest .
run: docker build -t memo-with-tags-backend:latest .

# 4. 도커 이미지를 ECR로 푸시
# 8. 도커 이미지를 ECR로 푸시
- name: Push Docker image to ECR
run: |
# ECR 리포지토리 URI
REPOSITORY_URI=739275468912.dkr.ecr.ap-northeast-2.amazonaws.com/memo-with-tags
TAG=$(echo $GITHUB_SHA | cut -c1-7) # 커밋 해시 앞 7자리로 태그 생성

# ECR에 태그 추가
docker tag memo-with-tags-backend:latest $REPOSITORY_URI:$TAG
echo "Pushing Docker image with TAG: $TAG"

# ECR에 푸시
docker tag memo-with-tags-backend:latest $REPOSITORY_URI:$TAG
docker push $REPOSITORY_URI:$TAG

# 5. EC2 서버에서 Docker 이미지 실행
# 9. EC2 서버에서 Docker 이미지 실행
- name: Deploy to EC2
run: |
# EC2 서버 접속
ssh -o StrictHostKeyChecking=no ubuntu@${{ secrets.EC2_PUBLIC_IP }} << 'EOF'
# ECR 로그인
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin $REPOSITORY_URI

# 기존 컨테이너 중지 및 삭제
docker stop memo-with-tags-backend || true
docker rm memo-with-tags-backend || true

# 새 컨테이너 실행
docker pull $REPOSITORY_URI:$TAG
docker run -d --name memo-with-tags-backend -p 80:80 $REPOSITORY_URI:$TAG
EOF
# 개인 키를 파일로 저장하고 권한 설정
echo "${{ secrets.EC2_SSH_PRIVATE_KEY }}" > private_key.pem
chmod 600 private_key.pem

# 배포 스크립트 작성
echo "#!/bin/bash
REPOSITORY_URI=739275468912.dkr.ecr.ap-northeast-2.amazonaws.com/memo-with-tags
TAG=$(echo $GITHUB_SHA | cut -c1-7)

echo \"Deploying Docker image with TAG: \$TAG\"
echo \"Deploying Docker image with REPOSITORY_URI: \$REPOSITORY_URI\"

aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin \$REPOSITORY_URI

docker stop memo-with-tags-backend || true
docker rm memo-with-tags-backend || true

docker pull \$REPOSITORY_URI:\$TAG
docker run -d \
-p 8080:8080 \
-e SPRING_PROFILES_ACTIVE=prod \
-e DB_NAME=memowithtags_db \
-e DB_USERNAME=${{ secrets.DB_USERNAME }} \
-e DB_PASSWORD=${{ secrets.DB_PASSWORD }} \
--name memowithtags-backend \
\$REPOSITORY_URI:\$TAG" > deploy.sh

# 배포 스크립트 EC2로 전송
scp -i private_key.pem -o StrictHostKeyChecking=no deploy.sh ubuntu@${{ secrets.EC2_PUBLIC_IP }}:/home/ubuntu/

# EC2에서 스크립트 실행
ssh -i private_key.pem -o StrictHostKeyChecking=no ubuntu@${{ secrets.EC2_PUBLIC_IP }} "bash /home/ubuntu/deploy.sh"

# - name: Stop Database
# run: |
# docker-compose down
# working-directory: .
39 changes: 33 additions & 6 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ name: Kotlin Lint Check
on:
push:
branches:
- actions
- main
- develop
pull_request:
branches:
- actions
- main
- develop

Expand All @@ -18,14 +20,39 @@ jobs:
- name: Checkout code
uses: actions/checkout@v2

# 1. Docker 및 Docker Compose 설치
- name: Install Docker Compose
run: |
sudo apt-get update
sudo apt-get install -y docker-compose

# 2. Docker Compose로 DB 시작
- name: Start Database with Docker Compose
run: |
docker-compose up -d mysql
working-directory: .

# 3. DB 준비 시간 대기
- name: Wait for Database
run: |
until nc -z localhost 3306; do
echo "Waiting for the database to be ready..."
sleep 5
done

# 4. Java 환경 설정
- name: Set up JDK
uses: actions/setup-java@v2
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'amazon-corretto'# 필요한 Java 버전 설정

- name: Install dependencies
run: ./gradlew clean build # Gradle 의존성 설치 및 빌드
distribution: 'corretto'

# 5. Gradle 의존성 설치 및 Ktlint 검사 실행
- name: Run Ktlint
run: ./gradlew ktlintCheck # Ktlint 검사 실행
run: ./gradlew ktlintCheck

# 6. Docker Compose 정리
- name: Stop Database
run: |
docker-compose down
working-directory: .
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ WORKDIR /app

# 로컬의 빌드된 JAR 파일을 컨테이너 안으로 복사
# (빌드 과정에서 JAR 파일을 생성한다고 가정)
COPY build/libs/your-app.jar /app/your-app.jar
COPY build/libs/memo-with-tags-0.0.1-SNAPSHOT.jar /app/memo-with-tags-0.0.1-SNAPSHOT.jar

# 컨테이너가 시작될 때 실행될 명령어 설정
CMD ["java", "-jar", "your-app.jar"]
CMD ["java", "-jar", "/app/memo-with-tags-0.0.1-SNAPSHOT.jar"]
57 changes: 29 additions & 28 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,51 +1,52 @@
plugins {
kotlin("jvm") version "1.9.25"
kotlin("plugin.spring") version "1.9.25"
id("org.springframework.boot") version "3.4.1"
id("io.spring.dependency-management") version "1.1.7"
kotlin("plugin.jpa") version "1.9.25"
kotlin("jvm") version "1.9.25"
kotlin("plugin.spring") version "1.9.25"
id("org.springframework.boot") version "3.4.1"
id("io.spring.dependency-management") version "1.1.7"
id("org.jlleitschuh.gradle.ktlint") version "11.5.1"
kotlin("plugin.jpa") version "1.9.25"
}

group = "com.wafflestudio.toyproject"
version = "0.0.1-SNAPSHOT"

java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}

repositories {
mavenCentral()
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("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.mindrot:jbcrypt:0.4")
implementation("com.mysql:mysql-connector-j:8.2.0")
implementation("io.jsonwebtoken:jjwt-api:0.11.5")
implementation("io.jsonwebtoken:jjwt-impl:0.11.5")
implementation("io.jsonwebtoken:jjwt-jackson:0.11.5")
implementation("org.springframework.boot:spring-boot-starter-oauth2-client")
testImplementation("org.springframework.boot:spring-boot-starter-test")
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("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.mindrot:jbcrypt:0.4")
implementation("com.mysql:mysql-connector-j:8.2.0")
implementation("io.jsonwebtoken:jjwt-api:0.11.5")
implementation("io.jsonwebtoken:jjwt-impl:0.11.5")
implementation("io.jsonwebtoken:jjwt-jackson:0.11.5")
implementation("org.springframework.boot:spring-boot-starter-oauth2-client")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}

kotlin {
compilerOptions {
freeCompilerArgs.addAll("-Xjsr305=strict")
}
compilerOptions {
freeCompilerArgs.addAll("-Xjsr305=strict")
}
}

allOpen {
annotation("jakarta.persistence.Entity")
annotation("jakarta.persistence.MappedSuperclass")
annotation("jakarta.persistence.Embeddable")
annotation("jakarta.persistence.Entity")
annotation("jakarta.persistence.MappedSuperclass")
annotation("jakarta.persistence.Embeddable")
}

tasks.withType<Test> {
useJUnitPlatform()
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.wafflestudio.toyproject.memo_with_tags
package com.wafflestudio.toyproject.memoWithTags

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
Expand All @@ -7,5 +7,5 @@ import org.springframework.boot.runApplication
class MemoWithTagsApplication

fun main(args: Array<String>) {
runApplication<MemoWithTagsApplication>(*args)
runApplication<MemoWithTagsApplication>(*args)
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
package com.wafflestudio.toyproject.memo_with_tags.memo.controller
package com.wafflestudio.toyproject.memoWithTags.memo.controller

import com.wafflestudio.toyproject.memo_with_tags.memo.service.MemoService
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestParam
import com.wafflestudio.toyproject.memoWithTags.memo.service.MemoService
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController
import java.time.Instant

@RestController
class MemoController(
private val memoService: MemoService
) {
@PostMapping("/api/v1/memo")
fun createMemo(@RequestBody request: CreateMemoRequest): MemoDto {
fun createMemo(@RequestBody request: CreateMemoResponse): MemoDto {
return MemoDto("", emptyList())
}

@PutMapping("/api/v1/memo/{memoId}")
fun updateMemo(@PathVariable memoId: Long, @RequestBody request: UpdateMemoRequest): MemoDto {
fun updateMemo(@PathVariable memoId: Long, @RequestBody request: UpdateMemoResponse): MemoDto {
return MemoDto("", emptyList())
}

@DeleteMapping("/api/v1/memo/{memoId}")
Expand All @@ -42,4 +47,4 @@ data class UpdateMemoResponse(
val tags: List<Long>,
val createdAt: Instant,
val updatedAt: Instant
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.wafflestudio.toyproject.memoWithTags.memo.persistence

class MemoEntity
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.wafflestudio.toyproject.memoWithTags.memo.service

import org.springframework.stereotype.Service

@Service
class MemoService
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.wafflestudio.toyproject.memoWithTags.tag.controller

import com.wafflestudio.toyproject.memoWithTags.tag.service.TagService
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController

@RestController
class TagController(
private val tagService: TagService
) {
@GetMapping("/api/v1/tag")
fun getTags(): List<TagDto> {
return emptyList() // 빈 리스트 반환
}

@PostMapping("/api/v1/tag")
fun createTag(@RequestBody request: CreateTagRequest): TagDto {
return TagDto(0L, "", "") // 기본값으로 TagDto 반환
}

@PutMapping("/api/v1/tag/{tagId}")
fun updateTag(@PathVariable id: Long, @RequestBody request: UpdateTagRequest): TagDto {
return TagDto(0L, "", "") // 기본값으로 TagDto 반환
}

@DeleteMapping("/api/v1/tag/{tagId}")
fun deleteTag(@PathVariable id: Long) {
// 반환 타입이 Unit이므로 아무 작업 없이 비워 둬도 OK
}
}

data class TagDto(
val id: Long,
val name: String,
val color: String
)

data class CreateTagRequest(
val name: String,
val color: String
)

data class UpdateTagRequest(
val name: String,
val color: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.wafflestudio.toyproject.memoWithTags.tag.persistence

class TagEntity
Loading
Loading