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
85 changes: 85 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: CD

on:
push:
branches:
- main

jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: 코드 체크아웃
uses: actions/checkout@v4

- name: 이미지 태그 생성
id: vars
run: echo "tag=${GITHUB_SHA}" >> $GITHUB_OUTPUT

- name: 이미지 경로 생성
run: |
REPO_LOWER=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
echo "IMAGE_NAME=ghcr.io/${REPO_LOWER}/backend" >> $GITHUB_ENV

- name: GHCR 로그인
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin

- name: QEMU 설정
uses: docker/setup-qemu-action@v3

- name: Buildx 설정
uses: docker/setup-buildx-action@v3

- name: 멀티 아키텍처 이미지 빌드 및 푸시
run: |
docker buildx build \
--platform linux/amd64,linux/arm64 \
-f Dockerfile \
-t $IMAGE_NAME:${{ steps.vars.outputs.tag }} \
-t $IMAGE_NAME:latest \
--push \
.

- name: 서버에 배포 디렉토리 생성
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_KEY }}
port: ${{ secrets.DEPLOY_PORT }}
script: |
mkdir -p ~/teampling

- name: 배포 파일 전송
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_KEY }}
port: ${{ secrets.DEPLOY_PORT }}
source: "docker-compose.prod.yaml,nginx.conf"
target: "~/teampling"

- name: 서버 배포 실행
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_KEY }}
port: ${{ secrets.DEPLOY_PORT }}
script: |
cd /home/${{ secrets.DEPLOY_USER }}/teampling

export IMAGE_TAG=${{ steps.vars.outputs.tag }}

docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GHCR_PAT }}

docker compose -f docker-compose.prod.yaml pull app
docker compose -f docker-compose.prod.yaml run --rm app alembic upgrade head
docker compose -f docker-compose.prod.yaml up -d app nginx

docker image prune -f
63 changes: 63 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: CI

on:
pull_request:
push:
branches: [develop, main]

jobs:
test:
runs-on: ubuntu-latest

services:
postgres:
image: postgres:16
env:
POSTGRES_DB: testdb
POSTGRES_USER: testuser
POSTGRES_PASSWORD: testpass
ports:
- 5432:5432
options: >-
--health-cmd="pg_isready -U testuser -d testdb"
--health-interval=5s
--health-timeout=5s
--health-retries=10

env:
PYTHONPATH: ${{ github.workspace }}
APP_ENV: test
APP_NAME: teampling-test
POSTGRES_DB: testdb
POSTGRES_USER: testuser
POSTGRES_PASSWORD: testpass
POSTGRES_HOST: localhost
POSTGRES_PORT: "5432"

steps:
- name: 코드 체크아웃
uses: actions/checkout@v4

- name: 파이썬 환경 설정
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: 의존성 설치
run: |
pip install poetry
poetry config virtualenvs.create false
poetry install --no-interaction --no-ansi

- name: 테스트 실행
env:
DATABASE_URL: postgresql+psycopg://testuser:testpass@localhost:5432/testdb
run: pytest -q

- name: Alembic 마이그레이션 테스트
env:
DATABASE_URL: postgresql+psycopg://testuser:testpass@localhost:5432/testdb
run: alembic upgrade head

- name: 도커 빌드 테스트
run: docker build -f Dockerfile -t backend:test .
23 changes: 14 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
FROM python:3.12-slim

RUN pip install poetry
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

WORKDIR /teampling
WORKDIR /app

RUN pip install --no-cache-dir --upgrade pip
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
libpq-dev \
curl \
&& rm -rf /var/lib/apt/lists/*

COPY pyproject.toml poetry.lock ./
COPY pyproject.toml poetry.lock* /app/

RUN poetry config virtualenvs.create false
RUN pip install --no-cache-dir poetry && \
poetry config virtualenvs.create false && \
poetry install --only main --no-interaction --no-ansi

RUN poetry install --no-root --only main
COPY . /app

COPY . .

EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
17 changes: 8 additions & 9 deletions app/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def LOCAL_DATABASE_URL(self) -> str:
)

# JWT / AUTH
JWT_SECRET: str
JWT_SECRET: str = ""
JWT_ALG: str = "HS256"
ACCESS_TOKEN_MINUTES: int = 30
REFRESH_TOKEN_DAYS: int = 14
Expand All @@ -52,13 +52,12 @@ def LOCAL_DATABASE_URL(self) -> str:
LOG_LEVEL: str = "INFO"

# Oracle Cloud Storage
OCI_USER_OCID: str
OCI_API_KEY_PATH: str
OCI_FINGERPRINT: str
OCI_TENANCY_OCID: str
OCI_REGION: str

OCI_OBJECT_STORAGE_NAMESPACE: str
OCI_OBJECT_STORAGE_BUCKET: str
OCI_USER_OCID: str = ""
OCI_API_KEY_PATH: str = ""
OCI_FINGERPRINT: str = ""
OCI_TENANCY_OCID: str = ""
OCI_REGION: str = ""
OCI_OBJECT_STORAGE_NAMESPACE: str = ""
OCI_OBJECT_STORAGE_BUCKET: str = ""

settings = Settings()
45 changes: 45 additions & 0 deletions docker-compose.prod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
services:
db:
image: postgres:16
container_name: teampling-db
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 10
restart: always

app:
image: ghcr.io/teampling/backend_main/backend:${IMAGE_TAG}
container_name: teampling-app
env_file:
- .env
depends_on:
db:
condition: service_healthy
expose:
- "8000"
restart: always

nginx:
image: nginx:stable-alpine
container_name: teampling-nginx
depends_on:
- app
ports:
- "80:80"
# - "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
# - ./certbot/conf:/etc/letsencrypt
# - ./certbot/www:/var/www/certbot
restart: always

volumes:
postgres_data:
2 changes: 1 addition & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ services:
ports:
- "8000:8000"
volumes:
- ./app:/teampling/app # 코드 바뀌면 바로 반영(개발용)
- ./app:/app/app
command: >
uvicorn app.main:app
--host 0.0.0.0
Expand Down
24 changes: 24 additions & 0 deletions nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
events {}

http {
upstream backend {
server app:8000;
}

server {
listen 80;
server_name _;

client_max_body_size 20M;

location / {
proxy_pass http://backend;
proxy_http_version 1.1;

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;
}
}
}
Loading