Skip to content

Instantly share code, notes, and snippets.

@dimmg
Created August 23, 2016 09:16
Show Gist options
  • Save dimmg/fa7f357ae5e63b00efa527aff1103413 to your computer and use it in GitHub Desktop.
Save dimmg/fa7f357ae5e63b00efa527aff1103413 to your computer and use it in GitHub Desktop.
fabric + gunicorn + upstart + nginx
HOST = '172.39.10.30'
PROJECTS_DIR = '/home/exampleuser/'
USER = 'exampleuser'
PROJECT_NAME = 'example'
APP_DIR = '{0}{1}/'.format(PROJECTS_DIR, PROJECT_NAME)
VIRTUALENVS_DIR = '{0}.virtualenvs/'.format(PROJECTS_DIR)
VIRTUALENV_PATH = '{0}{1}/'.format(VIRTUALENVS_DIR, PROJECT_NAME)
LOGS_DIR = '{0}logs/'.format(APP_DIR)
REPOSITORY = 'git@github.com:example-team/example.git'
BRANCH = 'master'
NGINX_SERVER_NAME = 'www.example.com'
from fabric.api import env, cd, run, sudo, settings
from fabric.contrib.console import confirm
from fabric.contrib.files import exists
from fabric.colors import blue, green, red
from config import (HOST, USER, PROJECT_NAME, APP_DIR, VIRTUALENVS_DIR,
VIRTUALENV_PATH, LOGS_DIR, REPOSITORY, BRANCH, PROJECTS_DIR,
NGINX_SERVER_NAME)
env.hosts = [HOST]
env.user = USER
env.project_name = PROJECT_NAME
env.app_dir = APP_DIR
env.virtualenv_dir = VIRTUALENVS_DIR
env.virtualenv_path = VIRTUALENV_PATH
env.logs_dir = LOGS_DIR
env.projects_dir = PROJECTS_DIR
def _create_virtualenv():
"""
Creates a virtual environment.
"""
if not exists(env.virtualenv_dir):
run('mkdir {0}'.format(VIRTUALENVS_DIR))
if not exists(env.virtualenv_dir + env.project_name):
with cd(env.virtualenv_dir):
run('virtualenv {0}'.format(PROJECT_NAME))
print blue('\nCreated virtual environment in {virtualenv_dir} ..\n'.format(**env))
def _create_logs():
"""
Creates logs folder.
"""
sudo('mkdir -p {logs_dir}'.format(**env))
print blue('\nCreated logs folder..\n')
def _setup_directories():
"""
Creates main project directories.
"""
if not exists(env.app_dir):
run('git clone {} {project_name}'.format(REPOSITORY, **env))
print blue('\nCloned repository..\n')
_create_virtualenv()
_create_logs()
def _run(command, pip=''):
"""
Runs a pip or python command from virtual
environment.
"""
run('{virtualenv}bin/{target} {command}'.format(
virtualenv=env.virtualenv_path,
command=command, target=pip or 'python'))
def _setup_nginx():
"""
Configures the nginx web server.
"""
with cd('/etc/nginx/sites-available/'):
sudo('touch {project_name}'.format(**env))
with open('nginx') as nginx:
nginx_configs = {
'project_name': env.project_name,
'host': HOST,
'user': env.user,
'server_name': NGINX_SERVER_NAME
}
nginx_conf = ''.join(nginx.readlines()) % nginx_configs
sudo("echo '{0}' > {1}".format(nginx_conf, env.project_name))
sudo('ln -s /etc/nginx/sites-available/{project_name} /etc/nginx/sites-enabled/{project_name}'
.format(**env))
print blue('\nCreated nginx configuration files..\n')
with cd('{app_dir}logs/'.format(**env)):
sudo('touch access.{project_name}.log'.format(**env))
sudo('touch error.{project_name}.log'.format(**env))
print blue('\nCreated nginx log files..\n')
def _setup_upstart():
"""
Creates an upstart task that will be performed when
the machine is started.
"""
with cd('/etc/init/'):
sudo('touch {project_name}.conf'.format(**env))
with open('upstart') as upstart:
upstart_conf = ''.join(upstart.readlines()).format(
project_name=env.project_name, user=env.user, virtualenv=env.virtualenv_path,
app_dir=env.app_dir
)
sudo("echo '{0}' > {1}.conf".format(
upstart_conf, env.project_name))
with cd('{app_dir}logs/'.format(**env)):
sudo('touch {logs_dir}gunicorn.{project_name}_acc.log'.format(**env))
sudo(
'chown {user}:www-data {logs_dir}gunicorn.{project_name}_acc.log'.format(**env))
sudo('touch {logs_dir}gunicorn.{project_name}_err.log'.format(**env))
sudo(
'chown {user}:www-data {logs_dir}gunicorn.{project_name}_err.log'.format(**env))
sudo('service {project_name} start'.format(**env))
print blue('\nCreated upstart task..\n')
def init_db():
"""
Adds the migrations folder to the application.
"""
with cd(env.app_dir):
_run('app.py db init')
print blue('\nInitialized database..\n')
def _migrate():
"""
Generates the migrations.
"""
with cd(env.app_dir):
_run('app.py db migrate')
print blue('\nGenerated migrations..\n')
def _upgrade():
"""
Applies the migrations.
"""
with cd(env.app_dir):
_run('app.py db upgrade')
print blue('\nApplied migrations..\n')
def _setup_database():
"""
Creates the database.
"""
sudo(
'sudo -u postgres psql -c "create database {project_name} owner admin"'.format(**env))
print blue('\nCreated database..\n')
def _update_app():
with cd(env.app_dir):
run('git pull origin {0}'.format(BRANCH))
_run('install -r requirements.txt', 'pip')
_migrate()
_upgrade()
def _restart_app():
"""
Restarts all application related services.
"""
sudo('service nginx restart')
with settings(warn_only=True):
sudo('service {project_name} start'.format(**env))
sudo('service {project_name} restart'.format(**env))
print blue('\nServices were restarted successfully..\n')
def deploy():
"""
Updates application with latest changes.
"""
_update_app()
_restart_app()
print green('\nDeployed successfully!\n')
def provision():
"""
Application provisioning on the server.
"""
_setup_directories()
with cd(env.app_dir):
_run('install -r requirements.txt', 'pip')
_setup_nginx()
_setup_upstart()
_setup_database()
print blue('\nPlease update the config file..\n')
print green('\nProvisioned successfully!\n')
def destroy():
"""
Destroyes everything related to the application.
"""
question = 'Do you really want to destroy everything related to {project_name}?'.format(
**env)
if confirm(question, default=False):
with settings(warn_only=True):
with cd('/etc/init/'):
print red('\nStopping {project_name} upstart task..\n'.format(**env))
sudo('service {project_name} stop'.format(**env))
print red('\nRemoving {project_name} upstart task..\n'.format(**env))
sudo('rm {project_name}.conf'.format(**env))
print red('\nRemoving nginx configuration files..\n')
with cd('/etc/nginx/sites-enabled/'):
sudo('unlink {project_name}'.format(**env))
with cd('/etc/nginx/sites-available/'):
sudo('rm {project_name}'.format(**env))
sudo('service nginx restart')
print red('\nDropping the database..\n')
sudo(
'sudo -u postgres psql -c "drop database {project_name}"'.format(**env))
print red('\nDeleting virtualenv from {virtualenv_path}..\n'.format(**env))
with cd('{virtualenv_dir}'.format(**env)):
sudo('rm -rf {project_name}'.format(**env))
print red('\nRemove application source directory..\n')
sudo('rm -rf {app_dir}'.format(**env))
print green('{project_name} application was completely removed!'.format(**env))
from config import USER, PROJECT_NAME, LOGS_DIR
user = USER
workers = 2
bind = "unix:{0}.sock".format(PROJECT_NAME)
pidfile = "/tmp/{0}.pid".format(PROJECT_NAME)
backlog = 2048
umask = 007
accesslog = "{0}gunicorn.{1}_acc.log".format(
LOGS_DIR, PROJECT_NAME)
errorlog = "{0}gunicorn.{1}_err.log".format(
LOGS_DIR, PROJECT_NAME)
server {
listen 80;
server_name %(server_name)s;
access_log /home/%(user)s/%(project_name)s/logs/access.%(project_name)s.log;
error_log /home/%(user)s/%(project_name)s/logs/error.%(project_name)s.log;
location / {
proxy_pass_header Server;
proxy_set_header Host $host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://unix:/home/%(user)s/%(project_name)s/%(project_name)s.sock;
}
}
description "Gunicorn application server running {project_name}"
start on runlevel [2345]
stop on runlevel [!2345]
respawn
setuid {user}
setgid www-data
env PATH={virtualenv}bin
chdir {app_dir}
exec python app.py gunicorn
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment