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

be/feat: github actions 배포 설정 #220

Merged
merged 2 commits into from
Mar 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
50 changes: 50 additions & 0 deletions .github/workflows/backend-cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: 배포

on:
push:
branches:
- 'be/**'
pull_request:
branches:
- main
- develop

jobs:
deploy:
runs-on: ubuntu-latest # 작업이 실행될 환경
defaults:
run:
working-directory: backend
steps:
- name: 체크아웃
uses: actions/checkout@v3
Comment on lines +19 to +20
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Action Version Update: Checkout

The checkout step uses actions/checkout@v3. Static analysis indicates that this version may be outdated. Consider updating to the latest stable release (e.g., actions/checkout@v4) to benefit from performance improvements and security fixes.

🧰 Tools
🪛 actionlint (1.7.4)

20-20: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

- name: JDK 17 사용
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'corretto'
Comment on lines +21 to +25
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Action Version Update: Setup Java

The workflow employs actions/setup-java@v3 to set up JDK 17 with the Corretto distribution. Upgrading to a newer version (if available) could yield additional fixes and improvements.

🧰 Tools
🪛 actionlint (1.7.4)

22-22: the runner of "actions/setup-java@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

- name: Gradle Wrapper 실행 권한 추가
run: chmod +x gradlew
- name: Gradle로 빌드(CI)
run: ./gradlew build
Comment on lines +27 to +29
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Set working directory for Gradle commands

The Gradle commands are being executed at the repository root, but the Gradle wrapper might be in the backend directory.

If gradlew is indeed in the backend directory, use this fix:

- name: Gradle Wrapper 실행 권한 추가
- run: chmod +x gradlew
- name: Gradle로 빌드(CI)
- run: ./gradlew build
+ name: Gradle Wrapper 실행 권한 추가
+ run: chmod +x backend/gradlew
+ name: Gradle로 빌드(CI)
+ working-directory: ./backend
+ run: ./gradlew build

🏁 Script executed:

#!/bin/bash
# Check if gradlew exists in repo root or in backend directory
if [ -f "gradlew" ]; then
  echo "Gradle wrapper found in root directory"
else
  echo "Gradle wrapper not found in root directory"
  if [ -f "backend/gradlew" ]; then
    echo "Gradle wrapper found in backend directory"
  else
    echo "Gradle wrapper not found in backend directory either"
  fi
fi

Length of output: 237


Gradle Wrapper Location Adjustment Required

The verification confirms that the Gradle wrapper is located in the backend directory. Please update the workflow file to use the Gradle wrapper from ./backend by modifying the commands as follows:

  • Change the execute permission command to target backend/gradlew.
  • Set the working-directory to ./backend for the build command.
- name: Gradle Wrapper 실행 권한 추가
- run: chmod +x gradlew
- name: Gradle로 빌드(CI)
- run: ./gradlew build
+ name: Gradle Wrapper 실행 권한 추가
+ run: chmod +x backend/gradlew
+ name: Gradle로 빌드(CI)
+ working-directory: ./backend
+ run: ./gradlew build
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
run: chmod +x gradlew
- name: Gradle로 빌드(CI)
run: ./gradlew build
- name: Gradle Wrapper 실행 권한 추가
run: chmod +x backend/gradlew
- name: Gradle로 빌드(CI)
working-directory: ./backend
run: ./gradlew build

- name: 도커허브에 로그인
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USER_NAME }}
password: ${{ secrets.DOCKER_USER_PW }}
Comment on lines +30 to +34
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Update Docker Login Action Version

The login step uses docker/login-action@v1, which static analysis flags as outdated. Upgrading to a newer version (e.g., docker/login-action@v2) will help improve security and compatibility.

🧰 Tools
🪛 actionlint (1.7.4)

31-31: the runner of "docker/login-action@v1" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

- name: 이미지 빌드
run: docker buildx build --platform linux/amd64 -f Dockerfile.prod -t ${{ secrets.DOCKER_USER_NAME }}/${{ secrets.DOCKER_IMAGE_NAME }}-be:latest .
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix Dockerfile path and add caching for faster builds

The Dockerfile path is incorrect and should include the backend directory. Additionally, adding caching can significantly improve build times.

- run: docker buildx build --platform linux/amd64 -f Dockerfile.prod -t ${{ secrets.DOCKER_USER_NAME }}/${{ secrets.DOCKER_IMAGE_NAME }}-be:latest .
+ name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+ name: Cache Docker layers
+ uses: actions/cache@v3
+ with:
+   path: /tmp/.buildx-cache
+   key: ${{ runner.os }}-buildx-${{ github.sha }}
+   restore-keys: |
+     ${{ runner.os }}-buildx-
+ name: 이미지 빌드
+ run: docker buildx build --platform linux/amd64 -f backend/Dockerfile.prod -t ${{ secrets.DOCKER_USER_NAME }}/${{ secrets.DOCKER_IMAGE_NAME }}-be:latest --cache-from=type=local,src=/tmp/.buildx-cache --cache-to=type=local,dest=/tmp/.buildx-cache-new,mode=max backend/
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
run: docker buildx build --platform linux/amd64 -f Dockerfile.prod -t ${{ secrets.DOCKER_USER_NAME }}/${{ secrets.DOCKER_IMAGE_NAME }}-be:latest .
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Cache Docker layers
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: 이미지 빌드
run: docker buildx build --platform linux/amd64 -f backend/Dockerfile.prod -t ${{ secrets.DOCKER_USER_NAME }}/${{ secrets.DOCKER_IMAGE_NAME }}-be:latest --cache-from=type=local,src=/tmp/.buildx-cache --cache-to=type=local,dest=/tmp/.buildx-cache-new,mode=max backend/

- name: 도커허브에 이미지 푸시
run: docker push ${{ secrets.DOCKER_USER_NAME }}/${{ secrets.DOCKER_IMAGE_NAME }}-be:latest
- name: AWS EC2에 ssh 접속 후 배포
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.AWS_IP }}
port: 22
username: ubuntu
key: ${{ secrets.AWS_KEY }}
script: |
sudo docker rm -f $(docker ps -qa)
docker pull ${{ secrets.DOCKER_USER_NAME }}/${{ secrets.DOCKER_IMAGE_NAME }}-be:latest
docker-compose --env-file .env.production up -d
docker image prune -f
Comment on lines +39 to +50
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

AWS EC2 Deployment: Pin Action Version and Caution on Container Removal
Several points to consider for the SSH deployment step:

  • Action Version Pinning: Using appleboy/ssh-action@master is not ideal because relying on a branch head can introduce unexpected changes. It is recommended to pin to a specific stable version.
  • Destructive Container Removal: The command sudo docker rm -f $(docker ps -qa) forcefully stops and removes all containers on the host. Confirm that this behavior is acceptable, as it could impact other running services.
  • Enhancement Opportunity: Consider integrating health check verification and a rollback strategy in case the deployment fails.

Suggested Diff for Pinning Version:

-        uses: appleboy/ssh-action@master
+        uses: appleboy/[email protected]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: AWS EC2에 ssh 접속 후 배포
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.AWS_IP }}
port: 22
username: ubuntu
key: ${{ secrets.AWS_KEY }}
script: |
sudo docker rm -f $(docker ps -qa)
docker pull ${{ secrets.DOCKER_USER_NAME }}/${{ secrets.DOCKER_IMAGE_NAME }}-be:latest
docker-compose --env-file .env.production up -d
docker image prune -f
- name: AWS EC2에 ssh 접속 후 배포
uses: appleboy/ssh-action@v0.1.8
with:
host: ${{ secrets.AWS_IP }}
port: 22
username: ubuntu
key: ${{ secrets.AWS_KEY }}
script: |
sudo docker rm -f $(docker ps -qa)
docker pull ${{ secrets.DOCKER_USER_NAME }}/${{ secrets.DOCKER_IMAGE_NAME }}-be:latest
docker-compose --env-file .env.production up -d
docker image prune -f

Comment on lines +46 to +50
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Deployment Script: Caution and Enhancements

The deployment script begins with a forceful removal of all Docker containers using sudo docker rm -f $(docker ps -qa). This command is highly destructive and might inadvertently stop unrelated services running on the host. Consider refining it to target only the specific container(s) associated with your application. Additionally, the script invokes docker-compose --env-file .env.production up -d without any subsequent health check or rollback mechanism. Implementing a health check (and optionally a rollback strategy) would enhance the reliability of your deployment process.

4 changes: 4 additions & 0 deletions backend/Dockerfile.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM openjdk:17-jdk
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} techeer-resume-0.0.1-SNAPSHOT.jar
ENTRYPOINT ["java","-jar","/techeer-resume-0.0.1-SNAPSHOT.jar"]
Comment on lines +3 to +4
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Fix path inconsistency and improve container security

There's a path inconsistency between the COPY and ENTRYPOINT commands. Additionally, the Dockerfile could be improved with several production best practices.

FROM openjdk:17-jdk
ARG JAR_FILE=build/libs/*.jar
-COPY ${JAR_FILE} techeer-resume-0.0.1-SNAPSHOT.jar
-ENTRYPOINT ["java","-jar","/techeer-resume-0.0.1-SNAPSHOT.jar"]
+WORKDIR /app
+COPY ${JAR_FILE} app.jar
+RUN addgroup --system --gid 1001 appuser \
+    && adduser --system --uid 1001 --ingroup appuser appuser \
+    && chown -R appuser:appuser /app
+USER appuser
+HEALTHCHECK --interval=30s --timeout=3s --retries=3 CMD wget -qO- http://localhost:8080/actuator/health || exit 1
+ENTRYPOINT ["java", "-XX:+UseContainerSupport", "-XX:MaxRAMPercentage=75.0", "-jar", "app.jar"]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
COPY ${JAR_FILE} techeer-resume-0.0.1-SNAPSHOT.jar
ENTRYPOINT ["java","-jar","/techeer-resume-0.0.1-SNAPSHOT.jar"]
FROM openjdk:17-jdk
ARG JAR_FILE=build/libs/*.jar
WORKDIR /app
COPY ${JAR_FILE} app.jar
RUN addgroup --system --gid 1001 appuser \
&& adduser --system --uid 1001 --ingroup appuser appuser \
&& chown -R appuser:appuser /app
USER appuser
HEALTHCHECK --interval=30s --timeout=3s --retries=3 CMD wget -qO- http://localhost:8080/actuator/health || exit 1
ENTRYPOINT ["java", "-XX:+UseContainerSupport", "-XX:MaxRAMPercentage=75.0", "-jar", "app.jar"]

4 changes: 4 additions & 0 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ java {
}
}

jar {
enabled = false
}

configurations {
compileOnly {
extendsFrom annotationProcessor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();

config.setAllowCredentials(true);
config.setAllowedOrigins(List.of("http://localhost:8080", "http://localhost:5173", "http://backend:8080"));
config.setAllowedOrigins(List.of("http://localhost:8080", "http://localhost:5173", "http://backend:8080", "http://backend:5173", "http://rexume.site:8080", "http://rexume.site:5173", "http://rexume.site", "http://52.78.85.237:8080", "http://52.78.85.237:5173"));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use HTTPS for production domains and externalize CORS configuration

The CORS configuration has security and maintainability issues:

  1. Production domains should use HTTPS instead of HTTP for secure communication
  2. Hard-coded IP addresses (52.78.85.237) make configuration changes difficult
  3. The long list of origins would be better managed through configuration properties

Consider refactoring to use environment-specific properties:

-config.setAllowedOrigins(List.of("http://localhost:8080", "http://localhost:5173", "http://backend:8080", "http://backend:5173", "http://rexume.site:8080", "http://rexume.site:5173", "http://rexume.site", "http://52.78.85.237:8080", "http://52.78.85.237:5173"));
+// Load from application properties
+String[] allowedOrigins = environment.getProperty("cors.allowed-origins", String[].class);
+config.setAllowedOrigins(Arrays.asList(allowedOrigins));

Then define in your application-{profile}.properties/yml:

# Local development
cors.allowed-origins=http://localhost:8080,http://localhost:5173,http://backend:8080,http://backend:5173

# Production
# cors.allowed-origins=https://rexume.site,https://www.rexume.site,https://api.rexume.site
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
config.setAllowedOrigins(List.of("http://localhost:8080", "http://localhost:5173", "http://backend:8080", "http://backend:5173", "http://rexume.site:8080", "http://rexume.site:5173", "http://rexume.site", "http://52.78.85.237:8080", "http://52.78.85.237:5173"));
// Load from application properties
String[] allowedOrigins = environment.getProperty("cors.allowed-origins", String[].class);
config.setAllowedOrigins(Arrays.asList(allowedOrigins));

config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
config.setAllowedHeaders(List.of("*"));
config.setExposedHeaders(List.of("*"));
Expand Down
Loading