In questo tutorial, prenderemo un semplice progetto Django locale, supportato da un database MySQL, e lo convertiremo per eseguirlo su Heroku. Amazon S3 verrà utilizzato per ospitare i nostri file statici, mentre Fabric automatizza il processo di distribuzione.
Il Progetto è un semplice sistema di messaggi. Potrebbe essere un'app di cose da fare o un blog o persino un clone di Twitter. Per simulare uno scenario dal vivo, il progetto verrà prima creato con un backend MySQL, quindi convertito in Postgres per l'implementazione su Heroku. Personalmente ho avuto cinque o sei progetti in cui ho dovuto fare esattamente questa cosa:convertire un progetto locale, supportato da MySQL, in un'app live su Heroku.
Configurazione
Prerequisiti
- Leggi la guida ufficiale di Django Quick Start su Heroku. Basta leggerlo. Questo ti aiuterà a farti un'idea di ciò che realizzeremo in questo tutorial. Utilizzeremo il tutorial ufficiale come guida per il nostro processo di implementazione più avanzato.
- Crea un account AWS e configura un bucket S3 attivo.
- Installa MySQL.
Iniziamo
Inizia scaricando il progetto di prova qui, decomprimi, quindi attiva un virtualenv:
$ cd django_heroku_deploy
$ virtualenv --no-site-packages myenv
$ source myenv/bin/activate
Crea un nuovo repository su Github:
$ curl -u 'USER' https://api.github.com/user/repos -d '{"name":"REPO"}'
Assicurati di sostituire le PAROLE CHIAVE in maiuscolo con le tue impostazioni. Ad esempio:curl -u 'mjhea0' https://api.github.com/user/repos -d '{"name":"django-deploy-heroku-s3"}'
Aggiungi un file readme, inizializza il repository Git locale, quindi PUSH la copia locale su Github:
$ touch README.md
$ git init
$ git add .
$ git commit -am "initial"
$ git remote add origin https://github.com/username/Hello-World.git
$ git push origin master
Assicurati di cambiare l'URL con l'URL del tuo repository che hai creato nel passaggio precedente.
Configura un nuovo database MySQL chiamato django_deploy :
$ mysql.server start
$ mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql>
mysql> CREATE DATABASE django_deploy;
Query OK, 1 row affected (0.01 sec)
mysql>
mysql> quit
Bye
Aggiorna settings.py :
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_deploy',
'USER': 'root',
'PASSWORD': 'your_password',
}
}
Installa le dipendenze:
$ pip install -r requirements.txt
$ python manage.py syncdb
$ python manage.py runserver
Esegui il server su http://localhost:8000/admin/ e assicurati di poter accedere all'amministratore. Aggiungi alcuni elementi a Whatever
oggetto. Uccidi il server.
Converti da MySQL a Postgres
Nota: In questa ipotetica situazione, supponiamo che tu stia lavorando a questo progetto per un po' di tempo usando MySQL e ora desideri convertirlo in Postgres.
Installa le dipendenze:
$ pip install psycopg2
$ pip install py-mysql2pgsql
Configura un database Postgres:
$ psql -h localhost
psql (9.2.4)
Type "help" for help.
michaelherman=# CREATE DATABASE django_deploy;
CREATE DATABASE
michaelherman=# \q
Migrare i dati:
$ py-mysql2pgsql
Questo comando crea un file chiamato mysql2pgsql.yml , contenente le seguenti informazioni:
mysql:
hostname: localhost
port: 3306
socket: /tmp/mysql.sock
username: foo
password: bar
database: your_database_name
compress: false
destination:
postgres:
hostname: localhost
port: 5432
username: foo
password: bar
database: your_database_name
Aggiornalo per la tua configurazione. Questo esempio copre solo la conversione di base. Puoi anche includere o escludere determinate tabelle. Vedi l'esempio completo qui.
Trasferisci i dati:
$ py-mysql2pgsql -v -f mysql2pgsql.yml
Una volta trasferiti i dati, assicurati di aggiornare il tuo settings.py file:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql_psycopg2",
"NAME": "your_database_name",
"USER": "foo",
"PASSWORD": "bar",
"HOST": "localhost",
"PORT": "5432",
}
}
Infine, risincronizza il database, esegui il server di prova e aggiungi un altro elemento al database per assicurarti che la conversione sia riuscita.
Aggiungi un file local_settings.py
Aggiungendo un local_settings.py puoi estendere il file settings.py file con le impostazioni rilevanti per il tuo ambiente locale, mentre il principale settings.py viene utilizzato esclusivamente per i tuoi ambienti di staging e produzione.
Assicurati di aggiungere local_settings.py al tuo .gitignore file per mantenere il file fuori dai tuoi repository. Coloro che desiderano utilizzare o contribuire al tuo progetto possono quindi clonare il repository e creare il proprio local_settings.py file specifico per il proprio ambiente locale.
Sebbene questo metodo di utilizzo di due file di impostazioni sia una convenzione da diversi anni, molti sviluppatori Python ora utilizzano un altro modello chiamato The One True Way. Potremmo esaminare questo modello in un tutorial futuro.
Aggiorna settings.py
Dobbiamo apportare tre modifiche al nostro attuale settings.py file:
Modifica DEBUG
modalità su falso:
DEBUG = False
Aggiungi il codice seguente in fondo al file:
# Allow all host hosts/domain names for this site
ALLOWED_HOSTS = ['*']
# Parse database configuration from $DATABASE_URL
import dj_database_url
DATABASES = { 'default' : dj_database_url.config()}
# Honor the 'X-Forwarded-Proto' header for request.is_secure()
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# try to load local_settings.py if it exists
try:
from local_settings import *
except Exception as e:
pass
Aggiorna le impostazioni del database:
# we only need the engine name, as heroku takes care of the rest
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql_psycopg2",
}
}
Crea il tuo local_settings.py file:
$ touch local_settings.py
$ pip install dj_database_url
Quindi aggiungi il seguente codice:
from settings import PROJECT_ROOT, SITE_ROOT
import os
DEBUG = True
TEMPLATE_DEBUG = True
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql_psycopg2",
"NAME": "django_deploy",
"USER": "foo",
"PASSWORD": "bar",
"HOST": "localhost",
"PORT": "5432",
}
}
Avvia il server di prova per assicurarti che tutto funzioni ancora. Aggiungi qualche altro record al database.
Impostazione Heroku
Aggiungi un Procfile alla directory principale:
$ touch Procfile
e aggiungi il seguente codice al file:
web: python manage.py runserver 0.0.0.0:$PORT --noreload
Installa la cintura degli strumenti Heroku:
$ pip install django-toolbelt
Blocca le dipendenze:
$ pip freeze > requirements.txt
Aggiorna wsgi.py file:
from django.core.wsgi import get_wsgi_application
from dj_static import Cling
application = Cling(get_wsgi_application())
Testa le impostazioni di Heroku in locale:
$ foreman start
Vai a http://localhost:5000/.
Stai bene? Facciamo funzionare Amazon S3.
Amazon S3
Sebbene sia ipoteticamente possibile ospitare file statici nel repository Heroku, è meglio utilizzare un host di terze parti, soprattutto se si dispone di un'applicazione rivolta al cliente. S3 è facile da usare e richiede solo poche modifiche al tuo settings.py file.
Installa le dipendenze:
$ pip install django-storages
$ pip install boto
Aggiungi storages
e boto
al tuo INSTALLED_APPS
in "impostazioni.py"
Aggiungi il seguente codice in fondo a "settings.py":
# Storage on S3 settings are stored as os.environs to keep settings.py clean
if not DEBUG:
AWS_STORAGE_BUCKET_NAME = os.environ['AWS_STORAGE_BUCKET_NAME']
AWS_ACCESS_KEY_ID = os.environ['AWS_ACCESS_KEY_ID']
AWS_SECRET_ACCESS_KEY = os.environ['AWS_SECRET_ACCESS_KEY']
STATICFILES_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
S3_URL = 'http://%s.s3.amazonaws.com/' % AWS_STORAGE_BUCKET_NAME
STATIC_URL = S3_URL
Le impostazioni dipendenti dall'ambiente AWS vengono archiviate come variabili ambientali. Quindi non dobbiamo impostarli dal terminale ogni volta che eseguiamo il server di sviluppo, possiamo impostarli nel nostro virtualenv activate
sceneggiatura. Prendi il nome del bucket AWS, l'ID chiave di accesso e la chiave di accesso segreta da S3. Apri myenv/bin/activate
e aggiungi il seguente codice (assicurati di aggiungere le informazioni specifiche che hai appena estratto da S3):
# S3 deployment info
export AWS_STORAGE_BUCKET_NAME=[YOUR AWS S3 BUCKET NAME]
export AWS_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXX
export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXX
Disattiva e riattiva il tuo virtualenv, quindi avvia il server locale per assicurarti che le modifiche abbiano effetto:
$ foreman start
Uccidi il server, quindi aggiorna il requirements.txt file:
$ pip freeze > requirements.txt
Spingi su Github e Heroku
Eseguiamo il backup dei nostri file su Github prima di PUSH su Heroku:
$ git add .
$ git commit -m "update project for heroku and S3"
$ git push -u origin master
Crea un progetto/repo di Heroku:
$ heroku create <name>
Chiamalo come preferisci.
PUSH a Heroku:
$ git push heroku master
Invia le variabili ambientali AWS a Heroku
$ heroku config:set AWS_STORAGE_BUCKET_NAME=[YOUR AWS S3 BUCKET NAME]
$ heroku config:set AWS_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXX
$ heroku config:set AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXX
Raccogli i file statici e inviali ad Amazon:
$ heroku run python manage.py collectstatic
Aggiungi database di sviluppo:
$ heroku addons:add heroku-postgresql:dev
Adding heroku-postgresql on deploy_django... done, v13 (free)
Attached as HEROKU_POSTGRESQL_COPPER_URL
Database has been created and is available
! This database is empty. If upgrading, you can transfer
! data from another database with pgbackups:restore.
Use `heroku addons:docs heroku-postgresql` to view documentation.
$ heroku pg:promote HEROKU_POSTGRESQL_COPPER_URL
Promoting HEROKU_POSTGRESQL_COPPER_URL to DATABASE_URL... done
Ora sincronizza il DB:
$ heroku run python manage.py syncdb
Trasferimento dati
Dobbiamo trasferire i dati dal database locale al database di produzione.
Installa il componente aggiuntivo Heroku PGBackups:
$ heroku addons:add pgbackups
Scarica il tuo database locale:
$ pg_dump -h localhost -Fc library > db.dump
Affinché Heroku possa accedere a db dump, devi caricarlo su Internet da qualche parte. Puoi utilizzare un sito Web personale, una casella personale o S3. L'ho semplicemente caricato nel bucket S3.
Importa il dump in Heroku:
$ heroku pgbackups:restore DATABASE http://www.example.com/db.dump
Test
Proviamo per assicurarci che tutto funzioni.
Innanzitutto, aggiorna gli host consentiti al tuo dominio specifico in settings.py :
ALLOWED_HOSTS = ['[your-project-name].herokuapp.com']
Dai un'occhiata alla tua app:
$ heroku open
Tessuto
Fabric viene utilizzato per automatizzare la distribuzione della tua applicazione.
Installa:
$ pip install fabric
Crea il fabfile:
$ touch fabfile.py
Quindi aggiungi il seguente codice:
from fabric.api import local
def deploy():
local('pip freeze > requirements.txt')
local('git add .')
print("enter your git commit comment: ")
comment = raw_input()
local('git commit -m "%s"' % comment)
local('git push -u origin master')
local('heroku maintenance:on')
local('git push heroku master')
local('heroku maintenance:off')
Prova:
$ fab deploy
Hai domande o commenti? Partecipa alla discussione qui sotto.