Skip to content

Commit

Permalink
Merge pull request #43 from SomSomParty/test
Browse files Browse the repository at this point in the history
[CHORE] CI/CD 구축
  • Loading branch information
dlrkdus authored Jan 2, 2025
2 parents 0a5a67c + 6952391 commit 8d6b4cb
Show file tree
Hide file tree
Showing 16 changed files with 237 additions and 81 deletions.
78 changes: 78 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Build, Push to ECR, and Deploy via CodeDeploy

on:
push:
branches:
- dev

permissions:
id-token: write
contents: read

jobs:
deploy:
runs-on: ubuntu-latest

env:
AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }}
ECR_REPOSITORY_NAME: somparty
AWS_REGION: ap-northeast-2
S3_BUCKET: ${{ secrets.S3_BUCKET_NAME }}
CODEDEPLOY_APP_NAME: ${{ secrets.CODEDEPLOY_APP_NAME }}
CODEDEPLOY_DEPLOYMENT_GROUP_NAME: ${{ secrets.CODEDEPLOY_DEPLOYMENT_GROUP_NAME }}

steps:
# 1. Java 17 설치
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'

# 2. 깃허브 레포에서 코드 가져오기
- name: Checkout Code
uses: actions/checkout@v3

# 3. Gradle 빌드
- name: Build Gradle
run: |
chmod +x ./gradlew
./gradlew build -x test
# 4. AWS IAM 역할로 GitHub Action에 AWS 접근 권한 부여
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/${{ secrets.ACTION_ROLE_NAME }}
aws-region: ${{ env.AWS_REGION }}

# 5. Amazon ECR 로그인
- name: Log in to Amazon ECR
run: |
aws ecr get-login-password --region ${{ env.AWS_REGION }} | docker login --username AWS --password-stdin ${{ env.AWS_ACCOUNT_ID }}.dkr.ecr.${{ env.AWS_REGION }}.amazonaws.com
# 6. 도커 이미지 빌드
- name: Build Docker Image
run: |
docker build -t ${{ env.ECR_REPOSITORY_NAME }}:latest .
docker tag ${{ env.ECR_REPOSITORY_NAME }}:latest ${{ env.AWS_ACCOUNT_ID }}.dkr.ecr.${{ env.AWS_REGION }}.amazonaws.com/${{ env.ECR_REPOSITORY_NAME }}:latest
# 7. ECR로 빌드한 이미지 푸시
- name: Push to Amazon ECR
run: |
docker push ${{ env.AWS_ACCOUNT_ID }}.dkr.ecr.${{ env.AWS_REGION }}.amazonaws.com/${{ env.ECR_REPOSITORY_NAME }}:latest
# 8. CodeDeploy에 필요한 파일 압축 및 S3 업로드
- name: Prepare and Upload Deployment Package
run: |
zip -r deploy.zip appspec.yml scripts/
aws s3 cp deploy.zip s3://${{ env.S3_BUCKET }}/deploy.zip --region ${{ env.AWS_REGION }}
# 9. CodeDeploy로 배포 실행
- name: Start CodeDeploy Deployment
run: |
aws deploy create-deployment \
--application-name ${{ env.CODEDEPLOY_APP_NAME }} \
--deployment-group-name ${{ env.CODEDEPLOY_DEPLOYMENT_GROUP_NAME }} \
--s3-location bucket=${{ env.S3_BUCKET }},key=deploy.zip,bundleType=zip \
--region ${{ env.AWS_REGION }}
11 changes: 11 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Base image
FROM openjdk:17-slim

# Set working directory
WORKDIR /app

# Copy application jar to container
COPY build/libs/somsomparty-0.0.1-SNAPSHOT.jar /app/app.jar

# Run the application
ENTRYPOINT ["java", "-jar", "/app/app.jar", "--spring.profiles.active=prod"]
19 changes: 19 additions & 0 deletions appspec.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
version: 0.0
os: linux
files:
- source: /
destination: /home/ubuntu/somparty
overwrite: yes

permissions:
- object: /
pattern: "**"
owner: ubuntu
group: ubuntu
mode: 755

hooks:
AfterInstall:
- location: scripts/afterInstall.sh
timeout: 60
runas: ubuntu
5 changes: 4 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ dependencies {
implementation 'com.auth0:java-jwt:4.4.0';
// 카프카
implementation 'org.springframework.kafka:spring-kafka:2.9.0'
implementation 'software.amazon.msk:aws-msk-iam-auth:1.1.0'
//DynamoDB
implementation platform('software.amazon.awssdk:bom:2.20.85')
implementation 'software.amazon.awssdk:dynamodb-enhanced'
Expand All @@ -58,12 +59,14 @@ dependencies {
//jackson
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.18.1'

implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:3.0.1")
implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:3.1.0")
implementation 'io.awspring.cloud:spring-cloud-aws-starter-sqs:3.2.0-M1'
implementation 'org.springframework.boot:spring-boot-starter-data-redis-reactive'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation "org.redisson:redisson-spring-boot-starter:3.40.2"
implementation 'io.awspring.cloud:spring-cloud-aws-starter-parameter-store'
implementation 'org.springframework.boot:spring-boot-starter-actuator'

}

tasks.named('test') {
Expand Down
18 changes: 18 additions & 0 deletions docker-compose.prod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version: '3.8'

services:
kafka-ui:
image: provectuslabs/kafka-ui
container_name: kafka-ui
ports:
- "8989:8080"
restart: always
environment:
- KAFKA_CLUSTERS_0_NAME=sompartyMsk
- KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=b-1.msk-cluster.kafka.ap-northeast-2.amazonaws.com:9092,b-2.msk-cluster.kafka.ap-northeast-2.amazonaws.com:9092,b-3.msk-cluster.kafka.ap-northeast-2.amazonaws.com:9092
- KAFKA_CLUSTERS_0_SECURITY=PLAINTEXT
- KAFKA_CLUSTERS_0_SECURITY=SASL_SSL
- KAFKA_CLUSTERS_0_SASL_MECHANISM=AWS_MSK_IAM
- KAFKA_CLUSTERS_0_PROPERTIES_AUTHENTICATION=SASL_SSL
- KAFKA_CLUSTERS_0_PROPERTIES_SASL_JAAS_CONFIG=software.amazon.msk.auth.iam.IAMLoginModule required;
- KAFKA_CLUSTERS_0_PROPERTIES_SASL_CLIENT_CALLBACK_HANDLER_CLASS=software.amazon.msk.auth.iam.IAMClientCallbackHandler
29 changes: 29 additions & 0 deletions scripts/afterInstall.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/bash

echo "AfterInstall: Starting the deployment process..."

# 1. AWS ECR 로그인
echo "Logging in to Amazon ECR..."
aws ecr get-login-password --region ap-northeast-2 | sudo docker login --username AWS --password-stdin 084828566517.dkr.ecr.ap-northeast-2.amazonaws.com

# 2. 기존 Docker 컨테이너 중지 및 제거
echo "Stopping and removing existing Docker containers..."
sudo docker stop somparty || true
sudo docker rm somparty || true

# 3. 새 이미지 가져오기
echo "Pulling the latest Docker image from ECR..."
sudo docker pull 084828566517.dkr.ecr.ap-northeast-2.amazonaws.com/somparty:latest

# 4. 새 컨테이너 실행
echo "Running the new Docker container..."
sudo docker run -d -p 8080:8080 --name somparty 084828566517.dkr.ecr.ap-northeast-2.amazonaws.com/somparty:latest

# 5. 애플리케이션 상태 확인
echo "Validating the application health..."
status_code=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/actuator/health)
if [ "$status_code" -eq 200 ]; then
echo "Service is running successfully with status code $status_code."
else
echo "Service validation failed with status code $status_code."
fi
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,29 @@

import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sns.SnsClient;
import software.amazon.awssdk.services.sqs.SqsClient;

@Getter
@Configuration
public class NotiAWSConfig {
@Value("${aws.noti.accessKey}")
private String notiAccessKey;

@Value("${aws.noti.secretKey}")
private String notiSecretKey;

@Value("${aws.noti.region}")
private String notiRegion;

@Bean
public SnsClient snsClient() {
return SnsClient.builder()
.region(Region.of(notiRegion))
.build();
}

@Bean
public SqsClient sqsClient() {
return SqsClient.builder()
.region(Region.of(notiRegion))
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@
import software.amazon.awssdk.services.sns.SnsClient;

public interface CredentialService {
AwsCredentialsProvider getAwsCredentials(String accessKeyID, String secretAccessKey);
SnsClient getSnsClient();
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,18 @@
import org.springframework.stereotype.Service;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sns.SnsClient;

@Service
@AllArgsConstructor
public class CredentialServiceImpl implements CredentialService {
private NotiAWSConfig notiAwsConfig;

public AwsCredentialsProvider getAwsCredentials(String accessKeyID, String secretAccessKey) {
AwsBasicCredentials awsBasicCredentials =
AwsBasicCredentials.create(accessKeyID, secretAccessKey);
return () -> awsBasicCredentials;
}

public SnsClient getSnsClient() {
return SnsClient.builder()
.credentialsProvider(getAwsCredentials(notiAwsConfig.getNotiAccessKey(),
notiAwsConfig.getNotiSecretKey())
).region(Region.of(notiAwsConfig.getNotiRegion()))
.credentialsProvider(DefaultCredentialsProvider.create()) // IAM 역할 기반 인증
.region(Region.AP_NORTHEAST_2) // AWS Region 설정
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,44 +1,29 @@
package com.acc.somsomparty.domain.Queue.config;

import static software.amazon.awssdk.regions.Region.AP_NORTHEAST_2;

import io.awspring.cloud.sqs.config.SqsBootstrapConfiguration;
import io.awspring.cloud.sqs.config.SqsMessageListenerContainerFactory;
import io.awspring.cloud.sqs.listener.acknowledgement.AcknowledgementOrdering;
import io.awspring.cloud.sqs.listener.acknowledgement.handler.AcknowledgementMode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import software.amazon.awssdk.auth.credentials.AwsCredentials;
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsAsyncClient;

@Import(SqsBootstrapConfiguration.class)
@Slf4j
@Configuration
public class AwsSQSConfig {
@Value("${spring.cloud.aws.queue.access-key}")
private String AWS_ACCESS_KEY;
@Value("${spring.cloud.aws.queue.secret-key}")
private String AWS_SECRET_KEY;
@Value("${spring.cloud.aws.queue.region}")
private String AWS_REGION;

@Bean
public SqsAsyncClient sqsAsyncClient() {
return SqsAsyncClient.builder()
.credentialsProvider(() -> new AwsCredentials() {
@Override
public String accessKeyId() {
return AWS_ACCESS_KEY;
}

@Override
public String secretAccessKey() {
return AWS_SECRET_KEY;
}
})
.region(Region.of(AWS_REGION))
.credentialsProvider(DefaultCredentialsProvider.create()) // IAM 역할 기반 인증
.region(Region.of(String.valueOf(AP_NORTHEAST_2))) // 환경 변수에서 AWS Region 읽기
.build();
}

Expand All @@ -47,7 +32,7 @@ SqsMessageListenerContainerFactory<Object> defaultSqsListenerContainerFactory(Sq
return SqsMessageListenerContainerFactory
.builder()
.configure(options -> options
.acknowledgementMode(AcknowledgementMode.MANUAL) // 명시적으로 acknowledgement를 해야 메시지가 삭제
.acknowledgementMode(AcknowledgementMode.MANUAL) // 명시적으로 acknowledgement를 해야 메시지가 삭제됨
.acknowledgementOrdering(AcknowledgementOrdering.ORDERED) // 순서대로 처리
)
.sqsAsyncClient(sqsAsyncClient)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,19 @@
package com.acc.somsomparty.domain.User.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.cognitoidentityprovider.CognitoIdentityProviderClient;

@Configuration
public class CognitoConfig {
@Value("${aws.auth.cognito.accessKey}")
private String accessKey;

@Value("${aws.auth.cognito.secretKey}")
private String secretKey;

@Bean
public CognitoIdentityProviderClient cognitoClient() {
AwsBasicCredentials awsCredentials = AwsBasicCredentials.create(accessKey, secretKey);

return CognitoIdentityProviderClient.builder()
.region(Region.AP_NORTHEAST_2)
.credentialsProvider(StaticCredentialsProvider.create(awsCredentials))
.region(Region.AP_NORTHEAST_2) // AWS Region 설정
.credentialsProvider(DefaultCredentialsProvider.create()) // IAM 역할 기반 인증
.build();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ public class UserChatRoom {
private Long id;

@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private User user;

@ManyToOne
Expand Down
Loading

0 comments on commit 8d6b4cb

Please sign in to comment.