기존에는 코드 수정 시마다 직접 클라우드 인스턴스에 접속하여 수동으로 코드를 업데이트해야 했기 때문에 배포에 번거로움이 있었다. 이러한 과정을 자동화하고, 보다 빠르고 안정적인 배포를 위해 CI/CD 파이프라인을 도입하게 되었다.
CI/CD
CI(Continuous Integration) 지속 통합
지속적 통합은 개발자가 변경한 코드를 주기적으로 통합하고, 이를 자동으로 테스트하는 프로세스이다.
CD(Continuous Deployment / Continuous Delivery) 지속적 배포
지속적으로 통합된 코드를 자동으로 프로덕션 환경에 배포하는 프로세스이다.
예전에 docker를 학습하며 CI/CD를 이미 공부한 경험이 있어 이론 내용은 생략했다. https://byeongtil.tistory.com/88
GitHub Action
Travis CI, Jenkins 등 CI/CD 도구가 있지만 유료인 경유가 많다. Github Actions의 public repository은 무료로 사용할 수 있어 선택했다.
개발자가 변경한 코드를 주기적으로 통합하고, 이를 자동으로 테스트하는 프로세스를 의미한다.
FastAPI test 코드 작성
# test_main.py
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_teach_grades():
response = client.get("api/teach/grades")
assert response.status_code == 200
data = response.json()
print(data)
assert isinstance(data, list)
pytest 모듈을 사용해서 테스트를 진행한다.
처음에는 tests/test_main.py 경로에 테스트파일을 작성했지만 main에 있는 FastAPI의 app을 가져오지 못하는 에러가 발생했다.
문제발생
from .main import app
ImportError: attempted relative import with no known parent package
해결 방법은 main.py와 같은 디렉토리 경로에 test_main.py 파일이 존재해야 pytest 파일이 작동했다.
출력
============================================================== test session starts ==============================================================
platform darwin -- Python 3.13.2, pytest-8.3.5, pluggy-1.5.0
rootdir: /Users/gimbyeongmin/Desktop/project/cheese/backend
plugins: anyio-4.8.0
collected 1 item
test_main.py .
yml 파일 작성
name: CI/CD
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.13"
- name: Install dependencies
run: pip install -r backend/requirements.txt
- name: Set environment variable
run: |
echo "SQLALCHEMY_ASYNC_DATABASE_URL=${{ secrets.SQLALCHEMY_ASYNC_DATABASE_URL }}" >> $GITHUB_ENV
echo "OPENAI_API_KEY=${{ secrets.OPENAI_API_KEY }}" >> $GITHUB_ENV
- name: Run tests
run: |
cd backend
pytest
구성 요소
- name : 워크플로우 이름.
- on : 어떤 이벤트로 워크플로우를 실행할지 정의.
- jobs : 워크플로우 안의 각 작업 단위.
Test 작업 설정
jobs에는 실행할 작업의 이름을 작성해줘야한다. 또 어떤 환경에서 실행할지 설정을 해줘야한다.
jobs:
test:
runs-on: ubuntu-latest
1.Repository 체크아웃
이제 순차적으로 실행할 작업을 작성해준다.
GitHub Actions는 기본적으로 코드에 접근이 불가하여 uses 를 통해 현재 저장소의 소스코드를 가져오게 한다.
- name: Checkout repository
uses: actions/checkout@v3
2.Python 셋업
GitHub Actions 머신에 파이썬을 설치
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.13"
3.의존성 설치
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r backend/requirements.txt
현재 프로젝트의 의존 패키지들을 requirements.txt 기준으로 설치.
4. 테스트 실행
- name: Run tests
run: |
cd backend
pytest
문제 발생 1 : 들여쓰기
Invalid workflow file: .github/workflows/cicd.yml#L6
You have an error in your yaml syntax on line 6
yaml 파일의 경우 들여 쓰기가 매우 중요한데 해당 파일이 들여쓰기를 잘못해서 에러가 발생했다. 들여 쓰기를 수정해서 문제를 해결했다.
문제 발생 2 : .env
ERROR test_main.py - sqlalchemy.exc.ArgumentError: Expected string or URL object, got None
SQLALCHEMY_ASYNC_DATABASE_URL 값이 .env 파일에 정의되어 있고 코드를 통해 불러오지만 GitHub Actions에서는 .env 파일이 기본적으로 존재하지 않기 때문에 None이 된다.
해결 방법
GitHub Secrets를 사용해서 환경변수를 주입한다.
- name: Set environment variables
run: echo "SQLALCHEMY_ASYNC_DATABASE_URL=${{ secrets.SQLALCHEMY_ASYNC_DATABASE_URL }}" >> $GITHUB_ENV
문제발생 3 : database
FAILED test_main.py::test_teach_grades - sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: grades
[SQL: SELECT grades.id, grades.title
FROM grades ORDER BY grades.id]
(Background on this error at: <https://sqlalche.me/e/20/e3q8>)
데이터베이스를 테스트용인 SQLite 를 사용중이다. 하지만 해당 코드에서는 alembic를 이용해 데이터베디스 생성과 테이블을 생성하지 않아 문제가 발생했다.
해결 방법
CI/CD 적용 테슽를 위한 작업이라 “/” 경로의 간단한 접속 테스트를 진행 하는 것으로 마무리했다.
# main.py
@app.get("/")
async def read_main():
return {"msg": "Hello FastAPI"}
# test_main.py
def test_teach_grades():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"msg": "Hello FastAPI"}
참고
https://docs.github.com/en/actions
https://fastapi.tiangolo.com/tutorial/testing/#using-testclient
'Docker' 카테고리의 다른 글
GitHub Actions에서 Docker Build 캐싱 적용하기 (0) | 2025.04.14 |
---|---|
Docker와 GitHub Actions로 구축하는 CI/CD (2): 자동배포(CD) (0) | 2025.04.13 |
맥북 오라클 데이터베이스 연결 + Docker (0) | 2025.03.17 |
MySQL과 Docker를 활용한 오라클 클라우드 연결 (0) | 2025.02.26 |
Docker를 활용한 서버 배포 (4) : Docker-Compose로 Django 배포하기 (1) | 2024.12.31 |