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

Feat: CI / CD 환경 구축 #8

Merged
merged 28 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2967b71
chore: deploy.sh 작성(#7)
whereami2048 Apr 30, 2024
1a8a968
chore: CI 워크플로우 파일 작성(#7)
whereami2048 Apr 30, 2024
ace5e2f
chore: 스프링 부트 버전 다운그레이드 3.2.5 -> 3.1.1(#7)
whereami2048 Apr 30, 2024
1dbf9e4
chore: Dockerfile, docker-compose.yml 파일 작성(#7)
whereami2048 Apr 30, 2024
53075d0
chore: CD-dev 파일 작성(#7)
whereami2048 Apr 30, 2024
3bab5ca
chore: application.yml 파일 작성(#7)
whereami2048 Apr 30, 2024
c0c1879
chore: CD 워크 플로우 .env 파일 생성 플로우 추가
whereami2048 May 1, 2024
4f13002
chore: 테스트 용 워크플로우 트리거 브랜치 변경
whereami2048 May 2, 2024
a78f69f
chore: workflow 파일 수정
whereami2048 May 2, 2024
cffc659
chore: workflow 파일 수정
whereami2048 May 2, 2024
711e2b1
chore: CI restdocs 생성 구문 제외
whereami2048 May 2, 2024
45de8d9
chore: CD 워크 플로우 .env 파일 생성 플로우 추가(#7)
whereami2048 May 1, 2024
c69b3ba
chore: 테스트 용 워크플로우 트리거 브랜치 변경
whereami2048 May 2, 2024
f91e0f4
chore: workflow 파일 수정
whereami2048 May 2, 2024
1b8da54
chore: workflow 파일 수정
whereami2048 May 2, 2024
3c63b26
chore: CI restdocs 생성 구문 제외
whereami2048 May 2, 2024
cdd9d4d
chore: CI RestDocs 생성 명령어 제거(#7)
whereami2048 May 2, 2024
3670e81
Merge branch 'feat/ci-cd' of github.com:KUSITMS-29th-TEAM-B/Backend i…
whereami2048 May 2, 2024
c33381a
chore: 트리거 브랜치 롤백(#7)
whereami2048 May 2, 2024
7e970e7
chore: Dockerfile 수정 및 배포 테스트
whereami2048 May 2, 2024
d6e38c8
chore: Dockerfile jar 파일 이름 수정
whereami2048 May 2, 2024
56342e4
chore: docker-compose.yml 파일 수정
whereami2048 May 2, 2024
ca8957a
chore: application.yml 파일 전송 워크플로우 삭제(#7)
whereami2048 May 2, 2024
75d3c91
chore: CD 테스트를 위한 healthCheckController 임시 추가
whereami2048 May 2, 2024
18638c5
chore: healthCheck 로그 출력
whereami2048 May 2, 2024
0c0879a
chore: CD 테스트(#7)
whereami2048 May 2, 2024
58ad7c2
feat: SecurityConfig 파일 추가(#7)
whereami2048 May 2, 2024
8260f6c
chore: CD 트리거 브랜치 main으로 변경(#7)
whereami2048 May 2, 2024
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
101 changes: 101 additions & 0 deletions .github/workflows/CD-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
name: CD-dev

on:
push:
branches: [ "main" ]

permissions:
contents: read

jobs:
deploy:
runs-on: ubuntu-22.04
steps:
- name: checkout
uses: actions/checkout@v3

- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'corretto'

- name: Gradle Caching
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-

- name: Set .env for configuration
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ubuntu
key: ${{ secrets.KEY }}
script: |
rm -rf ./.env
touch ./.env
echo "DOCKER_USERNAME=${{ secrets.DOCKER_USERNAME }}" >> ./.env
echo "DOCKER_REPOSITORY=${{ secrets.DOCKER_REPOSITORY }}" >> ./.env
echo "DB_URL=${{ secrets.DEV_DB_URL }}" >> ./.env
echo "DB_USERNAME=${{ secrets.DEV_DB_USERNAME }}" >> ./.env
echo "DB_PASSWORD=${{ secrets.DEV_DB_PASSWORD }}" >> ./.env
# echo "JWT_SECRET=${{ secrets.JWT_SECRET }}" >> ./.env
# echo "KAKAO_APP_ID=${{ secrets.KAKAO_APP_ID }}" >> ./.env
# echo "APPLE_APP_ID=${{ secrets.APPLE_APP_ID }}" >> ./.env
# echo "S3_BUCKET=${{ secrets.S3_BUCKET }}" >> ./.env
# echo "AWS_ACCESS_KEY=${{ secrets.AWS_ACCESS_KEY }}" >> ./.env
# echo "AWS_SECRET_KEY=${{ secrets.AWS_SECRET_KEY }}" >> ./.env

# gradle build
- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Build with Gradle
run: ./gradlew build -x test

## 도커 이미지 빌드 후 도커허브에 push
- name: docker build and push
run: |
docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
docker build -t ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPOSITORY }} .
docker push ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPOSITORY }}

## deploy.sh 파일 서버로 전달
- name: Send deploy.sh
uses: appleboy/scp-action@master
with:
username: ubuntu
host: ${{ secrets.HOST }}
key: ${{ secrets.KEY }}
port: 22
source: "./scripts/"
target: "/home/ubuntu/"

- name: Send docker-compose.yml
uses: appleboy/scp-action@master
with:
username: ubuntu
host: ${{ secrets.HOST }}
key: ${{ secrets.KEY }}
port: 22
source: "./docker-compose.yml"
target: "/home/ubuntu/"

## 도커 허브에서 jar파일 및 pull후에 컴포즈 up
- name: Deploy to Dev
uses: appleboy/ssh-action@master
with:
username: ubuntu
host: ${{ secrets.HOST }}
key: ${{ secrets.KEY }}
script: |
sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPOSITORY }}
chmod 777 ./scripts/deploy.sh
cp ./scripts/deploy.sh ./deploy.sh
./deploy.sh
docker image prune -f
36 changes: 36 additions & 0 deletions .github/workflows/CI-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: CI-dev

on:
pull_request:
branches:
- develop

jobs:
build:
runs-on: ubuntu-22.04

steps:
- uses: actions/checkout@v2

- name: Setup JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'corretto'

- name: Gradle Caching
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Grant Execute Permission For Gradlew
run: chmod +x gradlew

- name: Build With Gradle
run: |
./gradlew build
./gradlew bootJar
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,9 @@ out/

### Kotlin ###
.kotlin

### .env ###
.env

### .DS_Store ###
.DS_Store/
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration
import org.springframework.boot.runApplication

@SpringBootApplication(exclude = [UserDetailsServiceAutoConfiguration::class])
@SpringBootApplication(
scanBasePackages = ["com.bamyanggang.apimodule"],
exclude = [UserDetailsServiceAutoConfiguration::class]
)
class ApiModuleApplication {
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.bamyanggang.apimodule.domain.auth.presentation.config

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.builders.WebSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer
import org.springframework.security.config.http.SessionCreationPolicy
import org.springframework.security.web.SecurityFilterChain


@EnableWebSecurity
@Configuration
class SecurityConfig {
// TODO: api 추가될 때 white list url 확인해서 추가하기.
private val whiteList: Array<String> = arrayOf(
"/api/**",
"/api-docs/**",
"/",
"/error"
)

@Bean
fun webSecurityCustomizer(): WebSecurityCustomizer {
return WebSecurityCustomizer { web: WebSecurity -> web.ignoring().requestMatchers(*whiteList) }
}

@Bean
@Throws(Exception::class)
fun filterChain(http: HttpSecurity): SecurityFilterChain {
return http
.csrf { obj: AbstractHttpConfigurer<*, *> -> obj.disable() }
.formLogin { obj: AbstractHttpConfigurer<*, *> -> obj.disable() }
.httpBasic { obj: AbstractHttpConfigurer<*, *> -> obj.disable() }
.sessionManagement { sessionManagementConfigurer ->
sessionManagementConfigurer
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
}
.authorizeHttpRequests { authorizationManagerRequestMatcherRegistry ->
authorizationManagerRequestMatcherRegistry
.anyRequest()
.authenticated()
}
.build()
}
}
1 change: 0 additions & 1 deletion Api-Module/src/main/resources/application.properties

This file was deleted.

25 changes: 25 additions & 0 deletions Api-Module/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
spring:
application:
name: Api-Module

datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${DB_URL}
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
jpa:
open-in-view: false
hibernate:
ddl-auto: update
database-platform: org.hibernate.dialect.MySQLDialect
security:
oauth2:
client:
registration:
google:
client-id: ${OAUTH_GOOGLE_CLIENT_ID}
client-secret: ${OAUTH_GOOGLE_CLIENT_SECRET}
scope:
- email
- profile
redirect-uri: ${OAUTH_GOOGLE_REDIRECT_URI}
10 changes: 10 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM amazoncorretto:17-alpine-jdk

# JAR_FILE 변수에 값을 저장
ARG JAR_FILE=/Api-Module/build/libs/Api-Module-0.0.1-SNAPSHOT.jar

# 변수에 저장된 것을 컨테이너 실행시 이름을 app.jar파일로 변경하여 컨테이너에 저장
COPY ${JAR_FILE} app.jar

# 빌드된 이미지가 run될 때 실행할 명령어
ENTRYPOINT ["java","-jar","app.jar"]
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import org.springframework.boot.gradle.tasks.bundling.BootJar

plugins {
id("java-test-fixtures")
id("org.springframework.boot") version "3.2.5"
id("org.springframework.boot") version "3.1.1"
id("io.spring.dependency-management") version "1.1.4"

kotlin("jvm") version "1.9.23"
Expand Down
24 changes: 24 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
version: '3'
services:
blue:
container_name: blue
image: ${DOCKER_USERNAME}/${DOCKER_REPOSITORY}
expose:
- 8080
ports:
- "8082:8080"
environment:
- DB_URL=${DB_URL}
- DB_USERNAME=${DB_USERNAME}
- DB_PASSWORD=${DB_PASSWORD}
green:
container_name: green
image: ${DOCKER_USERNAME}/${DOCKER_REPOSITORY}
expose:
- 8080
ports:
- "8081:8080"
environment:
- DB_URL=${DB_URL}
- DB_USERNAME=${DB_USERNAME}
- DB_PASSWORD=${DB_PASSWORD}
59 changes: 59 additions & 0 deletions scripts/deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/bin/bash

IS_GREEN=$(docker ps | grep green) # 현재 실행중인 App이 blue인지 확인합니다.
DEFAULT_CONF=" /etc/nginx/nginx.conf"

if [ -z $IS_GREEN ];then # blue라면

echo "### BLUE => GREEN ####"

echo "1. get green image"
docker-compose pull green # green으로 이미지를 내려받습니다.

echo "2. green container up"
docker-compose up -d green # green 컨테이너 실행

while [ 1 = 1 ]; do
echo "3. green health check..."
sleep 3

REQUEST=$(curl http://127.0.0.1:8081) # green으로 request
if [ -n "$REQUEST" ]; then # 서비스 가능하면 health check 중지
echo "health check success"
break ;
fi
done;

echo "4. reload nginx"
sudo cp /etc/nginx/nginx.green.conf /etc/nginx/nginx.conf
sudo nginx -s reload

echo "5. blue container down"
docker-compose stop blue
else
echo "### GREEN => BLUE ###"

echo "1. get blue image"
docker-compose pull blue

echo "2. blue container up"
docker-compose up -d blue

while [ 1 = 1 ]; do
echo "3. blue health check..."
sleep 3
REQUEST=$(curl http://127.0.0.1:8082) # blue로 request

if [ -n "$REQUEST" ]; then # 서비스 가능하면 health check 중지
echo "health check success"
break ;
fi
done;

echo "4. reload nginx"
sudo cp /etc/nginx/nginx.blue.conf /etc/nginx/nginx.conf
sudo nginx -s reload

echo "5. green container down"
docker-compose stop green
fi
Loading