Created
August 23, 2016 09:16
-
-
Save dimmg/fa7f357ae5e63b00efa527aff1103413 to your computer and use it in GitHub Desktop.
fabric + gunicorn + upstart + nginx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 = '[email protected]:example-team/example.git' | |
BRANCH = 'master' | |
NGINX_SERVER_NAME = 'www.example.com' | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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