Skip to content

Commit

Permalink
Merge pull request #10 from Wedit-project/feat/#1-CI/CD-구현
Browse files Browse the repository at this point in the history
[feat] CI/CD 구현
  • Loading branch information
dyk-im authored Jan 9, 2025
2 parents 7600d4d + 3a77e17 commit 10d85cf
Show file tree
Hide file tree
Showing 4 changed files with 266 additions and 0 deletions.
140 changes: 140 additions & 0 deletions .github/workflows/dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
name: Java CI with Gradle

on:
push:
branches: [ "develop" ]
pull_request:
branches: [ "develop" ]

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout the repository
uses: actions/checkout@v3

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

# gradle caching - 빌드 시간 향상
- 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-
# 환경별 yml 파일 생성(1) - application.yml
- name: make application.yml
if: |
contains(github.ref, 'develop') ||
(github.event_name == 'pull_request')
run: |
mkdir ./src/main/resources # resources 폴더 생성
cd ./src/main/resources # resources 폴더로 이동
touch ./application.yml # application.yml 생성
echo "${{ secrets.YML }}" > ./application.yml # github actions에서 설정한 값을 application.yml 파일에 쓰기
shell: bash

# 환경별 yml 파일 생성(2) - dev
- name: make application-dev.yml
if: |
contains(github.ref, 'develop') ||
(github.event_name == 'pull_request')
run: |
cd ./src/main/resources
touch ./application-dev.yml
echo "${{ secrets.YML_DEV }}" > ./application-dev.yml
shell: bash

# 환경별 yml 파일 생성(3) - bucket
- name: make application-bucket.yml
if: |
contains(github.ref, 'develop') ||
(github.event_name == 'pull_request')
run: |
cd ./src/main/resources
touch ./application-dev.yml
echo "${{ secrets.YML_BUCKET }}" > ./application-bucket.yml
shell: bash

# 환경별 yml 파일 생성(3) - oauth
#- name: make application-oauth.yml
# if: |
# contains(github.ref, 'develop') ||
# (github.event_name == 'pull_request')
# run: |
# cd ./src/main/resources
# touch ./application-oauth.yml
# echo "${{ secrets.YML_OAUTH }}" > ./application-oauth.yml
# shell: bash

# 환경별 yml 파일 생성(3) - jwt
#- name: make application-jwt.yml
# if: |
# contains(github.ref, 'develop') ||
# (github.event_name == 'pull_request')
# run: |
# cd ./src/main/resources
# touch ./application-jwt.yml
# echo "${{ secrets.YML_JWT }}" > ./application-jwt.yml
# shell: bash

# Gradle Build (test는 제외)
- name: Build with Gradle
run: |
chmod +x gradlew
./gradlew build -x test
# 도커 허브에 로그인
- name: Docker Hub Login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USER_NAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Build Docker image
run: docker build -t ${{ secrets.DOCKER_USER_NAME }}/wedit .

- name: Push Docker image
run: docker push ${{ secrets.DOCKER_USER_NAME }}/wedit

deploy:
runs-on: ubuntu-latest
needs: build
if: github.event_name == 'push'

steps:
- name: Deploy to EC2
uses: appleboy/[email protected]
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.EC2_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: 22
script: |
EXISTING_CONTAINER_ID=$(sudo docker ps -q -f "publish=8080" -f "status=running")
if [ ! -z "$EXISTING_CONTAINER_ID" ]; then
sudo docker stop $EXISTING_CONTAINER_ID
sudo docker rm $EXISTING_CONTAINER_ID
fi
EXISTING_CONTAINER_ID=$(sudo docker ps -q -f "status=exited")
if [ ! -z "$EXISTING_CONTAINER_ID" ]; then
sudo docker rm $EXISTING_CONTAINER_ID
fi
sudo docker pull ${{ secrets.DOCKER_USER_NAME }}/wedit
sudo docker run --name spring -d -p 8080:8080 -e TZ=Asia/Seoul ${{ secrets.DOCKER_USER_NAME }}/wedit
sudo docker image prune -a -f
debug: true # Enable debugging output
12 changes: 12 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# open jdk 17 버전의 환경을 구성
FROM openjdk:17-alpine

# build가 되는 시점에 JAR_FILE이라는 변수 명에 build/libs/*.jar 선언
# build/libs - gradle로 빌드했을 때 jar 파일이 생성되는 경로
ARG JAR_FILE=build/libs/*.jar

# JAR_FILE을 app.jar로 복사
COPY ${JAR_FILE} app.jar

# 운영 및 개발에서 사용되는 환경 설정을 분리
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=dev, bucket", "/app.jar"]
80 changes: 80 additions & 0 deletions src/main/java/com/wedit/weditapp/domain/shared/S3Service.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.wedit.weditapp.domain.shared;

import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@RequiredArgsConstructor
@Service
public class S3Service {
private final AmazonS3Client amazonS3Client;

@Value("${cloud.aws.s3.bucket}")
private String bucket;

@Value("${cloud.aws.s3.path.image}")
private String imageFolder;

public String upload(MultipartFile multipartFile) {
String fileName = imageFolder + multipartFile.getOriginalFilename();

if (!(fileName.endsWith(".png") || fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") || fileName.endsWith(
".gif") || fileName.endsWith(".bmp"))) {
throw new RuntimeException();
}

ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType(multipartFile.getContentType());
metadata.setContentLength(multipartFile.getSize());
String uploadImageUrl = putS3(multipartFile, fileName, metadata);

return uploadImageUrl; // 업로드된 파일의 S3 URL 주소 반환
}

private String putS3(MultipartFile multipartFile, String fileName, ObjectMetadata metadata) {
try (InputStream inputStream = multipartFile.getInputStream()) {
amazonS3Client.putObject(
new PutObjectRequest(bucket, fileName, inputStream, metadata)
);
} catch (IOException e) {
throw new RuntimeException("파일 업로드 중 오류 발생", e);
}
return amazonS3Client.getUrl(bucket, fileName).toString();
}

//이미지 가져오기(url) => public access 걸어놔서 가져올 수 있을 것임
public String getImageFileUrl(String fileName) {
String filePath = imageFolder + fileName;
return amazonS3Client.getUrl(bucket, filePath).toString();
}

//파일 이름 중복 방지 코드
private String generateUniqueFileName(String originalFilename) {
String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
return UUID.randomUUID() + extension; // 고유 파일 이름 생성
}
//검증로직 필요하면 사용 가능
private void validateFileFormat(MultipartFile multipartFile) {
String contentType = multipartFile.getContentType();
if (contentType == null || !contentType.startsWith("image/")) {
throw new IllegalArgumentException("지원하지 않는 파일 형식입니다.");
}
}
//S3 파일 삭제가 필요한 경우
public void removeFile(String fileUrl) {
String fileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1);
amazonS3Client.deleteObject(bucket, imageFolder + fileName);
}
}
34 changes: 34 additions & 0 deletions src/main/java/com/wedit/weditapp/global/config/AwsConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.wedit.weditapp.global.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;

@Configuration
public class AwsConfig {
@Value("${cloud.aws.credentials.access-key}")
private String accessKey;

// S3를 등록한 사람이 전달받은 접속하기 위한 secret key 값
@Value("${cloud.aws.credentials.secret-key}")
private String secretKey;

// S3를 등록한 사람이 S3를 사용할 지역
@Value("${cloud.aws.region.static}")
private String region;

// 전달받은 Accesskey 와 SecretKey 로 아마존 서비스 실행 준비
@Bean
public AmazonS3Client amazonS3Client() {
BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, secretKey);
return (AmazonS3Client)AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.build();
}
}

0 comments on commit 10d85cf

Please sign in to comment.