diff --git a/.github/workflows/cd.yaml b/.github/workflows/cd.yaml new file mode 100644 index 00000000..f80edfa8 --- /dev/null +++ b/.github/workflows/cd.yaml @@ -0,0 +1,51 @@ +name: CD +on: + push: + branches: + - main + - develop + pull_request: + branches: + - develop + +jobs: + build: + runs-on: ubuntu-latest + steps: + + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up JDK 21 + uses: actions/setup-java@v3 + with: + java-version: 21 + distribution: temurin + + - name: Get CurrentTime + uses: 1466587594/get-current-time@v2 + id: current-time + with: + format: YYYY-MM-DDTHH-mm-ss + utcOffset: "+09:00" + + - run: chmod +x gradlew && ./gradlew build + + - name: 도커 이미지 빌드 & 푸시 by jib + run: | + ./gradlew :pic-api:jib -Prelease + env: + DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} + + - name: Beanstalk Deploy + uses: einaregilsson/beanstalk-deploy@v21 + with: + aws_access_key: ${{ secrets.AWS_BEANSTALK_ACCESS_KEY }} + aws_secret_key: ${{ secrets.AWS_BEANSTALK_SECRET_KEY }} + application_name: pic-backend-eb-app + environment_name: pic-backend-eb-app-env + version_label: pic-deploy-${{steps.current-time.outputs.formattedTime}} + region: ap-northeast-2 + deployment_package: ./deploy/Dockerrun.aws.json + wait_for_deployment: false diff --git a/build.gradle.kts b/build.gradle.kts index 4e108616..99e54fd5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,9 +1,10 @@ plugins { kotlin("jvm") version "1.9.24" - kotlin("plugin.spring") version "1.9.24" - kotlin("plugin.jpa") version "1.9.24" - id("org.springframework.boot") version "3.3.0" - id("io.spring.dependency-management") version "1.1.5" + kotlin("plugin.spring") version "1.9.24" apply false + kotlin("plugin.jpa") version "1.9.24" apply false + id("org.springframework.boot") version "3.3.0" apply false + id("io.spring.dependency-management") version "1.1.5" apply false + id("com.google.cloud.tools.jib") version "3.4.3" apply false } java.sourceCompatibility = JavaVersion.VERSION_21 @@ -41,15 +42,11 @@ subprojects { } } - tasks.bootJar { + tasks.getByName("bootJar") { enabled = false } - tasks.jar { + tasks.getByName("jar") { enabled = true } } - -tasks.bootJar { - enabled = false -} diff --git a/deploy/Dockerrun.aws.json b/deploy/Dockerrun.aws.json new file mode 100644 index 00000000..d1c620bf --- /dev/null +++ b/deploy/Dockerrun.aws.json @@ -0,0 +1,13 @@ +{ + "AWSEBDockerrunVersion": "1", + "Image": { + "Name": "gappangzip/pic-api:latest", + "Update": "true" + }, + "Ports": [ + { + "ContainerPort": 8080, + "HostPort": 5000 + } + ] +} diff --git a/gradle.properties b/gradle.properties index fc6ae899..f3383bdd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,4 @@ jjwtVersion=0.11.5 mysqlConnectorVersion=8.0.33 +### Jib version for containerization +jibVersion=3.3.2 diff --git a/pic-api/build.gradle.kts b/pic-api/build.gradle.kts index cde50150..eeee8d87 100644 --- a/pic-api/build.gradle.kts +++ b/pic-api/build.gradle.kts @@ -1,3 +1,5 @@ +import com.google.cloud.tools.jib.gradle.JibExtension + tasks.bootJar { enabled = true } @@ -6,6 +8,8 @@ tasks.jar { enabled = false } +apply(plugin = "com.google.cloud.tools.jib") + val jjwtVersion: String by project.extra dependencies { @@ -29,3 +33,46 @@ dependencies { developmentOnly("org.springframework.boot:spring-boot-devtools") testImplementation("org.springframework.boot:spring-boot-starter-test") } + +configure { + val registryUsername = System.getenv("DOCKERHUB_USERNAME") + val (activeProfile, containerImageName) = getProfileAndImageName(registryUsername) + + from { + image = "eclipse-temurin:21-jre" + } + + to { + image = containerImageName + tags = setOf("$version", "latest") + auth { + username = registryUsername + password = System.getenv("DOCKERHUB_PASSWORD") + } + } + + container { + // TODO: 서버 스펙에 따라 Xmx/Xms, Initial/Min/MaxRAMFraction 설정 + jvmFlags = listOf( + "-server", + "-XX:+UseContainerSupport", + "-XX:+UseStringDeduplication", + "-Dserver.port=8080", + "-Dfile.encoding=UTF-8", + "-Djava.awt.headless=true", + "-Dspring.profiles.active=${activeProfile}" + ) + ports = listOf("8080") + environment = mapOf( + "TZ" to "Asia/Seoul" + ) + } +} + +fun getProfileAndImageName(registryUsername: String?): Array { + val containerImageName = "${registryUsername}/${project.name}" + if (project.hasProperty("release")) { + return arrayOf("release", containerImageName) + } + return arrayOf("dev", "$containerImageName-dev") +}