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

Release:v1.0.0-beta.6 #38

Merged
merged 1 commit into from
Jan 15, 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
85 changes: 53 additions & 32 deletions .github/workflows/gradle-prod.yml
Original file line number Diff line number Diff line change
@@ -1,56 +1,59 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle

# 워크플로우 이름
name: CI/CD

# 어떤 브랜치에서, 어떤 행동이 일어날 때 ci/cd가 일어날 것인지를 설정
# workflow가 작동될 branch와, 작동시킬 trigger 설정
on:
pull_request:
types: [ closed ] # pr이 닫혔을 경우
types: [ closed ]
branches: [ "main" ]

# 워크플로우가 깃 레포에 대한 권한을 읽기 만 가능하게 설정
# git repo에 대해 읽기 권한만 부여
permissions:
contents: read

# 워크플로우에서 할 작업 정의
# workflow에서 실행할 작업 정의
jobs:
CI-CD:
# 작업 환경 = 우분투 최신 버전
runs-on: ubuntu-latest
# PR이 merge된 경우에만 실행
if: github.event.pull_request.merged == true
# ubuntu 24.04 환경에서 실행
runs-on: ubuntu-24.04

# 깃허브에서 제공하는 checkout 액션 사용
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

# jdk 17 설정
# JDK 17 설정
- name: Set up JDK 17
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
java-version: '17'
# temurin = Adoptium에서 제공하는 JDK
distribution: 'temurin'

# gradle caching - 캐싱을 통한 빌드 시간 향상 (젠킨스에서는 기본 동작하지만, 깃액션은 직접 설정해줘야함)
# Gradle 캐싱 설정
- name: Gradle Caching
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
${{ runner.os }}-gradle-

# 도커 레이어 캐싱 설정
## Buildx 설정 (효율적인 캐싱을 위한 도커 빌더)
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
## 캐시 저장소 설정
- name: Cache Docker layers
uses: actions/cache@v4
with:
path: /tmp/.buildx-cache # 캐시가 저장될 경로
key: ${{ runner.os }}-buildx-${{ github.sha }} # 캐시 식별자
restore-keys: | # 일치하는 캐시가 없을 때 사용할 이전 캐시
${{ runner.os }}-buildx-

# application-prod.yml 생성
# touch : 파일을 생성
# echo + > : '>'는 기존에 동일한 이름의 파일이 없다면 생성하고, 동일한 파일이 있다면 새로운 파일로 덮어쓰기 한다
# echo + >> : '>>'를 사용하면 기존에 파일이 없다면 생성하고, 동일한 파일이 있다면 파일 내부에 새로운 내용을 추가하는 방식으로 동작
- name: make application-prod.yml
run: |
mkdir -p ./src/main/resources
Expand All @@ -60,20 +63,19 @@ jobs:
shell: bash

# gradle wrapper 파일에 실행 권한을 부여
# gradle wrapper = 개발자가 특정 버전의 Gradle을 미리 설치하지 않고도 Gradle 빌드를 실행할 수 있게 해주는 편리한 도구
# (gradle wrapper = 개발자가 특정 버전의 Gradle을 미리 설치하지 않고도 Gradle 빌드를 실행할 수 있게 해주는 편리한 도구)
- name: Grant execute permission for gradlew
run: chmod +x gradlew

# Gradle 빌드 액션을 이용해서 프로젝트 빌드
# 프로젝트 build: -x test 옵션을 사용하면 테스트 없이 빌드
- name: Build with Gradle
# -x test 옵션을 사용하면, 테스트 없이 빌드 -> 테스트 사용하도록 변경
run: ./gradlew build -i -x test

# 도커 이미지 빌드 & 이미지를 도커허브로 push
## DOCKER_PASSWORD: 도커 허브 Token
## DOCKER_USERNAME: 도커 허브 유저네임
## PRODUCTION_REPO: 도커 허브 레포지토리 이름
- name: Docker build & push to dockerhub
# -f 뒤에는 도커파일 명을, /뒤에는 도커허브 저장소 명을 적는다
# 이메일 회원가입을 진행했다면, DOCKER_PASSWORD에는 token값을 적으면 된다
# 도커 유저네임에는 도커허브 이름을 적는다(이메일이 아님)
run: |
echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
docker build --build-arg PROFILE=prod -t ${{ secrets.DOCKER_USERNAME }}/${{ secrets.PRODUCTION_REPO }}:${{ github.run_number }} .
Expand All @@ -84,9 +86,11 @@ jobs:
uses: appleboy/ssh-action@master
id: deploy-prod
with:
host: ${{ secrets.PRODUCTION_HOST_EC2 }} # EC2 퍼블릭 IPv4 DNS
# EC2 Public IP
host: ${{ secrets.PRODUCTION_HOST_EC2 }}
username: ubuntu
key: ${{ secrets.EC2_PRIVATE_KEY }} # ec2접속 pem key
# EC2 ssh 접속 pem-key
key: ${{ secrets.EC2_PRIVATE_KEY }}
envs: GITHUB_SHA
script: |
sudo docker login -u "${{ secrets.DOCKER_USERNAME }}" -p "${{ secrets.DOCKER_PASSWORD }}"
Expand All @@ -95,4 +99,21 @@ jobs:
sudo docker rm "${{ secrets.SERVICE_NAME }}" || true
sudo docker pull "${{ secrets.DOCKER_USERNAME }}"/"${{ secrets.PRODUCTION_REPO }}":"${{ github.run_number }}"
sudo docker run -d --name "${{ secrets.SERVICE_NAME }}" -p "${{ secrets.PRODUCTION_SERVICE_PORT }}":"${{ secrets.PRODUCTION_SERVICE_PORT }}" --network "${{ secrets.PRODUCTION_DOCKER_NETWORK }}" "${{ secrets.DOCKER_USERNAME }}"/"${{ secrets.PRODUCTION_REPO }}":"${{ github.run_number }}"
sudo docker image prune -a -f

# 배포 실패시 롤백
- name: Rollback on failure
if: failure() && steps.deploy-prod.outcome == 'failure'
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.PRODUCTION_HOST_EC2 }}
username: ubuntu
key: ${{ secrets.EC2_PRIVATE_KEY }}
script: |
sudo docker login -u "${{ secrets.DOCKER_USERNAME }}" -p "${{ secrets.DOCKER_PASSWORD }}"
sudo docker ps
sudo docker stop "${{ secrets.SERVICE_NAME }}" || true
sudo docker rm "${{ secrets.SERVICE_NAME }}" || true
sudo docker pull "${{ secrets.DOCKER_USERNAME }}"/"${{ secrets.PRODUCTION_REPO }}":$((${github.run_number}-1))
sudo docker run -d --name "${{ secrets.SERVICE_NAME }}" -p "${{ secrets.PRODUCTION_SERVICE_PORT }}":"${{ secrets.PRODUCTION_SERVICE_PORT }}" --network "${{ secrets.PRODUCTION_DOCKER_NETWORK }}" "${{ secrets.DOCKER_USERNAME }}"/"${{ secrets.PRODUCTION_REPO }}":$((${github.run_number}-1))
sudo docker image prune -a -f
26 changes: 20 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
# server를 위한 dockerfile
# 멀티 스테이지 빌드를 사용한 Spring Boot 애플리케이션 Dockerfile

# 1단계: 빌드 스테이지(FROM: jdk 이미지 레이어, COPY: 빌드 파일 및 소스 코드 복사, RUN: Gradle 빌드 실행)
## 'openjdk:17-alpine linux' 이미지를 빌드 스테이지의 베이스 이미지로 사용, 'builder'라는 별칭 부여
FROM openjdk:17-alpine AS builder
COPY gradlew .
## Working Directory 설정
WORKDIR /app
## 소스 코드 복사 (의존성 캐싱을 위해 build.gradle, settings.gradle, gradle, gradlew 먼저 복사)
COPY build.gradle settings.gradle ./
COPY gradle gradle
COPY build.gradle .
COPY settings.gradle .
COPY gradlew .
RUN ./gradlew dependencies
COPY src src
## Gradle Wrapper에 실행 권한 부여
RUN chmod +x ./gradlew
## Gradle 빌드
RUN ./gradlew bootJAR

# 2단계: 실행 스테이지
## 'openjdk:17-alpine linux' 이미지를 실행 스테이지의 베이스 이미지로 사용
FROM openjdk:17-alpine
## Working Directory 설정
WORKDIR /app
## 빌드 스테이지에서 생성된 JAR 파일을 복사
COPY --from=builder build/libs/*.jar app.jar
# 이미지 빌드시에 사용되는 Build-time variable을 정의: docker build에서 --build-arg로 변수를 전달
## 빌드 시 전달받은 프로필 값을 환경변수로 설정
ARG PROFILE
# 이미지 실행시에 사용되는 환경변수를 정의: 컨테이너가 실행될 때 사용되는 환경변수
ENV PROFILE=${PROFILE}

# 3단계: 컨테이너 실행 명령어 설정
## JVM 타임존을 서울로 설정, Spring Profile 설정, JAR 파일 실행
ENTRYPOINT ["java","-jar", "-Duser.timezone=Asia/Seoul", "-Dspring.profiles.active=${PROFILE}", "/app.jar"]
Loading