Python for AI, Embedded/Python: Core & Automation

파이썬(Python) 애플리케이션 CI/CD 가이드: GitHub Actions 워크플로우 설정부터 Flask 도커(Docker) 빌드 및 자동 배포까지

임베디드 친구 2025. 7. 8. 19:42
반응형

지난 시간까지 우리는 완성된 코드가 예기치 않게 망가지는 것을 막아주는 유닛 테스트 기법과 전 세계 사용자가 내 코드를 내려받을 수 있도록 PyPI에 등록하는 패키징 기술을 함께 살펴보았습니다. 이제 한 단계 더 나아가 코드를 수정하고 배포하는 이 모든 일련의 과정을 사람이 수동으로 하는 것이 아니라, 소스코드 저장소에 git push 명령어 한 줄만 날리면 시스템이 알아서 검증하고 빌드하여 서버에 얹어주는 '자동화의 꽃', 바로 CI/CD 파이프라인을 구축해 볼 시간입니다. 매번 코드를 바꿀 때마다 컴퓨터에서 테스트를 직접 돌리고, 도커 이미지를 빌드하고, 서버에 접속해 컨테이너를 재시작하는 과정은 번거로울뿐더러 실수가 끼어들기 딱 좋습니다. 오늘 소프트웨어 공장에서는 GitHub Actions를 도구로 삼아 파이썬 소스코드를 자동으로 격리 테스트하고, 가볍고 단단한 도커(Docker) 컨테이너로 말아 올려 배포 허브까지 안전하게 배달하는 자동화 파이프라인의 실무 설계를 낱낱이 가르쳐 드리겠습니다.

Generated by Gemini AI.

📌 핵심 요약 3줄

  • CI(지속적 통합)는 개발자가 푸시한 코드를 가상 환경에서 자동으로 빌드하고 pytest 등으로 테스트하여 코드 저장소의 청정 상태를 유지하는 기술입니다.
  • CD(지속적 배포)는 검증이 완료된 소스코드를 상용 도커 이미지 등으로 자동 패키징하여 무중단으로 운영 서버에 밀어 넣는 인프라 프로세스입니다.
  • GitHub Actions의 .github/workflows/*.yml 스크립트를 활용하면 별도의 Jenkins 서버를 띄우지 않고도 클라우드 환경에서 완벽한 자동화 파이프라인을 구동할 수 있습니다.

1. 한눈에 보는 CI/CD 핵심 개념 및 GitHub Actions 컴포넌트

자동화 파이프라인을 설계하기 전 머릿속에 반드시 넣어두어야 할 핵심 개념과 스크립트 구성 요소를 표로 정리했습니다.

① CI와 CD의 역할 및 목적 비교

단계 약어 정의 핵심 역할 및 수행 작업 최종 목표
지속적 통합

(CI)
Continuous Integration * 코드 병합 시 자동 빌드 수행

* pytest를 통한 유닛 테스트 실행

* 코드 정적 분석 및 린팅(Linting) 체크
개발자들이 작성한 소스코드의 결함을 조기에 발견하고 형상 관리 저장소의 오염 방지
지속적 배포

(CD)
Continuous Deployment * 소스코드의 도커(Docker) 이미지화

* 컨테이너 레지스트리(Docker Hub 등) 푸시

* 클라우드/쿠버네티스 환경 갱신 및 롤아웃
사람이 개입하는 수동 배포의 실수를 제로(0)로 만들고, 신규 기능을 고객에게 초고속으로 릴리스

② GitHub Actions 워크플로우(yml) 핵심 키워드 요약

설정 키워드 역할 및 기능 실무 활용 팁
on: 파이썬 파이프라인을 가동할 트리거(이벤트)를 정의 main 브랜치에 push 되거나 pull_request가 열릴 때 매핑
runs-on: 빌드와 테스트를 수행할 가상의 컴퓨터 운영체제를 지정 일반적으로 리눅스 환경인 ubuntu-latest를 가장 많이 채택
uses: 이미 만들어진 검증된 외부 액션(플러그인)을 가져와 사용 코드 체크아웃(actions/checkout), 파이썬 세팅(actions/setup-python) 등
run: 가상 머신 터미널 창에 직접 쉘 명령어를 실행 pip install -r requirements.txt나 pytest 같은 실무 명령 하달
${{ secrets.* }} 도커 허브 비밀번호나 API 키 등 노출되면 안 되는 보안 데이터 처리 GitHub 레포지토리 Settings -> Secrets 메모리에 저장 후 안전하게 호출

2. 실전 파이썬 테스트 자동화(CI) 스크립트 구현

가장 먼저 우리가 만든 Flask 웹 애플리케이션의 연산 로직에 하자가 없는지 검증하는 기본적인 유닛 테스트 코드와, 이를 감시하는 GitHub Actions CI 설정입니다.

테스트 대상 소스코드 및 검증 파일 (test_app.py)

Python
 
import unittest

def calculate_uptime(days):
    return days * 24

class TestServerLogOperations(unittest.TestCase):
    def test_uptime_conversion(self):
        # 서버 가동 시간 계산 로직이 정확히 도는지 확인합니다.
        self.assertEqual(calculate_uptime(2), 48)
        self.assertEqual(calculate_uptime(0), 0)

if __name__ == "__main__":
    unittest.main()

저장소 루트에 배치할 워크플로우 파일 (.github/workflows/ci.yml)

YAML
 
name: Python App Continuous Integration

# main 브랜치로 무언가 흘러 들어오면 무조건 이 감시 파이프라인을 작동시킵니다.
on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:
  test-pipeline:
    runs-on: ubuntu-latest

    steps:
    # 1. 깃허브 저장소에 있는 우리 코드를 가상 우분투 컴퓨터로 통째로 복사해 옵니다.
    - name: 소스코드 체크아웃
      uses: actions/checkout@v3

    # 2. 테스트를 안정적으로 돌릴 파이썬 순정 환경을 구축합니다.
    - name: 파이썬 3.10 가동 환경 세팅
      uses: actions/setup-python@v4
      with:
        python-version: '3.10'

    # 3. 가상 가상환경 위에 필요한 패키지들을 싹 다 다운로드합니다.
    - name: 종속성 라이브러리 설치
      run: |
        python -m pip install --upgrade pip
        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
        pip install pytest

    # 4. 미리 짜둔 유닛 테스트를 무인으로 실행합니다. 에러가 나면 여기서 파이프라인이 중단됩니다.
    - name: pytest 엔진 구동
      run: |
        pytest test_app.py

3. 확장 매커니즘: Flask 애플리케이션 도커 빌드 및 배포 자동화(CD)

테스트를 무사히 통과했다면, 이제 파이썬 웹 서비스 코드를 도커 파일 기반의 이미지로 압축하여 도커 레지스트리 허브에 자동으로 업로드하는 고도화된 CD 자동화 트리거를 세팅해 보겠습니다.

배포할 경량 Flask 서버 소스코드 (main.py)

Python
 
from flask import Flask

app = Flask(__name__)

@app.route('/')
def home():
    # 사용자가 접속했을 때 마주할 메인 엔드포인트 화면입니다.
    return "안녕하세요, 소프트웨어 공장 CI/CD 엔진이 완벽하게 가동 중입니다!"

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=5000)

프로젝트 패키징을 위한 도커 명세서 (Dockerfile)

Dockerfile
 
FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["python", "main.py"]

자동 빌드 및 이미지 푸시 스크립트 (.github/workflows/cd.yml)

YAML
 
name: Docker Build and Continuous Deployment

on:
  push:
    branches: [ "main" ]

jobs:
  deploy-pipeline:
    runs-on: ubuntu-latest

    steps:
    - name: 소스코드 체크아웃
      uses: actions/checkout@v3

    # 가상 머신에 도커 빌드를 고속으로 수행할 레이아웃 가상 엔진을 탑재합니다.
    - name: Docker Buildx 세팅
      uses: docker/setup-buildx-action@v2

    # 보안을 위해 아이디와 패스워드는 레포지토리 암호화 변수(Secrets)를 매핑해 가져옵니다.
    - name: Docker Hub 로그인 진행
      uses: docker/login-action@v2
      with:
        username: ${{ secrets.DOCKER_USERNAME }}
        password: ${{ secrets.DOCKER_PASSWORD }}

    # 빌드가 끝난 컨테이너 이미지를 내 도커 헙 저장소로 강제로 밀어 올립니다(push).
    - name: 도커 이미지 빌드 및 레지스트리 푸시
      uses: docker/build-push-action@v4
      with:
        context: .
        tags: ${{ secrets.DOCKER_USERNAME }}/flask-factory-app:latest
        push: true

4. 개발을 위한 팁

  • 환경 변수나 접속용 비밀키는 절대 소스코드나 yml에 하드코딩하지 마세요: 데이터베이스 패스워드나 클라우드 액세스 토큰, 도커 허브 비밀번호 같은 민감 자료들을 소스코드나 GitHub Actions yml 파일에 날것 그대로 적어 올리면 퍼블릭 저장소일 경우 전 세계에 내 보안 자산이 유출되는 대참사가 벌어집니다. 반드시 해당 GitHub 저장소의 Settings -> Secrets and variables -> Actions 메뉴로 이동하여 Key-Value 형태로 안전하게 등록해 두세요. 스크립트 내부에서 ${{ secrets.MY_SECRET_KEY }} 꼴로 호출하면, 배포 로그 창에서도 비밀번호 패스워드가 별표(***)로 자동 마스킹되어 안전하게 통제할 수 있습니다.
  • 빌드 속도를 비약적으로 높여주는 캐싱(Caching) 레이어를 확보하세요: 파이프라인이 트리거될 때마다 매번 수십 메가바이트에 달하는 파이썬 외부 패키지(requirements.txt)를 인터넷에서 새로 다운로드하는 구조는 자원 낭비일뿐더러 전체 배포 시간을 늘리는 주범입니다. actions/setup-python 플러그인에는 자체 캐싱 옵션이 존재합니다. 아래와 같이 cache: 'pip' 설정을 넣어주면 가상 머신이 기존에 다운로드해 둔 패키지 압축 파일을 재사용하므로 배포 주기를 절반 이상 단축할 수 있습니다.
YAML
 
# [빌드 캐싱을 적용한 고속 파이썬 세팅 예시]
- name: Set up Python with Cache
  uses: actions/setup-python@v4
  with:
    python-version: '3.10'
    cache: 'pip' # requirements.txt가 바뀌지 않았다면 이전 빌드 메모리를 재활용합니다.

5. 흔히 하는 실수

  • requirements.txt 최신화 누락으로 가상 머신 빌드가 터지는 현상: 내 로컬 컴퓨터에서는 외부 라이브러리를 잔뜩 설치해 두고 코드가 잘 돌아가니까 그대로 git push를 때려버리는 실수를 자주 목격합니다. 하지만 GitHub Actions 가상 머신은 완전히 백지상태의 리눅스에서 출발하기 때문에, 내 프로젝트에 명세서 격인 requirements.txt 파일이 없거나 최신 설치 본이 누락되어 있으면 라이브러리를 찾지 못해 ModuleNotFoundError를 뿜어내며 빌드가 즉시 깨집니다. 패키지를 새로 설치할 때마다 터미널에 pip freeze > requirements.txt 명령을 수행하여 명세서를 동기화해 주는 버릇을 들여야 파이프라인이 멈추지 않습니다.
  • 도커 빌드 컨텍스트 경로 지정 오류로 인한 파일 실종 사건: CD 파이프라인을 작성할 때 docker/build-push-action 플러그인의 context: 항목을 엉뚱한 경로로 지정하거나 점(.) 누락을 범하는 경우가 많습니다. 컨텍스트를 현재 폴더인 점(.)으로 명시해 주어야 도커 데몬이 내 프로젝트 폴더 안의 소스코드와 Dockerfile을 통째로 인식하여 컨테이너 내부에 집어넣습니다. 만약 이 경로 지정이 꼬이게 되면 도커 레이어를 쌓는 과정에서 COPY failed: no source files were specified 에러를 직면하며 배포 스케줄이 완전히 마비되니 각별히 유의해야 합니다.

💡 맺음말

이번 포스팅에서는 파이썬 개발 생산성을 극대화하고 휴먼 에러를 원천 봉쇄하는 GitHub Actions 기반의 CI/CD 자동화 파이프라인 아키텍처를 빈틈없이 깎아보았습니다. 내가 짠 소스코드가 원격 저장소에 가 닿는 순간, 보이지 않는 곳에서 무인 로봇들이 가상 컴퓨터를 켜고 테스트를 수행한 뒤 도커 컨테이너로 패키징해 배포하는 일련의 과정을 지켜보시면 진정한 DevOps 개발자로 거듭난 기분이 드실 것입니다.

워크플로우 yml 문법 오류로 파이프라인이 빨간 불을 뿜거나 도커 허브 인증 실패 에러로 고생하고 계신다면 주저하지 말고 아래 댓글 창에 에러 로그를 남겨주세요. 속 시원하게 풀어드리겠습니다. 감사합니다!

반응형