Skip to content

Commit cc87ca3

Browse files
authored
CD 파이프라인 구축 (#9)
* feat: cd 파이프라인 구축 * feat: jib 적용 및 docker-compose 배포 세팅 * feat: 서버 내 docker 디렉토리 생성 * feat: 배포 * feat: 배포 * feat: 배포 * feat: 임시 배포 브랜치 제거
1 parent 01f0098 commit cc87ca3

File tree

7 files changed

+207
-1
lines changed

7 files changed

+207
-1
lines changed

.github/workflows/cd.yml

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
name: Backend CD
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
jobs:
9+
build-and-push:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- name: Checkout
13+
uses: actions/checkout@v4
14+
15+
- name: Set up JDK 21
16+
uses: actions/setup-java@v4
17+
with:
18+
java-version: "21"
19+
distribution: "temurin"
20+
21+
- name: Gradle Caching
22+
uses: actions/cache@v3
23+
with:
24+
path: |
25+
~/.gradle/caches
26+
~/.gradle/wrapper
27+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
28+
restore-keys: |
29+
${{ runner.os }}-gradle-
30+
31+
- name: Build and Push with Jib (API)
32+
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
33+
with:
34+
arguments: clean :tuk-api:jib -Djib.to.image=${{ secrets.NCP_CONTAINER_REGISTRY_API }}/tuk-api -Djib.to.tags=${{ github.sha }} -Djib.to.auth.username=${{ secrets.NCP_ACCESS_KEY }} -Djib.to.auth.password=${{ secrets.NCP_SECRET_KEY }}
35+
env:
36+
JIB_TO_IMAGE: ${{ secrets.NCP_CONTAINER_REGISTRY_API }}/tuk-api
37+
JIB_TO_TAGS: ${{ github.sha }}
38+
JIB_TO_AUTH_USERNAME: ${{ secrets.NCP_ACCESS_KEY }}
39+
JIB_TO_AUTH_PASSWORD: ${{ secrets.NCP_SECRET_KEY }}
40+
41+
- name: Create directory and copy docker files to server
42+
run: |
43+
sshpass -p ${{ secrets.API_SERVER_PASSWORD }} ssh -p ${{ secrets.SSH_PORT }} -o StrictHostKeyChecking=no ${{ secrets.API_SERVER_USERNAME }}@${{ secrets.API_SERVER_HOST }} "mkdir -p ${{ secrets.DOCKER_COMPOSE_PATH }}"
44+
sshpass -p ${{ secrets.API_SERVER_PASSWORD }} scp -P ${{ secrets.SSH_PORT }} -o StrictHostKeyChecking=no ./docker/docker-compose.prod.yml ${{ secrets.API_SERVER_USERNAME }}@${{ secrets.API_SERVER_HOST }}:${{ secrets.DOCKER_COMPOSE_PATH }}/docker-compose.yml
45+
sshpass -p ${{ secrets.API_SERVER_PASSWORD }} scp -P ${{ secrets.SSH_PORT }} -o StrictHostKeyChecking=no ./docker/init.sql ${{ secrets.API_SERVER_USERNAME }}@${{ secrets.API_SERVER_HOST }}:${{ secrets.DOCKER_COMPOSE_PATH }}/
46+
shell: bash
47+
48+
deploy-to-server:
49+
name: Connect api server ssh and pull from container registry
50+
needs: build-and-push
51+
runs-on: ubuntu-latest
52+
steps:
53+
## docker compose up
54+
- name: Deploy to api server
55+
uses: appleboy/ssh-action@master
56+
with:
57+
host: ${{ secrets.API_SERVER_HOST }}
58+
port: ${{ secrets.SSH_PORT }}
59+
username: ${{ secrets.API_SERVER_USERNAME }}
60+
password: ${{ secrets.API_SERVER_PASSWORD }}
61+
script: |
62+
cd ${{ secrets.DOCKER_COMPOSE_PATH }}
63+
sudo docker rm -f $(sudo docker ps -qa) 2>/dev/null || true
64+
65+
# Login to NCP Container Registry
66+
echo "${{ secrets.NCP_SECRET_KEY }}" | sudo docker login ${{ secrets.NCP_CONTAINER_REGISTRY_API }} -u ${{ secrets.NCP_ACCESS_KEY }} --password-stdin
67+
68+
# Run with environment variables
69+
sudo env \
70+
MYSQL_USERNAME='${{ secrets.MYSQL_USERNAME }}' \
71+
MYSQL_PASSWORD='${{ secrets.MYSQL_PASSWORD }}' \
72+
MYSQL_ROOT_PASSWORD='${{ secrets.MYSQL_PASSWORD }}' \
73+
APPLE_CLIENT_ID='${{ secrets.APPLE_CLIENT_ID }}' \
74+
GOOGLE_CLIENT_ID='${{ secrets.GOOGLE_CLIENT_ID }}' \
75+
GOOGLE_CLIENT_SECRET='${{ secrets.GOOGLE_CLIENT_SECRET }}' \
76+
NCP_CONTAINER_REGISTRY_API='${{ secrets.NCP_CONTAINER_REGISTRY_API }}' \
77+
JWT_SECRET='${{ secrets.JWT_SECRET }}' \
78+
IMAGE_TAG='${{ github.sha }}' \
79+
docker-compose up -d
80+
81+
sudo docker image prune -f

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ plugins {
44
kotlin("plugin.jpa") version "1.9.25" apply false
55
id("org.springframework.boot") version "3.5.3" apply false
66
id("io.spring.dependency-management") version "1.1.7" apply false
7+
id("com.google.cloud.tools.jib") version "3.4.0" apply false
78
}
89

910
java {

docker/docker-compose.prod.yml

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
services:
2+
api:
3+
container_name: tuk-api
4+
image: ${NCP_CONTAINER_REGISTRY_API}/tuk-api:${IMAGE_TAG}
5+
restart: always
6+
ports:
7+
- "8080:8080"
8+
environment:
9+
SPRING_PROFILES_ACTIVE: prod
10+
MYSQL_USERNAME: ${MYSQL_USERNAME}
11+
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
12+
MYSQL_HOST: mysql
13+
MYSQL_PORT: 3306
14+
JWT_SECRET: ${JWT_SECRET}
15+
REDIS_HOST: redis
16+
REDIS_PORT: 6379
17+
APPLE_CLIENT_ID: ${APPLE_CLIENT_ID}
18+
GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID}
19+
GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET}
20+
depends_on:
21+
- mysql
22+
- redis
23+
networks:
24+
- tuk-network
25+
mysql:
26+
image: mysql:8.0.39
27+
container_name: tuk-mysql
28+
restart: always
29+
environment:
30+
MYSQL_ROOT_PASSWORD: ${MYSQL_PASSWORD}
31+
MYSQL_DATABASE: tuk_db
32+
MYSQL_USER: ${MYSQL_USERNAME}
33+
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
34+
ports:
35+
- "3306:3306"
36+
volumes:
37+
- mysql_data:/var/lib/mysql
38+
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
39+
command:
40+
- --character-set-server=utf8mb4
41+
- --collation-server=utf8mb4_unicode_ci
42+
- --skip-character-set-client-handshake
43+
networks:
44+
- tuk-network
45+
46+
redis:
47+
image: redis:7.2-alpine
48+
container_name: tuk-redis
49+
restart: always
50+
ports:
51+
- "6379:6379"
52+
volumes:
53+
- redis_data:/data
54+
command: redis-server --appendonly yes
55+
networks:
56+
- tuk-network
57+
58+
volumes:
59+
mysql_data:
60+
driver: local
61+
redis_data:
62+
driver: local
63+
64+
networks:
65+
tuk-network:
66+
driver: bridge

docker/init.sql

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
CREATE DATABASE IF NOT EXISTS tuk_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
2+
3+
CREATE TABLE IF NOT EXISTS member
4+
(
5+
id BIGINT AUTO_INCREMENT PRIMARY KEY,
6+
name VARCHAR(255),
7+
email VARCHAR(255) NOT NULL,
8+
social_type VARCHAR(50) NOT NULL,
9+
social_id VARCHAR(255) NOT NULL,
10+
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
11+
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
12+
deleted_at TIMESTAMP NULL,
13+
14+
UNIQUE KEY uk_social_user (social_type, social_id),
15+
INDEX idx_email (email),
16+
INDEX idx_deleted_at (deleted_at)
17+
);

tuk-api/build.gradle.kts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,34 @@
1+
plugins {
2+
id("com.google.cloud.tools.jib")
3+
}
4+
5+
jib {
6+
from {
7+
image = "eclipse-temurin:21-jre"
8+
}
9+
to {
10+
image = System.getProperty("jib.to.image") ?: System.getenv("JIB_TO_IMAGE") ?: "tuk-api"
11+
tags = setOf(
12+
System.getProperty("jib.to.tags") ?: System.getenv("JIB_TO_TAGS") ?: "latest"
13+
)
14+
auth {
15+
username = System.getProperty("jib.to.auth.username") ?: System.getenv("JIB_TO_AUTH_USERNAME")
16+
password = System.getProperty("jib.to.auth.password") ?: System.getenv("JIB_TO_AUTH_PASSWORD")
17+
}
18+
}
19+
container {
20+
ports = listOf("8080")
21+
mainClass = "nexters.tuk.TukApplicationKt"
22+
jvmFlags = listOf(
23+
"-XX:InitialRAMPercentage=25.0",
24+
"-XX:MinRAMPercentage=25.0",
25+
"-XX:MaxRAMPercentage=50.0",
26+
"-XX:+UseG1GC",
27+
"-Dspring.profiles.active=prod"
28+
)
29+
}
30+
}
31+
132
dependencies {
233
implementation("org.springframework.boot:spring-boot-starter-web")
334
implementation("org.springframework.boot:spring-boot-starter-actuator")
@@ -21,7 +52,7 @@ dependencies {
2152
implementation("io.jsonwebtoken:jjwt-jackson:${properties["jjwtVersion"]}")
2253

2354
implementation("com.nimbusds:nimbus-jose-jwt:${properties["nimbusJwtVersion"]}")
24-
55+
2556
// test
2657
testImplementation("org.springframework.boot:spring-boot-starter-test")
2758
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
@@ -41,4 +72,8 @@ dependencies {
4172
tasks.withType<Test> {
4273
useJUnitPlatform()
4374
systemProperty("spring.profiles.active", "test")
75+
}
76+
77+
tasks.withType<Jar> {
78+
archiveBaseName.set("tuk-api")
4479
}

tuk-api/src/main/kotlin/nexters/tuk/domain/member/Member.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
package nexters.tuk.domain.member
22

33
import jakarta.persistence.Entity
4+
import jakarta.persistence.EnumType
5+
import jakarta.persistence.Enumerated
46
import jakarta.persistence.Table
57
import nexters.tuk.application.member.SocialType
68
import nexters.tuk.application.member.dto.request.MemberCommand
79
import nexters.tuk.domain.BaseEntity
810

11+
/**
12+
* FIXME: member 임시 테이블
13+
*/
914
@Entity
1015
@Table(name = "member")
1116
class Member private constructor(
1217
val name: String?,
1318
val email: String,
19+
@Enumerated(EnumType.STRING)
1420
val socialType: SocialType,
1521
val socialId: String,
1622
) : BaseEntity() {

0 commit comments

Comments
 (0)