ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • local 개발환경 세팅부터 배포까지 - 3부(Fabric)
    Web, APP/Docker 2019.09.01 16:38

    안녕하세요! 운동하는 개발자 Jay입니다. 

    오늘은 대망의 3부 배포에 대해 알아 보겠습니다. 배포를 위해 Fabric 이라는 python 라이브러리를 사용하겠습니다.

    GitHub에서 프로젝트를 clone 받아서 실행(runserver) 까지 실행하는 배포 스크립트를 만들어 보겠습니다!

     

     

    1. Fabric 이란?


    Fabric은 SSH를 통해 원격으로 shell commands를 실행할 수 있도록 만들어진 Python (2.7, 3.4+) 라이브러리 입니다.

    말그대로 우리가 local에서 만든 프로젝트를 배포하고자 하는 서버에 원격으로 배포를 할 수 있게 해주는 라이브러리 입니다.

    물론 그냥은 아니고 SSH를 사용해서요!

     

    * Fabric 홈페이지 : https://www.fabfile.org/

     

    Welcome to Fabric! — Fabric documentation

    What is Fabric? Fabric is a high level Python (2.7, 3.4+) library designed to execute shell commands remotely over SSH, yielding useful Python objects in return: >>> from fabric import Connection >>> result = Connection('web1.example.com').run('uname -s',

    www.fabfile.org

     

    2. How is it used?


    먼저 Fabric 명령어를 사용하기 위해서 서버에 Fabric이 설치 되어있어야 합니다.

    2부에서는 docker -> docker로 배포를 하기위해 deploy, api 서버를 만들었습니다.

    deploy 서버에 접속하여 apt-get install fabric 명령어를 실행 시켜줍니다. fabric을 설치하면 fab 명령어를 사용할 수 있습니다.

     

    fabric 버전 확인, fab 옵션 확인

    이제, 배포할 프로젝트의 manage.py 가 있는 폴더로 가서 fabfile.py를 생성해 줍니다. (manage.py 가 있는 폴더에 생성 권장)

    이제 python에서 fabric을 사용하기 위해, 가상환경에서 pip install fabric을 해줍니다.

    저는 python3를 사용하기 때문에 pip install fabric3 으로설치하였습니다. (fabric, fabric3 라이브러리가 약간 다릅니다.)

     

     

    3. fabfile 작성하기 


    본격적으로 fabfile.py 를 작성해보겠습니다.

     

    - fabric api 함수 설명

    env 환경변수가 저정되어 있는 dict 변수
    local local에서 command를 실행하는 함수
    run 원격으로 접속한 host에 shell commmand를 실행하는 함수
    sudo 원격으로 접속한 host에 sudo권한의 shell commmand를 실행하는 함수
    settings context manager로서 특정 코드블럭에 설정을 적용(?). (python with 구문과 비슷한 역할이라고 생각하시면 됩니다)

     https://docs.fabfile.org/en/1.11/tutorial.html

     

    Overview and Tutorial — Fabric documentation

    Overview and Tutorial Welcome to Fabric! This document is a whirlwind tour of Fabric’s features and a quick guide to its use. Additional documentation (which is linked to throughout) can be found in the usage documentation – please make sure to check it ou

    docs.fabfile.org

    * 접속할 user에 sudo 권한 주기
    sudo 함수를 쓰기 위해서는 deploy(user)에 root권한 및 password 없이 사용할 수 있게 설정 해줘야 합니다. 
    visudo /etc/sudoers 명령어로 sudoers 파일을 수정합니다. 

    ( 주의 : ubuntu docker image의 경우 sudo가 설치되어 있지 않기 때문에 사전에 apt-get install sudo 를 실행해줘야 합니다.)

     

    NOPASSWD 설정을 해주지 않으면 sudo 명령어를 쓸 때마다 root 비밀번호를 입력하라는 메시지가 나옵니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    #-*- coding: utf-8 -*-
    from fabric.contrib.files import append, exists, sed, put
    from fabric.api import env, local, run, sudo, settings
    import random
    import os
    import json
     
    PROJECT_NAME = 'sample'
    PROJECT_GITHUB = 'https://github.com/[GITHUB_ID]/{}.git'.format(PROJECT_NAME)
    PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))
    BASE_DIR = os.path.dirname(PROJECT_DIR)
     
    DOCKER = 'docker'
    STAGING = 'staging'
    PRODUCT = 'product'
     
    env.user = 'deploy'
    env.target = '' # 베포 타겟
     
     
    # 배포 환경 (실서버, 개발서버, 도커 ...)
    def docker():
        env.target = DOCKER
     
     
    def staging():
        env.target = STAGING
     
     
    def prod():
        env.target = PRODUCT
     
     
    # API 서버
    def api():
        if env.target == DOCKER:
            env.hosts = 'bt-api'
        elif env.target == STAGING:
            env.hosts = '개발서버 host'
        elif env.target == PRODUCT:
            env.hosts = '실서버 host'
     
     
    # 초기 프로젝트 clone 및 관련 폴더생성, 패키지 설치
    def init():
        install_package()
        make_project()
     
     
    # init()으로 프로젝트 배포후, 추가 패키지 설치 및 프로젝트 pull
    def dist():
        # 가장 최근 커밋으로 소스를 되돌림 (충돌 방지)
        head = local("git rev-parse HEAD", capture=True)
        run('cd /home/deploy/sample && git reset --hard {}'.format(head))
        # 로컬 프로젝트의 최신 커밋으로
        run('cd /home/deploy/sample && git pull')
        # 필요한 라이브러리 설치
        run('/home/deploy/venv/bin/pip install -r /home/deploy/sample/requirement.txt')
     
        # 가상환경 실행, 프로젝트 runserver
        run('cd /home/deploy/ && source venv/bin/activate && /home/deploy/sample/./manage.py runserver 0.0.0.0:8888')
     
     
    # 기본적으로 필요한 패키지 설치
    def install_package():
        sudo('apt-get update')
        sudo('apt-get install python3')
        sudo('apt-get install python3-pip')
        sudo('apt-get install build-essential')
        sudo('apt-get install virtualenv virtualenvwrapper')
     
     
    def make_project():
        ''' private repo(Two-Factor Auth repo) 일 때 '''
        run('cd /home/deploy && git clone {}'.format(PROJECT_GITHUB))
        # 가상환경 설치
        run('cd /home/deploy && virtualenv venv')
        # 필요한 라이브러리 설치
        run('/home/deploy/venv/bin/pip install -r /home/deploy/sample/requirement.txt')
     
    cs
    1. 우리가 배포할 서버의 종류에 대해 정의하는 함수를 만듭니다.  docker, staging, prod 함수가 바로 이런 역할을 합니다.

    2. 배포할 서버 host를 정의해주는 함수를 작성합니다. 전 api 서버를 배포할거기 때문에 api 함수를 만들어 주었습니다. env.hosts 에는 host주소를 적어줍니다. IP 를 적어주시면 됩니다. 전 docker를 사용하기 때문에 컨테이명을 입력 했습니다.

    3. init() :  프로젝트를 처음 배포하는 함수입니다. 초기 필요한 디렉토리 및 환경을 설정해줍니다.

    4. dist() : init()으로 처음 배포 후, 다시 배포할때 사용하는 함수입니다. 이미 init()으로 초기에 필요한 환경을 구성해주었기 때문에, dist()에서는 새로 커밋된 소스로 update해주고, requirement에서 패키지만 재설치 합니다.(추가된 패키지 혹은 업데이트 된 패키지가 있을 수 있기 때문)

    * 최종적으로 우리가 실행할 fab 명령은 

    fab docker api init

    fab docker api dist

    이렇게 두가지 입니다. 실제로 한번 실행해 보도록 하겠습니다.

     

    * private repo + Two-Factor Auth 인증 일 경우

    1
    2
    3
    ''' private repo(Two-Factor Auth repo) 일 때 '''
    with settings(prompts={"Username for 'https://github.com': ""USER_NAME",
                           "Password for 'https://[GITHUB_ID]@github.com': ": TOKEN}):
    cs

    settings 함수를 이용해 cmd창에 Username, Password를 요구하는 메시지에 따라 값을 넣어줍니다.

    two-factor Auth인 경우에는 tocken 값을 넣어 줘야 합니다.

     

    GitHub/Settings/Developer settings

    https://metinsaylan.com/9422/how-to-git-clone-a-two-factor-authenticated-github-repository/

     

    [How To] Git Clone a Two-Factor Authenticated Github Repository // metinsaylan

    If you are using two-factor authentication on your Github account, chances are that you will be puzzled when you try to git clone your private repository from GitHub. Because it won't ask you two

    metinsaylan.com

     

     

    4. fabric으로 배포 (from deploy server to api server)


    1. deploy server에 접속하여, fabfile이 있는 프로젝트의 디렉토리로 이동

    2. api server에 접속하여 현재 디렉토리를 확인.

    3. deploy server에서 fab docker api init  명령어 실행

    필요한 패키지까지 설치후, 종료된 걸 확인 할 수 있습니다.

     

    4. deploy server에서 fab docker api dist  명령어 실행

    실행결과를 보시면, local 최신 commit id 를 가져와서, 배포할 서버의 프로젝트에 hard reset 해줍니다.

    그 후, 패키지를 한번 더 설치하고 runserver를 실행해 줍니다.

     

    실제 프로젝트에서는 runserver로 실행하진 않고 Django + Nginx + Gunicorn 조합으로 Django server를 실행합니다. 이 부분에 대해서는 따로 다뤄보도록 하겠습니다.

     

     

    5. 마치며...


    3부를 끝으로 local 개발환경 세팅부터 배포까지 시리즈가 끝났네요ㅎㅎ 처음으로 시리즈로 써보는 글을 완결(?) 했는데, 누군가에게 도움이 되는 글이 되었으면 좋겠습니다:D

    글을 쓰면서 개발환경 세팅을 지웠다 만들었다 반복하면서 저도 조금은 익숙해 졌네요! 

    모두 즐거운 코딩 하세요! 

    댓글 0

운동하는 개발자 JAY-JI