Today
-
Total
-
  • [django] shell 스크립트를 이용해 배포 자동화하기
    Dev 2020. 11. 30. 21:47

     

    안녕하세요.

     

    오늘은 장고에서 bash 스크립트를 사용하여 배포 과정을 간결하게 만든 경험에 대해 공유합니다.

     

    웨? 귀찮으니까!😉

    현재 제 프로젝트는 정적 파일은 Amazon s3에, 데이터베이스는 mysql로 관리하고 있습니다. 장고 프레임워크를 사용하고 있기 때문에 settings.py에 s3과 mysql 정보가 들어가 있고 기본적으로 python manage.py runserver 명령어를 통해 서버를 시작하면 해당 setting에 따라 s3, mysql에 접근하게 되죠. 따라서 dev에 작업(머지)된 내용을 master에 합치고 aws ec2에 배포를 하려면 다음과 같은 과정을 지나게 됩니다.


    * Github의 기본 브랜치는 이제 master에서 main으로 바뀌었습니다! 제 프로젝트는 git flow를 준수하지만 이번 포스팅에서는 master로 표현합니다. 자세한 건 아래 링크를 참조해주세요 👇
    blog.outsider.ne.kr/1503


    1. 새로 설치된 패키지가 있는지 체크

    장고는 pip로 패키지 관리를 하기 때문에, 프로젝트에 설치된 패키지 정보가 requirement.txt에 담겨 있습니다. 따라서 dev환경에서 새로운 패키지를 설치하면, pip freeze 명령어로 추가된 패키지 정보를 requirement.txt에 담게 됩니다. dev에서 requirement.txt를 커밋해 마스터로 넘기면, 배포할 때는 이 패키지를 설치를 해줘야겠죠. 그렇기 때문에 우선 가상환경에 접속합니다. (ec2에는 이미 가상환경이 설치되어있다고 가정합니다!)

     

    $ source venv/bin/activate

    $ pip install -r requirement.txt

     

    가상환경에 접속 후 패키지부터 설치해줍니다.

     

    2. 정적 파일 배포

    dev환경에서 정적 파일은 로컬을 바라보고 있지만, ec2에 배포되면 s3을 바라봐야 합니다. 장고에서는 정적 파일을 배포하는 명령어로 collectstatic을 제공하고 있는데요. 원래는 이 명령어를 사용하면 다음과 같이 confirm을 한번 해줍니다.

     

    $ python manage.py collectstatic

     

    3. DB Migrate

    장고의 ORM을 사용하고 있다면, 모델에 변화를 주거나 새로운 모델을 추가하였을 때 Migration은 다음과 같이 진행됩니다.

     

    $ python manage.py makemigrations

    변화된 내용을 감지하고 각 앱의 migrations 폴더에 변화/추가된 내용을 남긴다.

    이렇게 매번 히스토리가 남는다.


    $ python manage.py migrate

     

    따라서 dev환경에서 makemigrations 명령어를 이용해 migration.py 파일을 넘기고, master에서는 migrate 명령어를 사용하여 DB에 적용하게 됩니다.

     

    4. uwsgi 재시작

    현재 제 프로젝트는 uWSGI가 웹 서버와 장고 프레임워크 간 통신을 담당하고 있습니다. 즉 배포를 위해서는 이 uWSGI를 재시작하여 master에 머지된 내용을 적용해야 합니다. 명령어는 다음과 같습니다.

     

    $ sudo systemctl restart uwsgi

     

     

    이렇듯 배포를 위해서는 깃/커밋 관리를 제외하고도 이렇게나 많은 명령어를 쳐야 합니다😭

    그래서 저는 쉘 스크립트를 이용하여 이 과정을 간결하게 수정해보도록 하겠습니다.


     

    배포는 간결히 😎

     

    셸 스크립트는 셸이나 명령 줄 인터프리터에서 돌아가도록 작성되었거나 한 운영 체제를 위해 쓰인 스크립트입니다라고 위키에서 말하고 있습니다. Amazon ec2를 사용하면 리눅스 환경에 프로젝트를 배포하기 때문에, 셸에서 돌아가는 스크립트 언어인 셸 스크립트를 이용하여 저 귀찮은 명령어들을 한번에 작성되도록 할 수 있습니다.

     

    .sh파일을 하나 만들어 봅시다.

     

    deploy.sh

    cd $(dirname "$0")
    
    source venv/bin/activate
    
    pip install -r requirement.txt
    python manage.py collectstatic
    python manage.py migrate
    deactivate
    sudo systemctl restart uwsgi

    간단합니다. 셸 스크립트는 작성된 명령어를 줄 단위로 차례로 실행합니다. 위에 나열한 배포 명령어들을 차례로 적어준 뒤, sh 명령어를 이용하여 이 스크립트 파일을 실행하면 알아서 명령어를 실행해 줍니다. 이렇게만 작성해도 배포에는 문제가 없지만, 이 스크립트를 여러 명이 사용한다고 가정하고 좀 더 친절히 바꿔봅시다.

     

     

    1. echo 명령어를 이용하여 현재 상황 출력하기

    echo는 유닉스 계열 운영체제에서 사용가능한, 문자열을 터미널에 출력하는 명령어입니다. 셸 스크립트를 실행중인 동안에는 어떤 명령어가 실행되고 있는지 알기 힘들기 때문에, 터미널에 출력을 해줍시다.

    echo "hello!"
    
    cd $(dirname "$0")
    pwd // 현재 경로 보여주기
    
    // sh파일이 다른 폴더에 있다면 cd 명령어를 통해 root로 와야한다.
    
    echo "activate venv"
    source venv/bin/activate
    
    echo "install package.."
    pip install -r requirement.txt
    
    echo "collect static.."
    python manage.py collectstatic
    
    echo "apply migration"
    python manage.py migrate
    
    echo "deactive venv"
    deactivate
    
    echo "restart uwsgi"
    sudo systemctl restart uwsgi
    
    echo "bye bye!"

    나름 친절하게 경과상황을 보고합니다. 왜 npm 패키지 설치할 때 패키지 개발자들이 콘솔에 장난을 쳤는지 이해가 가기 시작합니다.

     

    2. noinput 옵션 달기

    python manage.py collectstatic 명령어를 사용하면 다음과 같이 한번 confirm을 해줍니다.

    하지만 배포를 자동화 한다해놓고 이렇게 interaction이 추가로 생기면 귀찮쿨하지 못하겠죠.

     --noinput 옵션을 넘기면 confirm을 하지 않고 넘어갑니다.

     

    3. 실행 권한 부여하기

    이제 이 셸 스크립트를 master에 머지하고 ec2에 접속해 봅시다. sh 파일은 실행권한을 주지 않으면 시스템에서 허용하지 않습니다. 실행권한을 부여하고 실행해 봅시다.

     

    $ chmod +x deploy.sh

    $ ./deploy.sh

     

    열심히 알아서 배포를 해줍니다. 참 간단하죠? 진작 할걸

    다음 포스팅에서는 개발 환경을 구분하여 dev, master에 각각 배포하는 과정을 분리해보도록 하겠습니다.

     

     

    이상으로 포스팅을 마칩니다.

     

     

    📚 출처

    ko.wikipedia.org/wiki/%EC%85%B8_%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B

     

    댓글