Skip to content

Commit 280efdd

Browse files
authored
Merge pull request #2 from Leets-Official/chore/cicd
[chore] CICD 파이프라인 구축
2 parents 784141d + 81b6b80 commit 280efdd

10 files changed

Lines changed: 397 additions & 3 deletions

File tree

.github/workflows/ci-test.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: CI - Build & Test (Local Only)
2+
3+
on:
4+
push:
5+
branches: [ "develop", "main" ]
6+
pull_request:
7+
branches: [ "develop" ]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Checkout source code
15+
uses: actions/checkout@v4
16+
17+
- name: Set up JDK
18+
uses: actions/setup-java@v4
19+
with:
20+
java-version: 21
21+
distribution: temurin
22+
23+
- name: Grant execute permission for Gradle
24+
run: chmod +x gradlew
25+
26+
- name: Build project
27+
run: ./gradlew clean build -x test
28+
29+
- name: Run tests
30+
run: ./gradlew test

.github/workflows/dev-cicd.yml

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
name: CI/CD Dev
2+
3+
on:
4+
push:
5+
branches: [ "develop" ]
6+
7+
jobs:
8+
ci:
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- name: 1. Checkout source
13+
uses: actions/checkout@v4
14+
15+
- name: 2. Set up JDK
16+
uses: actions/setup-java@v4
17+
with:
18+
java-version: 21
19+
distribution: temurin
20+
21+
- name: 3. application.yml 파일 설정
22+
run: |
23+
mkdir -p src/main/resources
24+
echo "${{ secrets.APPLICATION_YML }}" > ./src/main/resources/application.yml
25+
26+
- name: 4. Gradle Wrapper 권한 부여
27+
run: chmod +x gradlew
28+
29+
- name: 5. Gradle Caching
30+
uses: actions/cache@v3
31+
with:
32+
path: |
33+
~/.gradle/caches
34+
~/.gradle/wrapper
35+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
36+
restore-keys: |
37+
${{ runner.os }}-gradle-
38+
39+
- name: 6. Build JAR
40+
run: ./gradlew clean build -x test
41+
42+
- name: 7. Docker login
43+
uses: docker/login-action@v3
44+
with:
45+
username: ${{ secrets.DOCKER_USERNAME }}
46+
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
47+
48+
- name: 8. Build & Push Docker image
49+
uses: docker/build-push-action@v5
50+
with:
51+
context: .
52+
dockerfile: Dockerfile
53+
push: true
54+
tags: ${{ secrets.DOCKER_USERNAME }}/server:latest
55+
56+
cd:
57+
needs: ci
58+
runs-on: ubuntu-latest
59+
60+
steps:
61+
- name: 1. Checkout source
62+
uses: actions/checkout@v4
63+
64+
- name: 2. Create .env file
65+
run: |
66+
echo "${{ secrets.ENV }}" > .env
67+
68+
- name: 2-1. .env 파일 EC2에 전송
69+
uses: appleboy/scp-action@master
70+
with:
71+
host: ${{ secrets.EC2_PUBLIC_IP }}
72+
username: ${{ secrets.SSH_USER }}
73+
key: ${{ secrets.EC2_PRIVATE_KEY }}
74+
source: ".env"
75+
target: "/home/ubuntu/stepbookstep-dev/docker/"
76+
77+
- name: Check docker-compose.dev.yml exists
78+
run: ls -al ./docker/
79+
80+
- name: 3. docker-compose.yml 전달
81+
uses: appleboy/scp-action@master
82+
with:
83+
host: ${{ secrets.EC2_PUBLIC_IP }}
84+
username: ${{ secrets.SSH_USER }}
85+
key: ${{ secrets.EC2_PRIVATE_KEY }}
86+
source: "./docker/docker-compose.dev.yml"
87+
target: "/home/ubuntu/stepbookstep-dev/docker/" # <= 경로 일치시킴
88+
89+
90+
- name: 4. SSH to Dev Server and Deploy
91+
uses: appleboy/ssh-action@master
92+
with:
93+
host: ${{ secrets.EC2_PUBLIC_IP }}
94+
username: ${{ secrets.SSH_USER }}
95+
key: ${{ secrets.EC2_PRIVATE_KEY }}
96+
script: |
97+
cd /home/ubuntu/stepbookstep-dev/docker/
98+
docker pull ${{ secrets.DOCKER_USERNAME }}/server:latest
99+
docker compose -f docker-compose.dev.yml down
100+
docker compose -f docker-compose.dev.yml up -d

.github/workflows/prod-cicd.yml

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
name: CI/CD Prod
2+
3+
on:
4+
push:
5+
branches: [ "main" ]
6+
7+
jobs:
8+
ci:
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- name: 1. Checkout source
13+
uses: actions/checkout@v4
14+
15+
- name: 2. Set up JDK
16+
uses: actions/setup-java@v4
17+
with:
18+
java-version: 21
19+
distribution: temurin
20+
21+
- name: 3. 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: 4. Build JAR
32+
run: ./gradlew clean build -x test
33+
34+
- name: 5. Docker login
35+
uses: docker/login-action@v3
36+
with:
37+
username: ${{ secrets.DOCKER_USERNAME }}
38+
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
39+
40+
- name: 6. Build & Push Docker image
41+
uses: docker/build-push-action@v5
42+
with:
43+
context: .
44+
dockerfile: Dockerfile
45+
push: true
46+
tags: ${{ secrets.DOCKER_USERNAME }}/server:prod-latest
47+
48+
cd:
49+
runs-on: ubuntu-latest
50+
needs: ci
51+
52+
steps:
53+
- name: 1. Checkout source
54+
uses: actions/checkout@v4
55+
56+
- name: 2. Create .env file
57+
run: echo "${{ secrets.PROD_ENV }}" > .env
58+
59+
- name: 3. Upload .env to Prod Server
60+
uses: appleboy/scp-action@master
61+
with:
62+
host: ${{ secrets.EC2_PUBLIC_IP }}
63+
username: ${{ secrets.SSH_USER }}
64+
key: ${{ secrets.EC2_PRIVATE_KEY }}
65+
source: ".env"
66+
target: "/home/ubuntu/stepbookstep-prod/docker/"
67+
68+
- name: 4. docker-compose.yml 전달
69+
uses: appleboy/scp-action@master
70+
with:
71+
host: ${{ secrets.EC2_PUBLIC_IP }}
72+
username: ${{ secrets.SSH_USER }}
73+
key: ${{ secrets.EC2_PRIVATE_KEY }}
74+
source: "./docker/docker-compose.prod.yml"
75+
target: "/home/ubuntu/stepbookstep-prod/"
76+
77+
- name: 5. SSH to Dev Server and Deploy
78+
uses: appleboy/ssh-action@master
79+
with:
80+
host: ${{ secrets.EC2_PUBLIC_IP }}
81+
username: ${{ secrets.SSH_USER }}
82+
key: ${{ secrets.EC2_PRIVATE_KEY }}
83+
script: |
84+
cd /home/ubuntu/stepbookstep-dev/docker/
85+
docker pull ${{ secrets.DOCKER_USERNAME }}/server:latest
86+
docker compose -f docker-compose.prod.yml down
87+
docker compose -f docker-compose.prod.yml up -d

.gitignore

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,42 @@ out/
3838

3939
### Kotlin ###
4040
.kotlin
41+
42+
## application.yml
43+
**/resources/*.yml
44+
45+
### MySQL Docker volume data ###
46+
docker/mysql/data/
47+
mysql/data/
48+
49+
### Redis ###
50+
redis/data/
51+
dump.rdb
52+
53+
### Logs ###
54+
logs/
55+
*.log
56+
*.log.*
57+
58+
### OS ###
59+
.DS_Store
60+
Thumbs.db
61+
62+
### Docker ###
63+
docker-compose.override.yml
64+
65+
### Backup files ###
66+
*.bak
67+
*.swp
68+
*~
69+
70+
### Secrets & Keys ###
71+
secrets/
72+
*.pem
73+
*.key
74+
*.crt
75+
*.yml
76+
77+
### Env ###
78+
.env*
79+
docker/.env*

Dockerfile

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# ==============================
2+
# 1단계: Gradle 빌드 (Builder Stage)
3+
# ==============================
4+
FROM gradle:8.4-jdk21 AS builder
5+
WORKDIR /app
6+
7+
# Gradle 설정 파일 복사 (Kotlin DSL)
8+
COPY build.gradle.kts settings.gradle.kts gradlew ./
9+
COPY gradle ./gradle
10+
11+
# 의존성 미리 다운로드 (캐시 최적화)
12+
RUN ./gradlew dependencies --no-daemon || return 0
13+
14+
# 전체 프로젝트 복사
15+
COPY . .
16+
17+
# Kotlin 프로젝트 빌드 (테스트 제외)
18+
RUN ./gradlew clean build -x test --no-daemon
19+
20+
# ==============================
21+
# 2단계: Runtime Stage
22+
# ==============================
23+
FROM eclipse-temurin:21
24+
WORKDIR /app
25+
26+
# 빌드 결과물 복사
27+
COPY --from=builder /app/build/libs/*.jar app.jar
28+
29+
EXPOSE 8080
30+
31+
ENTRYPOINT ["java", "-jar", "app.jar"]

build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,15 @@ dependencies {
3333
implementation("org.springframework.boot:spring-boot-starter-webmvc")
3434
implementation("org.jetbrains.kotlin:kotlin-reflect")
3535
implementation("tools.jackson.module:jackson-module-kotlin")
36+
implementation("org.springframework.boot:spring-boot-starter-actuator")
3637
developmentOnly("org.springframework.boot:spring-boot-devtools")
3738
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
3839
// testImplementation("org.springframework.boot:spring-boot-starter-data-jpa-test")
3940
testImplementation("org.springframework.boot:spring-boot-starter-security-test")
4041
testImplementation("org.springframework.boot:spring-boot-starter-webmvc-test")
4142
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
4243
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
44+
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
4345
}
4446

4547
kotlin {

docker/docker-compose.dev.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
services:
2+
stepbookstep-app:
3+
image: stepbookstep/server:latest
4+
container_name: stepbookstep-dev
5+
restart: unless-stopped
6+
env_file:
7+
- .env
8+
ports:
9+
- "8080:8080"
10+
environment:
11+
SPRING_PROFILES_ACTIVE: dev
12+
13+
mysql:
14+
image: mysql:8.0
15+
container_name: stepbookstep-mysql
16+
volumes:
17+
- mysql_dev_data:/var/lib/mysql
18+
ports:
19+
- '3306:3306'
20+
environment:
21+
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
22+
MYSQL_DATABASE: ${DB_DATABASE}
23+
MYSQL_USER: ${DB_USER}
24+
MYSQL_PASSWORD: ${DB_PASSWORD}
25+
26+
redis:
27+
image: redis:7.2.5
28+
container_name: stepbookstep-redis
29+
ports:
30+
- '6379:6379'
31+
32+
networks:
33+
backend-bridge:
34+
driver: bridge

docker/docker-compose.prod.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
services:
2+
stepbookstep-app:
3+
image: stepbookstep/server:latest
4+
container_name: stepbookstep-prod-app
5+
restart: unless-stopped
6+
ports:
7+
- "8080:8080"
8+
environment:
9+
SPRING_PROFILES_ACTIVE: prod
10+
ALADIN_API_KEY: ${ALADIN_API_KEY}
11+
depends_on:
12+
- mysql
13+
- redis
14+
networks:
15+
- backend-bridge
16+
env_file:
17+
- .env
18+
19+
mysql:
20+
image: mysql:8.0
21+
container_name: stepbookstep-mysql
22+
ports:
23+
- '3306:3306'
24+
volumes:
25+
- ./mysql/data:/var/lib/mysql
26+
environment:
27+
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
28+
MYSQL_DATABASE: ${MYSQL_DATABASE}
29+
MYSQL_USER: ${MYSQL_USER}
30+
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
31+
networks:
32+
- backend-bridge
33+
34+
redis:
35+
image: redis:7.2.5
36+
container_name: stepbookstep-redis-prod
37+
ports:
38+
- '6379:6379'
39+
networks:
40+
- backend-bridge
41+
42+
volumes:
43+
mysql_prod_data:
44+
45+
networks:
46+
backend-bridge:
47+
driver: bridge

0 commit comments

Comments
 (0)