Skip to content

dev to main

dev to main #202

Workflow file for this run

name: CI/CD Pipeline
on:
push:
branches:
- main
pull_request:
branches:
- dev
- main
jobs:
# CI, main과 dev로 pr 날리면 발생
ci:
name: Build and Test
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
cache: 'gradle'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
# firebase CI 설정
- name: Create Firebase credential file
run: |
mkdir -p src/main/resources/firebase
echo "${{ secrets.FIREBASE_CREDENTIALS }}" | base64 -d > src/main/resources/firebase/nuvibe-web-firebase.json
if [ ! -s src/main/resources/firebase/nuvibe-web-firebase.json ]; then
echo "Error: Firebase credential file is empty or not created"
exit 1
fi
- name: Run tests
run: ./gradlew test
# CD, main에 push하면 발생, 도커 이미지 생성 후 배포
cd:
name: Build and Deploy
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
cache: 'gradle'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
# firebase CD 설정
- name: Create Firebase credential file
run: |
mkdir -p src/main/resources/firebase
echo "${{ secrets.FIREBASE_CREDENTIALS }}" | base64 -d > src/main/resources/firebase/nuvibe-web-firebase.json
if [ ! -s src/main/resources/firebase/nuvibe-web-firebase.json ]; then
echo "Error: Firebase credential file is empty or not created"
exit 1
fi
- name: Build with Gradle
run: ./gradlew build -x test
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/nuvibe:latest
- name: Deploy to EC2
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.EC2_HOST }}
username: ubuntu
key: ${{ secrets.EC2_SSH_KEY }}
envs: AWS_ACCESS_KEY,AWS_S3_BUCKET,AWS_SECRET_KEY,DOCKERHUB_USERNAME,FRONT_URL,GMAIL_ADDRESS,GMAIL_PASSWORD,JWT_ACCESS_TOKEN_VALIDITY,JWT_REFRESH_TOKEN_VALIDITY,JWT_SECRET_KEY,PROD_DB_PASSWORD,PROD_DB_URL,PROD_DB_USERNAME,SERVER_URL,FIREBASE_CREDENTIALS_PATH,AWS_QUEUE_NAME,NAVER_CLIENT_ID,NAVER_CLIENT_SECRET,KAKAO_CLIENT_ID,KAKAO_CLIENT_SECRET,GOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET
script: |
# 배포 디렉토리 생성
mkdir -p /home/ubuntu/nuvibe
cd /home/ubuntu/nuvibe
# Nginx 설정 디렉토리 생성
mkdir -p nginx/conf.d certbot/conf certbot/www logs
# Git에서 Nginx 설정 파일 다운로드
curl -f -o nginx/nginx.conf https://raw.githubusercontent.com/Team-Nuvibe/BE/main/nginx/nginx.conf
curl -f -o nginx/conf.d/default.conf https://raw.githubusercontent.com/Team-Nuvibe/BE/main/nginx/conf.d/default.conf
# docker-compose.yml 생성 (Nginx + Certbot 포함)
cat << 'COMPOSE_EOF' > docker-compose.yml
version: '3.8'
services:
app:
image: ${DOCKERHUB_USERNAME}/nuvibe:latest
container_name: nuvibe-app
expose:
- "8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
# AWS 설정
- AWS_ACCESS_KEY=${AWS_ACCESS_KEY}
- AWS_S3_BUCKET=${AWS_S3_BUCKET}
- AWS_SECRET_KEY=${AWS_SECRET_KEY}
- AWS_QUEUE_NAME=${AWS_QUEUE_NAME}
# DB 설정
- PROD_DB_PASSWORD=${PROD_DB_PASSWORD}
- PROD_DB_URL=${PROD_DB_URL}
- PROD_DB_USERNAME=${PROD_DB_USERNAME}
# JWT 설정
- JWT_ACCESS_TOKEN_VALIDITY=${JWT_ACCESS_TOKEN_VALIDITY}
- JWT_REFRESH_TOKEN_VALIDITY=${JWT_REFRESH_TOKEN_VALIDITY}
- JWT_SECRET_KEY=${JWT_SECRET_KEY}
# 메일 설정
- GMAIL_ADDRESS=${GMAIL_ADDRESS}
- GMAIL_PASSWORD=${GMAIL_PASSWORD}
- SERVER_URL=${SERVER_URL}
# Frontend 설정
- FRONT_URL=${FRONT_URL}
# Firebase 설정
- FIREBASE_CREDENTIALS_PATH=${FIREBASE_CREDENTIALS_PATH}
# OAuth2 설정
- NAVER_CLIENT_ID=${NAVER_CLIENT_ID}
- NAVER_CLIENT_SECRET=${NAVER_CLIENT_SECRET}
- KAKAO_CLIENT_ID=${KAKAO_CLIENT_ID}
- KAKAO_CLIENT_SECRET=${KAKAO_CLIENT_SECRET}
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
- GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
networks:
- nuvibe-network
restart: unless-stopped
volumes:
- ./logs:/logs
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
nginx:
image: nginx:alpine
container_name: nuvibe-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- ./certbot/conf:/etc/letsencrypt:ro
- ./certbot/www:/var/www/certbot:ro
networks:
- nuvibe-network
depends_on:
- app
restart: unless-stopped
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
certbot:
image: certbot/certbot
container_name: nuvibe-certbot
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
entrypoint: >-
/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'
networks:
- nuvibe-network
restart: unless-stopped
networks:
nuvibe-network:
driver: bridge
COMPOSE_EOF
# 최신 이미지 Pull
sudo -E docker pull ${DOCKERHUB_USERNAME}/nuvibe:latest
# 기존 컨테이너 중지 및 재시작
sudo -E docker compose down
sudo -E docker compose up -d
# 사용하지 않는 이미지 정리
sudo docker image prune -f
echo "Deployment completed at $(date)"
env:
AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }}
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
AWS_SECRET_KEY: ${{ secrets.AWS_SECRET_KEY }}
AWS_QUEUE_NAME: ${{ secrets.AWS_QUEUE_NAME }}
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
FRONT_URL: ${{ secrets.FRONT_URL }}
GMAIL_ADDRESS: ${{ secrets.GMAIL_ADDRESS }}
GMAIL_PASSWORD: ${{ secrets.GMAIL_PASSWORD }}
JWT_ACCESS_TOKEN_VALIDITY: ${{ secrets.JWT_ACCESS_TOKEN_VALIDITY }}
JWT_REFRESH_TOKEN_VALIDITY: ${{ secrets.JWT_REFRESH_TOKEN_VALIDITY }}
JWT_SECRET_KEY: ${{ secrets.JWT_SECRET_KEY }}
PROD_DB_PASSWORD: ${{ secrets.PROD_DB_PASSWORD }}
PROD_DB_URL: ${{ secrets.PROD_DB_URL }}
PROD_DB_USERNAME: ${{ secrets.PROD_DB_USERNAME }}
SERVER_URL: ${{ secrets.SERVER_URL }}
FIREBASE_CREDENTIALS_PATH: ${{ secrets.FIREBASE_CREDENTIALS_PATH }}
NAVER_CLIENT_ID: ${{ secrets.NAVER_CLIENT_ID }}
NAVER_CLIENT_SECRET: ${{ secrets.NAVER_CLIENT_SECRET }}
KAKAO_CLIENT_ID: ${{ secrets.KAKAO_CLIENT_ID }}
KAKAO_CLIENT_SECRET: ${{ secrets.KAKAO_CLIENT_SECRET }}
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }}