본문 바로가기
카테고리 없음

코린이의 GitHub action을 활용한 docker이미지 배포

by kyung-mini 2024. 10. 11.

1. 개요

본 포스팅에서는 GitHub action, Docker, AWS EC2를 활용하여, 반쪽짜리 CI/CD를 구축하는 방법에 대해서 알아보겠습니다.

코드가 필요하신 분은 "3. Docker란?" 목차로 넘어가시면 됩니다.

근 한 달간을 투자한 프로젝트의 마감일이 다가왔습니다. 해당 프로젝트를 배포하기 위해 조언을 얻던 중, 수작업으로 배포를 하는 것보다 쉬운 CI / CD 구축 방법이 있다고 해서, 따라하게 되었습니다. 이번글의 목적은 다양한 내용을 다루기 때문에 구체적인 방법과 개념에 대해서는 간략하게 설명하고 넘어가겠습니다.

2. CI / CD란?

코딩에 막 입문한 분이시라도, CI / CD에 대해서 많이 들어보셨으리라. 생각합니다. 본 포스팅에서는 흐름을 다루기 때문에 자세하게 다루지 않습니다. 따라서, 추가적인 정보를 검색해보는 것을 추천드립니다.

2.1 CI란?

CI는 "Continuous Integration"의 약자로 지속적 통합이라는 뜻 입니다.

처음부터 완벽한 서비스를 내놓으면 좋겠지만, 불가능합니다. 개발자들은 서비스를 출시한 이후 지속적으로 코드를 수정하고 개선해 나갑니다. CI란 이렇게 수정한 코드를 통합하는 과정을 의미합니다. 이 과정에는 보편적으로 Lint를 활용한 코드 품질 검사, 자동화된 테스트가 포함됩니다.

2.2 CD란?

CD는 두가지 뜻을 가지고 있습니다. 첫 번째는 "Continuous Delivery"로 지속적 전달입니다. 두 번째는 "Continuous Deployment"로 지속적 배포라는 뜻을 가지고 있습니다.

지속적 전달 단계의 초점은 CI가 완료된 코드를 프로덕션 환경에 배포할 준비 상태로 유지하는 것입니다. 이 단계에는 '.env'파일 생성, docker이미지를 빌드하는 과정이 포함됩니다.

지속적 배포는 앞서 설명한 CI와 지속적 전달 단계를 포함하며, 배포까지 자동으로 이루어지는 것을 의미합니다. 지속적 배포는 코드 변경이 이루어지면 프로덕션에 배포하는 것까지 자동화된 배포 파이프라인을 의미합니다.

3. Docker란?

배포를 간단하게 만드는 것에 큰 기여를 한 도구입니다. Docker는 컨테이너라는 가상화된 환경을 구축하여, 서비스를 실행할 수 있게 해줍니다. Docker의 컨테이너는 완전히 독립적인 공간입니다. 따라서, 컨테이너를 실행할 수 있다면 어떤 환경에서 컨테이너를 실행하였든지 동일한 환경에서 서비스를 실행할 수 있게됩니다.

Docker의 핵심 개념은 이미지와 컨테이너입니다.

  • 이미지 : 서비스를 실행하는데 필요한 모든 파일들을 패키지화한 것입니다. 이 이미지를 기반으로 컨테이너가 실행됩니다.
  • 컨테이너 : 이미지를 활용하여 생성된 실행 환경입니다. 서비스가 동작하는 가상화된 독립적인 공간입니다.

Docker 이미지를 빌드하기 위해서는 Dockerfile이라는 파일이 필요합니다. 루트 디렉토리에 Dockerfile이라는 파일을 만들고 아래 코드를 작성하고, 수정해주세요.

# 공식 Python 3.12-slim 이미지 사용
FROM python:3.12-slim
ENV PYTHONPATH=/app
ENV DJANGO_SETTINGS_MODULE=src.config.settings.docker
# PostgreSQL 개발 패키지와 gcc 설치 (최소 의존성 설치 후 캐시 정리)
RUN apt-get update && apt-get install -y libpq-dev gcc && rm -rf /var/lib/apt/lists/*

# 작업 디렉토리 설정
WORKDIR /app

# PDM 설치
RUN pip install --no-cache-dir pdm

# PDM 프로젝트 파일 복사 및 종속성 설치
COPY pyproject.toml pdm.lock /app/
RUN pdm install --prod --no-lock --no-editable --no-self

# 소스 코드 복사
COPY ./src /app/src
COPY .env /app/.env

# Django의 collectstatic 명령어 실행 (staticfiles 폴더가 자동 생성됨)
RUN pdm run python src/manage.py collectstatic --noinput

# 컨테이너 시작 시 PDM의 가상 환경을 활성화하고 Django 서버 실행
CMD ["pdm", "run", "python", "src/manage.py", "runserver", "0.0.0.0:8000"]

 

docker가 아예 처음이라면 아래 글을 참고해보시는 것도 좋을 것 같습니다.

Django 개발자를 위한 Docker Desktop 시작하기 전 세팅

Django 개발자를 위한 Docker Desktop 사용 가이드

아래 과정을 하기 전에 docker hub에 들어가셔서 회원 가입 후 private 레포지터리를 생성해 주세요.

https://hub.docker.com/

4. GitHub action이란?

특정 조건을 만족할 때, 미리 정해놓은 작업을 실행시키는 도구입니다. 본 포스팅에서는 CI/ CD를 위해 사용되지만, 다양한 것들을 자동화할 수 있습니다. 아래에서는 GitHub Actions를 활용하여 코드 검증, .env파일 생성, Docker이미지 빌드를 자동화할 예정입니다.

깃허브 레포의 루트 디렉토리에 .github폴더를 만들고, 만든 폴더 안에 workflows라는 폴더를 만들어 줍니다. 폴더 이름이 틀리면 작동하지 않기 때문에 유의해주시기 바랍니다. workflows 폴더 안에는 .yml 파일들을 생성해줍니다. 이때 이름은 작성할 코드를 식별할 수 있도록 만들어주시는게 좋습니다.

4.1 CI - 코드 검사

아래 코드는 ruff라는 Lint를 활용한 코드 검사합니다. Lint를 활용한 코드 검사는 코드 품질 유지, 일관성 있는 코드 등의 이점이 있기 때문에 포함하는 것이 좋은 과정입니다. build.yml이라는 파일을 만든 후 아래 코드를 입력해주세요.

name: Lint Python Code with Ruff

on:
  pull_request:
    branches:
      - main

jobs:
  lint:
    name: Lint
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - name: Run Ruff on changed files in src directory
        uses: chartboost/ruff-action@v1
        with:
          changed-files: 'true'
          src: './src'

ruff에 대해서 추가적인 설명을 덧붙이자면, Flake8, isort, Black을 포함하고 있는 도구입니다. 또한, Rust로 작성되었기 때문에, 매우 빠른 속도를 가지고 있습니다.

ruff 사이트

4.2 CI / CD - .env생성 및 지속적 전달 과정

build.yml파일을 만든 후 아래 코드를 작성하시면 됩니다. 아래 코드가 작동하게 되면 .env 파일을 생성한 후 Docker 이미지를 빌드한 후 Docker Hub에 이미지를 배포합니다.

.env 파일을 사용하지 않으신다면 - name: Make envfile 부분은 지우셔도 됩니다.

아래 코드의 조건은 다른 브렌치에서 main브렌치로 PR을 보낼 때, 아래 코드가 실행됩니다. 필요에 따라 수정이 필요합니다. 다른 코드들의 자세한 사용 방법은 아래 링크를 달아두었으니, 확인해보시면 좋을 것 같습니다.

name: Create envfile

on:
  pull_request:
    branches:
      - main

jobs:
  build-docker-image:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    - name: Make envfile
      uses: SpicyPizza/create-envfile@v2.0
      with:
        envkey_SECRET_KEY: ${{ secrets.SECRET_KEY }}
        envkey_DATABASE_NAME: ${{ secrets.DATABASE_NAME }}
        envkey_DATABASE_USER: ${{ secrets.DATABASE_USER }}
        envkey_DATABASE_PASSWORD: ${{ secrets.DATABASE_PASSWORD }}
        envkey_DATABASE_HOST: ${{ secrets.DATABASE_HOST }}
        envkey_DATABASE_PORT: ${{ secrets.DATABASE_PORT }}
        envkey_AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        envkey_AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        envkey_AWS_S3_REGION_NAME: ${{ secrets.AWS_S3_REGION_NAME }}
        envkey_AWS_STORAGE_BUCKET_NAME: ${{ secrets.AWS_STORAGE_BUCKET_NAME }}
        envkey_IMP_KEY: ${{ secrets.IMP_KEY }}
        envkey_IMP_SECRET: ${{ secrets.IMP_SECRET }}
        envkey_IMP_REST_API_KEY: ${{ secrets.IMP_REST_API_KEY }}
        envkey_DJANGO_SUPERUSER_USERNAME: ${{ secrets.DJANGO_SUPERUSER_USERNAME }}
        envkey_DJANGO_SUPERUSER_PASSWORD: ${{ secrets.DJANGO_SUPERUSER_PASSWORD }}



    - id: commit
      uses: pr-mpt/actions-commit-hash@v2

    - name: Build and Push to Docker Hub
      uses: mr-smithers-excellent/docker-build-push@v6
      with:
        image: ${{ secrets.DOCKER_HUB_USERNAME}}/orm-city
        tags: ${{ steps.commit.outputs.short }}, latest
        registry: docker.io
        dockerfile: Dockerfile
        username: ${{ secrets.DOCKER_HUB_USERNAME }}
        password: ${{ secrets.DOCKER_HUB_PASSWORD }}

create-envfile GitHub repo

Github Actions - Docker 이미지 빌드 및 푸시하기

5. aws ec2란?

AWS 클라우드의 가상 서버로, 클라우드 컴퓨팅 서비스입니다. 쉽게 생각하면 원격으로 제어할 수 있는 컴퓨터를 빌리는 것이라고 할 수 있습니다.

목차 4를 수행하셨다면, docker hub 개인 프라이빗 레포에 이미지가 들어가 있을겁니다.

aws ec2의 ssh에 들어가셔서 docker를 pull 해오신 다음에 run을 하시면 서버 배포 완료입니다.

 

6. 마무리

CI / CD가 말로만 들었을 때는 건드리지 못할 정도로  어려울 것이라 생각하였는데, 조금씩 하다보니 따라할만것 같습니다. 아직 반쪽짜리 CI / CD이기 때문에 온전한 CI / CD를 만드는 것을 목표로 하고 있습니다. 프로젝트 중간에 짬내서 정리하는 느낌으로 적다보니 많이 미흡합니다. 추후 수정하겠습니다....