본문 바로가기

회고록(TIL&WIL)

TIL 2022.08.22 github actions(CI) - dotenv - Django - postgreSQL - Docker

Github Actions

github flow 를 자동화 해주는 기능 그 중에서도 branch를 만들었을 때 혹은 push를 했을 때 자동으로 Test 를 해준다던지 merge를 해주는 deploy과정을 자동으로 해주는 기능

 

demo test

# Github-Actions-Demo.yaml
name: GitHub Actions Demo # 액션의 이름 Action에서 제목처럼 뜨는 것
on: [push] # 언제 작동할 것인가?
jobs:
  Explore-GitHub-Actions: # 작동 이름
    runs-on: ubuntu-latest # 작동 환경
    steps:  # echo로 콘솔에 출력
      - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event." # github action 작동시킨 것 여기선 push
      - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" # 현재 os 출력 > linux 
      - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." # branch 이름(main), 레포지토리 출력(Aeius/SMOPS-BE)
      - name: Check out repository code
        uses: actions/checkout@v3 # 클론해오고 브랜치에 checkout 하는 것을 actions으로 만들어두어서 간편하게 쓸 수 있는 것 (@v3은 버젼)
      - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
      - run: echo "🖥️ The workflow is now ready to test your code on the runner."
      - name: List files in the repository
        run: |
          ls ${{ github.workspace }}
      - run: echo "🍏 This job's status is ${{ job.status }}." # success

Github Actions 으로 django CI 하기

// django-test.yaml
name: Django Test

on: [push] # push 할 때마다

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false # 하나가 실패해도 다른 job은 진행되도록
      matrix: # 매트릭스 병렬로 파이썬의 각각 버젼에 대해서 테스트를 실행하겠다.
        python-version: ["3.8", "3.9", "3.10"]

    steps:
      - uses: actions/checkout@v3
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install flake8
          pip install -r requirements.txt
      - name: Lint with flake8
        run: |
          # stop the build if there are Python syntax errors or undefined names
          flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
          # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
          flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
   
      - name: Run Tests
        run: |
          python manage.py test

참고자료

GitHub Actions Documentation - GitHub Docs


dotenv 파일로 환경변수 관리하기

1. 설치

pip install django-dotenv
pip freeze > requirements.txt

2. .env 파일 생성하여 SECRET_KEY 가져와서 환경변수화

// .env
SECRET_KEY = '...'
// settings.py
import os
...

SECRET_KEY = os.environ.get("SECRET_KEY")

3. dotenv 파일 불러오기

// manage.py
import dotenv
...

if __name__ == "__main__":
    dotenv.read_dotenv()
    main()

4. 민감한 정보를 담고 있기 떄문에 gitignore에 .env 추가하기

// .gitignore
...
.env

*이미 SECRET_KEY를 노출 시켜버렸다면? -> 재발급 받는 방법

python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())'

*dotenv로 환경변수를 관리하게 될 경우 Github Actions와 연동했을 때 SECRET_KEY 필요하다는 오류가 발생함!

1. yaml file에 직접적으로 값을 주는 방법 -> but yaml 파일도 마찬가지로 upload 되기 때문에 좋은 방법은 아님

// django-test.yaml
...
    - name: Run Tests
      env:
        SECRET_KEY:''
      run: |
        python manage.py test

2. github settings에서 설정하여 SECRET_KEY 추가한 다음 yaml 파일에서 run 이전에 코드 추가

// django-test.yaml
...
    - name: Run Tests
      env:
        SECRET_KEY: ${{secrets.SECRET_KEY}}
      run: |
          python manage.py test

참고자료


Docker 설정

# dockerfile
FROM python:3.10.0-alpine
# 장고를 설정할 때 필요한 코드들
ENV PYTHONDONTWRITEBYTECODE=1
# ㄴ 소스코드가 컴파일될 때 생성되는 파일 중 docker에서 필요하지않은 파일들을 생성되지 않도록 설정
ENV PYTHONUNBUFFERED=1
# ㄴ 파이썬 로고가 즉각적으로 로드되도록 설정

RUN apk update
# ㄴ alpine linux 패키지 업데이트 (pip ≒ apk )
RUN apk add build-base python3-dev py-pip jpeg-dev zlib-dev
# ㄴ 이후 build 시 필요한 모듈들을 추가로 작성해주면된다. 구글링을 통해서 적절한 패키지들을 추가하여야만 build가 된다.

COPY requirements.txt /usr/src/app/
# ㄴ 컨테이너에 requirements.txt 복사

WORKDIR /usr/src/app
# ㄴ 작업 위치 이동 후 패키지 설치
RUN pip install --upgrade pip
RUN pip install -r requirements.txt

COPY . /usr/src/app/
# ㄴ 현재 폴더에 있는 것들을(. 으로 경로 표시)들을 /user/scr/app/ 에 복사
docker build -t smops-be .

>> 보통 프로젝트 명으로 build를 하고 반드시 ( . ) 을 붙여줘야함

*pip install 과정에서 많은 오류가 발생함 > requirements.txt 의 패키지를 잘관리해야한다.

docker run -dp 8000:8000 \
> -w /usr/src/app -v "$(pwd):/usr/src/app" \
> smops-be \
> sh -c "python manage.py runserver 0.0.0.0:8000"
# docker-compose.yaml
version: "3.8"
# ㄴ 사용하는 docker-compose 버젼

services: # 추가할 서비스들 web, db, nginx
  web: 
    build: .
    # ㄴ . 을 써서 현재폴더에 있는 도커파일로 빌드를 하겠다.
    command: python manage.py runserver 0.0.0.0:8000
    # ㄴ 사용하는 커맨드
    ports: # 포트 맵핑
      - 8000:8000
    working_dir: /usr/src/app/
    volumes: # 바인딩 볼륨
     - ./:/usr/src/app/
     # ㄴ 현재 폴더(.)를 /usr/src/app/ 에 바인딩 
    env_file:
      - ./.env
      # ㄴ 현재 폴더(.)의 .env 파일로 환경변수 설정
docker-compose build #빌드

...process

docker-compose up #실행

postgreSQL을 Docker에 띄워서 Django와 연동하는 방법

Why? postgreSQL?

postgreSQL은 MySQL 보다 이후에 개발된 RDBMS이며 보다 다양한 기능을 제공한다.

Django에서도 대표적으로 지원을 많이하는 DB이다.

 

postgreSQL 과 Django를 같이 쓰면 좋은 점

  • Django는 PostgreSQL에서만 작동하는 다양한 데이터 유형을 제공합니다.
  • Django에는 PostgreSQL에서 데이터베이스 작업을 수행하기 위한 django.contrib.postgres가 있습니다. 
  • 지도로 애플리케이션을 구축하거나 지리 데이터를 저장하는 경우 GeoDjango는 PostgreSQL과만 완벽하게 호환되므로 PostgreSQL을 사용해야 합니다.
  • PostgreSQL은 Django에서 지원하는 가장 풍부한 기능 세트를 가지고 있습니다.

Django와 postgreSQL 연결

settings.py 와 .env 코드 작성

# settings.py
# ================================================================================
DATABASES = {
    'default' :{
        'ENGINE': os.environ.get('SQL_ENGINE', 'django.db.backends.sqlite3'),
        'NAME': os.environ.get('SQL_DATABASE', BASE_DIR / "db.sqlite3"),
        'USER': os.environ.get('SQL_USER', 'user'),
        'PASSWORD': os.environ.get('SQL_PASSWORD', 'password'),
        'HOST': os.environ.get('SQL_HOST', 'localhost'),
        'PORT': os.environ.get('SQL_PORT', '5432'),
    }
}
# ================================================================================

.env 파일의 경우는 반드시 gitignore에 추가해서 외부에 공개되어선 안된다!

# .env
SECRET_KEY = ''

SQL_ENGINE = 'django.db.backends.postgresql'
SQL_DATABASE = 'db_name' # Schema Name
SQL_USER = 'user'
SQL_PASSWORD = 'password'
SQL_HOST = 'db'
SQL_PORT = '5432'

dockerfile 수정, docker-compose 작성

# dockerfile
...
RUN apk add build-base python3-dev py-pip jpeg-dev zlib-dev libpq-dev
...
# docker-compose.yaml
...
services: # 추가할 서비스들 web, db, nginx
  web: 
   ...
    depends_on:
      - db
  db:
    image: postgres:14.4-alpine
    volumes:
      - postgres_db:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=ai2_back_db
      - POSTGRES_USER=ai2_back_user
      - POSTGRES_PASSWORD=ai2_back_password
    ports:
      - "5432:5432"

volumes:
  postgres_db:

*최초에 services.db.ports must be a list 오류가 발생했는데 아래와 같이 코드의 미세한 오타가 있을 가능성이 높다.

yml 파일은 형식에 대해 매우 엄격하기 때문에 띄워쓰기 같은 자잘한 오타도 상세하게 잘 적어야만 작동한다.

 

    ports:
      -"5432:5432"
>> services.db.ports must be a list 오류발생!
    ports:
      - "5432:5432"
>> 띄워쓰기를 잘해줘야한다

>> 이대로는 실행해도 오류가 나는데 그 이유는 django와 postgreSQL을 연결해주는 모듈인 psycopg가 없기 때문!

requirements.txt에 추가해줌으로써 build 시 다운로드 되도록 추가

# requirements.txt
...
psycopg2
docker-compose build
...
process
...
docker-compose up

docker desktop 에서 생성된 도커 컨테이너 확인하여 터미널 창 연뒤 마이그레이션, admin 계정 생성 하여 테스트

>> python manage.py migrate

>> python manage.py createsuperuser


pgAdmin 에 postgreSQL 연결