2009-09-10 2 views
23

Ho cercato un modo migliore per gestire le impostazioni specifiche del sito (in questo caso, il file settings.py di django).Gestisci in modo elegante le impostazioni/configurazione specifiche del sito in svn/hg/git/etc?

La struttura e i campi di settings.py sono abbastanza coerenti, ma i valori differiscono tra le caselle dello sviluppatore, l'integrazione, il controllo qualità, i test e gli ambienti di produzione.

Qual è un modo elegante per controllare le impostazioni mantenendo ancora le modifiche tra diverse caselle?

Sono anche preoccupato di avere dati sensibili (ad esempio le password del database) nel controllo del codice sorgente, ma voglio implementazioni automatizzate.

Esempi di ciò che abbiamo usato:

  • settings.py imposta i valori comuni quindi carica un file di impostazioni secondarie in base al nome host o il nome utente.

  • iniettare valori nel file settings.py utilizzando uno script di distribuzione. Ma questo sposta semplicemente il problema alla gestione degli script di distribuzione invece dello script settings.py.

Chiunque ha un approccio particolarmente elegante?

+0

Vedere anche questa buona risposta qui che utilizza le credenziali di accesso correnti per differenziare le impostazioni specifiche (ma mantenerle tutte in controllo di versione): http://stackoverflow.com/questions/6009/how-do-you-deal- con-configuration-files-in-source-control/65226 # 65226 –

risposta

18

Creare un file settings.py principale, che dovrebbe includere questo:

# Pull in hostname-based changes. 
import socket 
HOSTNAME = socket.gethostname().lower().split('.')[0].replace('-','') 

try: 
    exec "from myproject.settings.host_%s import *" % HOSTNAME 
except ImportError: 
    pass 

# Pull in the local changes. 
try: 
    from myproject.settings.local import * 
except ImportError: 
    pass 

Ora si crea un nuovo file di impostazioni per ciascun nome host a cui tieni. Ma questi sono veramente piccoli. Ognuno dei file del server di produzione contiene solo:

from myproject.settings.production import * 

e i server di gestione temporanea sono:

from myproject.settings.staging import * 

Ora è possibile creare un file production.py con le sostituzioni di produzione per le impostazioni, uno staging.py, e presto. È possibile creare nuovi file per ciascun ruolo riprodotto da un server.

Infine, è possibile creare un file local.py su qualsiasi computer (comprese le macchine degli sviluppatori) con sostituzioni locali, e contrassegnare questo file come ignorata da controllo del codice sorgente, in modo che le modifiche non vengono registrati.

Abbiamo usato questa struttura per anni, funziona davvero bene.

+0

Grazie Ned. Metti i file delle impostazioni specifici del sito nel controllo del codice sorgente? Sono preoccupato di avere password nei file di impostazioni nel controllo del codice sorgente. – Parand

+0

Abbiamo messo tutto tranne local.py nel controllo del codice sorgente. Non ho una soluzione per il problema della password. –

+3

Questo sembra un ottimo approccio, ma non riesco a capire la struttura della directory. Disponi di un settings.py e di un pacchetto/directory delle impostazioni? In tal caso, come evitare i conflitti di denominazione? (Scusa se è davvero ovvio). – donturner

4

+1 per la risposta di Ned, ma voglio menzionare una leggera variazione.

Vedo le impostazioni di Django che rientrano in 2 aree: progetto e istanza.

Le impostazioni del progetto sono comuni a tutte le istanze (dev, testing, produzione, più siti in produzione) e le impostazioni di istanza sono locali solo per quella specifica istanza del server.

Le impostazioni del progetto sono cose come INSTALLED_APPS (anche se le impostazioni locali possono anche includere questo per aggiungere cose come la barra di debug di django per gli sviluppatori), MIDDLEWARE_CLASSES e TEMPLATE_LOADERS. Le impostazioni delle istanze sono cose come le impostazioni del database, le impostazioni MEDIA_URL, ecc.

Le impostazioni di progetto vanno a settings.py e le impostazioni di istanza in local_settings.py, che viene importata in settings.py. local_settings.py è elencato in .gitignore e le impostazioni del progetto sono memorizzate in git.

Ho provato diverse altre varianti su questo ma sono finito qui perché è molto più semplice.

L'unica volta che non mi piace questa configurazione è per più siti (usando Django siti quadro), che finiscono per proliferare in cose come sitename_settings.py che importa sitename_local_settings.py ecc

Infine, io mantengo una local_settings_template.py in git, da utilizzare come punto di partenza per nuove istanze e per gli sviluppatori per tenere traccia delle modifiche che potrebbero aver bisogno delle proprie impostazioni locali.

0

Il mio modo di gestire questa situazione è quello di avere un file di base settings.py e quindi un file di impostazioni per ogni ambiente (ad esempio dev_settings.py, live_settings.py)

Nella parte superiore di ogni file specifico ambiente ho

from settings import * 

posso quindi semplicemente ignorare le impostazioni ho bisogno di cambiare in un ambiente base specifica

per garantire ogni ambiente utilizza le impostazioni corrette ho appena modificare la variabile d'ambiente DJANGO_SETTINGS_MODULE. Il modo in cui lo fai dipende da come stai distribuendo django (mod_wsgi, mod_python e così via ...)

3

Consente di separare questi due problemi distinti: 1) gestire le impostazioni specifiche del sito e 2) gestire i segreti.

1) le impostazioni specifiche del sito

Versione tutto (tranne i segreti), impostazioni anche specifiche per sviluppatori.

Con Django e molti altri software, il file di configurazione è un pezzo di codice eseguibile, che semplifica il caricamento di impostazioni di configurazione comuni e l'override di tutto ciò che deve essere sovrascritto. In questo modo puoi rimanere DRY.

# settings_prod.py 
from settings_base import * 
... # override whatever needs to be overridden for production environment 

Così ora avete settings_base.py, settings_prod.py, settings_dev.py, settings_developper_john.py, ecc Come si fa a dire Django quale usare?

La distribuzione del file delle impostazioni appropriato sul server è un'attività per lo script di distribuzione, credo. La script di distribuzione saprebbe che si sta distribuendo per ospitare prod17 che è un server di produzione, in modo che avrebbe generato al volo un file settings.py che sarebbe simile a questa:

# settings.py (generated by deployment script) 
from settings_prod import * 

Un'altra soluzione è quella di avere quella logica in un generico settings.py: si potrebbe leggere una variabile d'ambiente o ottenere il nome host (o applicare qualsiasi altra logica) e caricare il modulo impostazioni appropriate:

# settings.py 
import os 
if os.environ["MY_APP_ENV"] == "prod": 
    from settings_prod import * 
elif ... 

la mia soluzione preferita per le impostazioni di Django è described here.

Per qualsiasi altro software che non sia flessibile con il suo file di configurazione, l'opzione migliore è probabilmente avere lo script di distribuzione generare il file di configurazione, possibilmente utilizzando i modelli (strumenti come Chef o Puppet rendono questo facile). Ciò consente di rimanere asciutti: ad esempio, un software richiede un file flat config.ini, quindi lo script di distribuzione può leggere un file common.ini e un file production.ini, unirli in modo appropriato e produrre un config.ini pronto per essere distribuito alla produzione.

Gestione dei segreti

Prima di tutto, non conservare le password in un sistema di controllo versione. :-)

Una soluzione per la gestione dei segreti è che lo script di distribuzione trasferisca i segreti. Ad esempio, bob è responsabile della distribuzione di applicazioni Web, conosce la password del database, quindi quando lancia lo script di distribuzione, viene richiesto per la password del database e lo script lo trasferisce al server. Oppure lo script di distribuzione legge semplicemente la password in un file sul computer di Bob e la trasferisce. Questa è probabilmente la soluzione più comune. Va bene nella maggior parte dei casi.

   secrets 
deployer ================> server 

Se avete bisogno di automatizzare la creazione di macchine virtuali e non si desidera che il-deployer automatizzato per conoscere un segreto, allora si potrebbe includere i segreti del VM-immagine. Ovviamente qualcuno deve includere i segreti nell'immagine della VM in primo luogo.

    VM image including secrets 
human deployer -------------------------------+ 
               | 
               | 
        image_name    v 
automated deployer ==============> Cloud Service ========> VM including secrets 

Il problema con questa soluzione è che è necessario generare una nuova immagine VM ogni volta che vengono apportate modifiche segrete. Se vuoi evitarlo, potresti volere un "server segreto": un server per gestire i segreti di ogni altro server. Quindi l'unico segreto che è necessario includere nell'immagine della VM è il segreto di boot necessario per connettersi al "server segreto".

step 1: 

       VM image including bootstrap secret 
human deployer -----------------------------------+ 
                | 
                | 
        image_name     v 
automated deployer ==================> Cloud Service ========> VM including secrets 


step 2: 

    bootstrap secret 
    ==================> 
VM      Secret Server 
    <================== 
     secrets 

Ad esempio, il server segreto potrebbe essere un server Chef, i segreti potrebbero essere conservare in sacchetti di dati crittografati, e il segreto di bootstrap sarebbe la chiave per decifrare queste borse.