Fabric으로 django 배포
장고 배포 방법
- manage.py에 있는 곳에 fabfile.py 를 아래와 같이 만든다.
- 같은 위치에 deploy.json 과 envs.json (빈파일)을 만든다.
# fabfile.py
from fabric.contrib.files import append, exists, sed, put
from fabric.api import env, local, run, sudo
import random
import os
import json
PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))#settings 가 있는 제일 상위 폴더
# PROJECT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)),'fbtest')
# PROJECT_DIR = './fbtest' # settings가 있는 폴더
with open(os.path.join(PROJECT_DIR, "deploy.json")) as f:
envs = json.loads(f.read())
def get_env(setting, envs):
return envs[setting]
# TODO: Required Fields: REPO_URL, PROJECT_NAME, REMOTE_HOST, REMOTE_PASSWORD, REMOTE_USER @ deploy.json
# developer: chagne this!
REPO_URL = get_env('REPO_URL', envs)
PROJECT_NAME = get_env('PROJECT_NAME', envs)
REMOTE_HOST = get_env('REMOTE_HOST', envs)
REMOTE_HOST_SSH = get_env('REMOTE_HOST_SSH', envs)
REMOTE_USER = get_env('REMOTE_USER', envs)
REMOTE_PASSWORD = get_env('REMOTE_PASSWORD', envs)
STATIC_ROOT_NAME = 'static' #---------------------------- 수정
STATIC_URL_NAME = 'static' #---------------------------- 수정
MEDIA_ROOT = 'media' #---------------------------- 수정
# TODO: Server Engineer: you should add env.user as sudo user and NOT be root
env.user = REMOTE_USER
username = REMOTE_USER
# Option: env.password
env.hosts = [
REMOTE_HOST_SSH,
]
env.password = REMOTE_PASSWORD
project_folder = '/home/{}/{}'.format(env.user, PROJECT_NAME)
apt_requirements = [
'curl',
'git',
'python3-dev',
'python3-pip',
'build-essential',
'libpq-dev',
'postgresql',
'postgresql-contrib',
'apache2',
'libapache2-mod-wsgi-py3',
'python3-setuptools',
'libssl-dev',
'libffi-dev',
]
def new_server():
setup()
deploy()
def setup():
_mkdir_ssh()
_register_ssh_key()
_get_latest_apt()
_install_apt_requirements(apt_requirements)
_make_virtualenv()
#_ufw_allow()
def deploy():
_get_latest_source()
_put_envs()
_update_settings()
_update_virtualenv()
_update_static_files()
_update_database()
#_ufw_allow()
_make_virtualhost()
_grant_apache2()
_restart_apache2()
def create_superuser():
virtualenv_folder = project_folder + '/../.virtualenvs/{}'.format(PROJECT_NAME)
run('cd %s && %s/bin/python3 manage.py createsuperuser' % (
project_folder, virtualenv_folder
))
def myg(val="blank"):
'''git push하고 배포'''
local('git add .')
local('git commit -m {}'.format(val))
local('git push')
deploy()
def _mkdir_ssh():
USER_HOME = os.path.expanduser('~')
if not os.path.exists(os.path.join(USER_HOME, '.ssh/')):
local("mkdir {}".format(os.path.join(USER_HOME, '.ssh')))
def _register_ssh_key():
local("ssh-keyscan -H {} >> {}".format(REMOTE_HOST, os.path.expanduser('~/.ssh/known_hosts')))
def migrate():
_put_envs()
_update_settings()
_update_virtualenv()
_update_static_files()
_update_database()
_make_virtualhost()
_grant_apache2()
_restart_apache2()
def _put_envs():
put('envs.json', '~/{}/envs.json'.format(PROJECT_NAME))
#put('bank_envs.json', '~/{}/bank_envs.json'.format(PROJECT_NAME))
def _get_latest_apt():
update_or_not = input('would you update?: [y/n]')
if update_or_not=='y':
sudo('sudo apt-get update && sudo apt-get -y upgrade')
def _install_apt_requirements(apt_requirements):
reqs = ''
for req in apt_requirements:
reqs += (' ' + req)
sudo('sudo apt-get -y install {}'.format(reqs))
def _make_virtualenv():
if not exists('~/.virtualenvs'):
script = '''"# python virtualenv settings
export WORKON_HOME=~/.virtualenvs
export VIRTUALENVWRAPPER_PYTHON="$(command \which python3)" # location of python3
source /usr/local/bin/virtualenvwrapper.sh"'''
run('mkdir ~/.virtualenvs')
sudo('sudo pip3 install virtualenv virtualenvwrapper')
run('echo {} >> ~/.bashrc'.format(script))
def _get_latest_source():
if exists(project_folder + '/.git'):
run('cd %s && git fetch' % (project_folder,))
else:
run('git clone %s %s' % (REPO_URL, project_folder))
current_commit = local("git log -n 1 --format=%H", capture=True)
run('cd %s && git reset --hard %s' % (project_folder, current_commit))
def _update_settings():
settings_path = project_folder + '/{}/settings.py'.format(PROJECT_NAME)
sed(settings_path, "DEBUG = True", "DEBUG = False")
# sed(settings_path, "DEBUG = True", "DEBUG = True")
sed(settings_path,
'ALLOWED_HOSTS = .+$',
'ALLOWED_HOSTS = ["%s"]' % (REMOTE_HOST,),
)
secret_key_file = project_folder + '/{}/secret_key.py'.format(PROJECT_NAME)
if not exists(secret_key_file):
chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)'
key = ''.join(random.SystemRandom().choice(chars) for _ in range(50))
append(secret_key_file, "SECRET_KEY = '%s'" % (key,))
append(settings_path, '\nfrom .secret_key import SECRET_KEY')
def _update_virtualenv():
virtualenv_folder = project_folder + '/../.virtualenvs/{}'.format(PROJECT_NAME)
if not exists(virtualenv_folder + '/bin/pip'):
run('cd /home/%s/.virtualenvs && virtualenv %s' % (env.user, PROJECT_NAME))
run('%s/bin/pip install -r %s/requirements.txt' % (
virtualenv_folder, project_folder
))
def _update_static_files():
virtualenv_folder = project_folder + '/../.virtualenvs/{}'.format(PROJECT_NAME)
run('cd %s && %s/bin/python3 manage.py collectstatic --noinput' % (
project_folder, virtualenv_folder
))
def _update_database():
virtualenv_folder = project_folder + '/../.virtualenvs/{}'.format(PROJECT_NAME)
run('cd %s && %s/bin/python3 manage.py migrate --noinput' % (
project_folder, virtualenv_folder
))
def _ufw_allow():
sudo("ufw allow 'Apache Full'")
sudo("ufw reload")
def _make_virtualhost():
script = """'<VirtualHost *:80>
ServerName {servername}
Alias /{static_url} /home/{username}/{project_name}/{static_root}
Alias /{media_url} /home/{username}/{project_name}/{media_url}
<Directory /home/{username}/{project_name}/{media_url}>
Require all granted
</Directory>
<Directory /home/{username}/{project_name}/{static_root}>
Require all granted
</Directory>
<Directory /home/{username}/{project_name}/{project_name}>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
WSGIDaemonProcess {project_name} python-home=/home/{username}/.virtualenvs/{project_name} python-path=/home/{username}/{project_name}
WSGIProcessGroup {project_name}
WSGIScriptAlias / /home/{username}/{project_name}/{project_name}/wsgi.py
ErrorLog $/error.log
CustomLog $/access.log combined
</VirtualHost>'""".format(
static_root=STATIC_ROOT_NAME,
username=env.user,
project_name=PROJECT_NAME,
static_url=STATIC_URL_NAME,
servername=REMOTE_HOST,
media_url=MEDIA_ROOT
)
sudo('echo {} > /etc/apache2/sites-available/{}.conf'.format(script, PROJECT_NAME))
sudo('a2ensite {}.conf'.format(PROJECT_NAME))
def _grant_apache2():
sudo('chown :www-data ~/{}'.format(PROJECT_NAME))
# enable below if use sqlite3
sudo('chmod 775 ~/{}/db.sqlite3'.format(PROJECT_NAME))
# sudo('chmod a+w ~/{}/db.sqlite3'.format(PROJECT_NAME))
def _restart_apache2():
sudo('sudo service apache2 restart')과정
- gitignore 에 sqlite3 를 추가하여 데이터가 지워지지 않도록함.
- 실행하면 github의 유저네임, 비번을 입력하도록 하는 창이 계속 나타났음.
- 이때에는 서버의 .ssh/에 퍼블릭 키를 생성하고 이를 github에 등록하면됨. 또한 연결된 주소는 ssh 주소로 바꾸면 됨.
- 서버에서 git fetch에 대한 명령에 의해 나타남
- git 과 연결할때 가장 처음에는 ssh말고 그냥 주소로 해야함.
- staic_root 를 세팅파일에 추가해야 함.
- 서버에 ssh로 접속하여 서버에서 git 명령이 ssh로 나타나도록 설정하는 것이 중요(주소를 git에서 ssh형태로 복사 !서버에 .ssh가 있는 지 확인하였음)
- myg 를 통해 git push와 배포자동화 (명령 : fab myg:”pushname”)
- 처음에 ssh 관련 오류가 나서, 주소를 ip주소로 바꾸니 됨.
- ssh 오류가 나서 .ssh/known_hosts를 지우니 해결됨.
- git reset –hard ***오류가 발생, 서버측에 git 장소를 제대로 지정하니 해결됨.
- 혹은 git push가 다되었는지 확인! 꼭!
- fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.
- 이 경우 서버에 직접 ssh키를 생성하고 서버에 생성된 공개키를 github에 등록하면 되었음.
- key_load_public: invalid format Permission denied (publickey). fatal: Could not read from remote repository.
- 위의 에러의 경우 서버에 직접 ssh키를 생성하고 서버에 생성된 공개키를 github에 등록하면 되었음. 이때 서버에 개인키가 있고 이것에 대한 공개키가 github에 있어야 하는 것 같음.
https://beomi.github.io/2017/03/20/Deploy-Django-with-Fabric/
Leave a Comment