Skip to content
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
65 changes: 42 additions & 23 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,65 @@ name: CD

on:
workflow_run:
workflows: ["CI with Gradle"] # CI 워크플로 이름과 정확히 일치해야 함
types: [completed] # CI가 끝났을 때 트리거
branches: [main] # 특정 브랜치에서만
workflows: ["CI with Gradle"]
types: [completed]
branches: [main]

permissions:
contents: read

env:
IMAGE: ${{ secrets.DOCKER_USERNAME }}/tokbaro
DOMAIN: tokbaro.com
EMAIL: tokbaro.conncet@gmail.com

jobs:
deploy:
name: Deploy to Server
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

# SSH로 서버에 접속해 배포
- name: Deploy over SSH
- name: Deploy to Server
uses: appleboy/ssh-action@v1.2.0
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
port: 22
script: |
echo "${{ secrets.ENV_FILE }}" > /home/${{ secrets.SERVER_USER }}/.env
echo "[1/3] Pull latest Docker image..."
docker pull ${{ env.IMAGE }}:latest

echo "[2/3] Restart container with new image..."
docker stop tokbaro || true
docker rm tokbaro || true
docker run -d --name tokbaro \
--env-file /home/${{ secrets.SERVER_USER }}/.env \
-p 8080:8080 \
-v /opt/apns/keys/AuthKey_R687V74YYB.p8:/app/keys/AuthKey.p8 \
${{ env.IMAGE }}:latest


echo "[3/3] Cleanup unused images..."
# 1. 서버에 미리 클론해둔 프로젝트 디렉토리로 이동합니다.
cd /home/${{ secrets.SERVER_USER }}/tokbaro

# 2. 최신 소스 코드를 pull 받습니다.
echo "Pulling latest source code..."
git pull origin main

# 3. GitHub Secret으로부터 .env 파일을 생성합니다.
echo "Creating .env file..."
echo "${{ secrets.ENV_FILE }}" > .env

# 4. docker-compose.yml에 정의된 최신 이미지들을 pull 받습니다.
echo "Pulling latest docker images from registry..."
docker-compose pull

# 5. 인증서 존재 여부 확인 및 발급/갱신 처리
CERT_DIR="/home/${{ secrets.SERVER_USER }}/tokbaro/nginx/letsencrypt/live/${{ env.DOMAIN }}"

if [ -d "$CERT_DIR" ]; then
# --- 인증서가 이미 있는 경우 ---
echo "Certificate found. Starting services and renewing..."
docker-compose up -d --build
docker-compose exec certbot renew --quiet
else
# --- 인증서가 없는 경우 (최초 배포) ---
echo "Certificate not found. Issuing a new one..."
# Certbot 단독 모드로 인증서 발급 (80번 포트를 직접 사용)
docker-compose run --rm certbot certonly --standalone \
--email ${{ env.EMAIL }} -d ${{ env.DOMAIN }} \
--rsa-key-size 4096 --agree-tos --non-interactive
# 모든 서비스를 시작
docker-compose up -d --build
fi

# 6. 불필요한 Docker 이미지를 정리합니다.
echo "Pruning unused docker images..."
docker image prune -f
72 changes: 72 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
version: "3.8"

services:
springboot-app:
build: .
container_name: tokbaro-app
depends_on:
- redis
ports:
- "8080:8080"
environment:
# Docker 내부 네트워크용 변수 (직접 할당)
- REDIS_HOST=redis
- REDIS_PORT=6379

# .env 파일 또는 GitHub Actions Secret으로부터 주입될 변수들
- DATABASE_URL=${DATABASE_URL}
- DATABASE_USERNAME=${DATABASE_USERNAME}
- DATABASE_PASSWORD=${DATABASE_PASSWORD}
- JWT_SECRET_KEY=${JWT_SECRET_KEY}
- JWT_ACCESS_EXPIRATION=${JWT_ACCESS_EXPIRATION}
- JWT_REFRESH_EXPIRATION=${JWT_REFRESH_EXPIRATION}
- APNS_TEAM_ID=${APNS_TEAM_ID}
- APNS_KEY_ID=${APNS_KEY_ID}
- APNS_BUNDLE_ID=${APNS_BUNDLE_ID}
- APNS_P8_FILE=${APNS_P8_FILE} # .env 파일에 컨테이너 내부 경로로 지정 필요
- APPLE_CLIENT_ID=${APPLE_CLIENT_ID}
volumes:
# 서버의 절대 경로(/home/ubuntu/secure/keys)를 컨테이너의 /app/keys로 마운트합니다.
# EC2 유저명이 ubuntu가 아닌 경우 경로를 수정해야 합니다.
- /home/ubuntu/secure/keys:/app/keys
networks:
- tokbaro-network

redis:
image: redis:7-alpine
container_name: tokbaro-redis
ports:
- "6379:6379"
networks:
- tokbaro-network

nginx:
image: nginx:stable-alpine
container_name: tokbaro-nginx
depends_on:
- springboot-app
ports:
- "80:80"
- "443:443" # HTTPS를 위한 443 포트 추가
volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
# Let's Encrypt 인증서 공유를 위한 볼륨 추가
- ./nginx/letsencrypt:/etc/letsencrypt
# Let's Encrypt 도메인 인증용 파일 공유를 위한 볼륨 추가
- ./nginx/www:/var/www/certbot
networks:
- tokbaro-network

# Certbot 서비스 추가
certbot:
image: certbot/certbot
container_name: tokbaro-certbot
volumes:
# Let's Encrypt 인증서 공유
- ./nginx/letsencrypt:/etc/letsencrypt
# Let's Encrypt 도메인 인증용 파일 공유
- ./nginx/www:/var/www/certbot

networks:
tokbaro-network:
driver: bridge
41 changes: 41 additions & 0 deletions nginx/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# /nginx/nginx.conf (수정안)

# 1. HTTP 서버 (포트 80)
server {
listen 80;
# 여기에 사용자님의 도메인을 적어주세요.
server_name tokbaro.com;

# Let's Encrypt 소유권 확인 요청 처리
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}

# 나머지 모든 요청은 HTTPS로 리다이렉트
location / {
return 301 https://$host$request_uri;
}
}

# 2. HTTPS 서버 (포트 443)
server {
listen 443 ssl;
# 여기에 사용자님의 도메인을 적어주세요.
server_name tokbaro.com;

# SSL 인증서 경로 설정
ssl_certificate /etc/letsencrypt/live/tokbaro.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/tokbaro.com/privkey.pem;
# 최신 SSL 옵션 (권장)
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

# Spring Boot 백엔드로 요청 프록시
location / {
proxy_pass http://springboot-app:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}