Esistono molti modi per automatizzare il processo di installazione e configurazione di un box. Per qualsiasi motivo, se il nostro intero sistema a questo punto comprende una sola casella, la creazione di un'infrastruttura SCM (Software Configuration Management) completa è eccessiva. Gli script di shell sono un'opzione, ma potremmo anche utilizzare una versione ridotta di SCM che è disponibile in alcuni degli strumenti disponibili. Chef è una delle opzioni più popolari e "chef-solo" è la modalità di configurazione autonoma di Chef in cui non è necessario un nodo aggiuntivo per fungere da "chef-server". Tutto ciò che serve è un URL o un percorso per un pacchetto tarball che contiene libri di cucina per chef. Rispetto agli script di shell, questo tipo di approccio è più dichiarativo ed efficiente pronto all'uso ed è anche una buona introduzione per iniziare con i processi SCM o IaC (Infrastruttura come codice).
Alcuni altri vantaggi nell'uso di chef-solo:
- Composibilità: utilizzare i libri di cucina della comunità dal supermercato dello chef o da altri luoghi.
- Libero e open source; concesso in licenza con la permissiva licenza Apache 2.0.
- Accesso al resto dell'ecosistema di Chef (InSpec, ChefSpec, Cookstyle, Foodcritic, chef-shell ecc.)
- I libri di cucina e le ricette possono essere successivamente adattati a una modalità client / server.
E alcuni aspetti negativi:
- Alcuni libri di cucina della comunità nel supermercato Chef sono obsoleti, rotti e non mantenuti.
- chef-solo non può risolvere da solo le dipendenze.
Le "ricette" all'interno di un "libro di cucina" di uno chef hanno un DSL basato su rubini che descrive le "risorse" per trovarsi in uno stato particolare su un nodo. Procediamo con una procedura dettagliata per conoscere alcuni concetti dello Chef applicabili anche allo chef-solo. Il nostro obiettivo è configurare un nodo Ubuntu che esegue un'app Web Python / Django utilizzando Gunicorn e NGINX.
Nota: non è necessario che ChefDK sia installato sulla nostra "Stazione di lavoro Chef" (la nostra macchina), sebbene con esso sia possibile utilizzare i comandi 'chef generate' per iniziare con una struttura di directory per la creazione di libri di cucina, ricette e altro. In questo articolo, supponiamo che ChefDK sia installato sulla nostra workstation. I comandi sono stati eseguiti utilizzando la versione 4.7.26-1 di ChefDK.
(Da questo punto in poi tutto, se non diversamente specificato, deve essere eseguito sulla nostra macchina, indicata anche come "Chef Workstation")
Creare il libro di cucina
I libri di cucina nello chef sono unità riutilizzabili che contengono tutto il necessario per supportare uno scenario di configurazione. I libri di cucina possono contenere più "ricette" e "ricette" principalmente costituite da modelli di risorse. default.rb
è la ricetta predefinita che verrà eseguita quando si fa riferimento al ricettario in una lista di esecuzione . Diverse ricette consentono la separazione delle preoccupazioni. Per questo tutorial, tuttavia, aggiungeremo tutte le dichiarazioni delle risorse in un file di ricette principale, che è il default.rb
.
Crea una cartella denominata "my-chef-project" e crea una cartella al suo interno chiamata "libri di cucina". Da ./my-chef-project/cookbooks/
, esegui:
$ chef generate cookbook my-cookbook
La nostra struttura di directory ora apparirà così:
.
└── my-chef-project
└── cookbooks
└── my-cookbook
├── CHANGELOG.md
├── LICENSE
├── Policyfile.rb
├── README.md
├── chefignore
├── kitchen.yml
├── metadata.rb
├── recipes
│ └── default.rb
├── spec
│ ├── spec_helper.rb
│ └── unit
│ └── recipes
│ └── default_spec.rb
└── test
└── integration
└── default
└── default_test.rb
Aggiunta di pacchetti
Il primo passo per configurare il nostro nodo è identificare quali pacchetti sono richiesti dalla nostra app. Il nostro nodo è selezionato per essere Ubuntu, quindi possiamo fare affidamento sul gestore di pacchetti APT per raccogliere le dipendenze. L'installazione dei pacchetti forniti dalla distribuzione del sistema operativo è quindi un gioco da ragazzi:
apt_update
package 'python3'
package 'python3-pip'
package 'nginx'
package 'pkg-config'
package 'libcairo2-dev'
package 'libjpeg-dev'
package 'libgif-dev'
package 'libgirepository1.0-dev'
Questi sono praticamente autoesplicativi. La prima riga aggiornerà il repository apt e le seguenti righe installeranno quei pacchetti.
Nota: i pacchetti che seguono 'nginx' sono necessari per compilare alcune dipendenze di Python tramite pip. Questi possono differire in base alle dipendenze del tuo progetto python / django specificate in requirements.txt
. È possibile utilizzare un metodo di prova ed errore per determinare questi pacchetti che è necessario includere nel libro di cucina. Per fare ciò, esegui un manuale sudo pip install -r requirements.txt
(Nota: questo installa i pacchetti a livello di sistema!) Su una macchina Ubuntu appena istanziata per vedere se funziona correttamente. Altrimenti, lo stderr dovrebbe darti suggerimenti su quali pacchetti mancano.
Creazione di utenti Linux
Dopo aver aggiunto i pacchetti richiesti, è necessario creare un utente Linux non privilegiato che sarà proprietario del codice sorgente dell'applicazione.
user 'bob' do
uid 1212
gid 'users'
home '/home/bob'
shell '/bin/bash'
password '$1$alilbito$C83FsODuq0A1pUMeFPeR10'
end
Nota che la password è un formato hash ombra usato in Linux. Può essere derivato usando OpenSSL:
$ openssl passwd -1 -salt alilbitof mypassword
Inclusa la fonte dell'app
Ora includiamo il codice sorgente dell'applicazione Django nel nostro ricettario. Inserisci il codice sorgente all'interno ./my-chef-project/cookbooks/my-cookbook/files/default/myapp/
Crea la ./my-chef-project/cookbooks/my-cookbook/files/default
directory se non esiste.
Le istruzioni per copiare questi file in una posizione remota sul nostro nodo sono descritte usando la risorsa directory_directory :
remote_directory '/home/bob/myapp' do
source 'myapp' # This is the name of the folder containing our source code that we kept in ./my-cookbook/files/default/
owner 'bob'
group 'users'
mode '0755'
action :create
end
Tirando le dipendenze di Python
Per installare i pacchetti python in requirements.txt
, possiamo usare il eseguire risorsa per eseguire un comando arbitrario. In questo caso, dobbiamo eseguire il comando pip install su di esso:
execute 'install python dependencies' do
command 'pip3 install -r requirements.txt'
cwd '/home/bob/myapp'
end
Nota: tenere presente che questo verrà eseguito come utente root e le librerie python verranno installate a livello di sistema. Se il nostro nodo è progettato per eseguire esclusivamente questa singola app Python, non è un grosso problema. Nonostante ciò, un'opzione migliore per mantenere le cose pulite e sane è quella di trovare e usare un libro di cucina della comunità che gestisca le installazioni di Python o "virtualenvs". (o per lo meno, scrivi una serie di blocchi di esecuzione per replicarlo). L'uso di virtualenvs in Python garantisce che non vengano interessati gli strumenti di sistema basati su Python o altri progetti Python
Installazione di Gunicorn e NGINX
Ora è il momento di preparare il server HTTP WSGI di Gunicorn con NGINX come proxy inverso. Nginx è anche usato per gestire tutte le risorse statiche di Django.
Per legare Gunicorn come servizio su Ubuntu, è possibile utilizzare Systemd. La risorsa systemd_unit è inclusa in Chef dalla versione 12.11.
systemd_unit 'gunicorn.service' do
content({
Unit: {
Description: 'Django on Gunicorn',
After: 'network.target',
},
Service: {
ExecStart: '/usr/local/bin/gunicorn --workers 3 --bind localhost:8080 myapp.wsgi:application',
User: 'bob',
Group: 'www-data',
WorkingDirectory: '/home/bob/myapp'
Restart: 'always',
},
Install: {
WantedBy: 'multi-user.target',
}
})
action [:create, :enable, :start]
end
Ora dobbiamo includere una configurazione proxy NGINX standard su questo server Gunicorn come mostrato di seguito. Questo frammento può entrare ./my-cookbook/templates/nginx.conf.erb
. Creare la directory dei modelli se non esiste.
Nota: i modelli di Chef supportano file ruby incorporati che possono contenere variabili, espressioni e dichiarazioni ruby. Sebbene questo file abbia l'estensione 'erb', non abbiamo usato nessuna delle dichiarazioni o espressioni ruby. Inoltre, per semplicità, qui abbiamo solo una configurazione nginx non HTTPS (promemoria gentile; per favore non farlo in produzione!)
server {
listen 80;
server_name http://example.com/;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/bob/myapp/myapp/static;
}
location / {
include proxy_params;
proxy_pass http://localhost:8080/;
}
}
Nota: esiste anche un'alternativa e una configurazione migliore, in cui, ad esempio, il server Gunicorn è associato a un socket di dominio unix anziché a una connessione di loopback TCP. Vale la pena esplorarlo per motivi di prestazioni.
Per copiare su questa configurazione nella cartella abilitata per i siti sul nodo, utilizzare la risorsa modello di Chef.
template '/etc/nginx/sites-available/example.com.conf' do
source 'nginx.conf.erb'
owner 'root'
group 'root'
mode '0744'
end
L'attivazione delle configurazioni su nginx avviene normalmente creando un collegamento simbolico che punta alla configurazione sites-available
nella sites-enabled
cartella di nginx . I link simbolici possono essere dichiarati nei libri di cucina dello chef con la risorsa link come mostrato di seguito:
link '/etc/nginx/sites-enabled/example.com.conf' do
to '/etc/nginx/sites-available/example.com.conf'
end
e per eliminare il link simbolico di configurazione predefinito:
link '/etc/nginx/sites-enabled/default' do
action :delete
end
Avvio di NGINX
E infine, per avviare il servizio nginx:
service 'nginx' do
action :enable
action :start
end
Runlists
Le run-list in chef sono un elenco ordinato di ruoli o ricette in un ricettario che verrà eseguito in sequenza sul nodo. Abbiamo un libro di cucina "mio-libro di cucina" e la ricetta "predefinita" al suo interno che dobbiamo eseguire sulla scatola di Ubuntu, quindi runlist.json nella nostra directory di progetto ( ./my-chef-project/runlist.json
) dovrebbe assomigliare a questo:
{
"run_list": [
"recipe[my-cookbook::default]"
]
}
Passaggi finali
Il nostro libro di cucina per Chef Solo è pronto per essere servito. È ora di eseguire il provisioning di una macchina Ubuntu 18.04 e installare ChefDK su di essa:
$ ssh [email protected] 'apt-get update && yes | apt-get install curl && curl https://packages.chef.io/files/current/chefdk/4.7.45/ubuntu/18.04/chefdk_4.7.45-1_amd64.deb -o chefdk.deb && yes | dpkg -i chefdk.deb && rm chefdk.deb'
Tornando alla nostra stazione di lavoro Chef , tutto ciò che dobbiamo fare è mettere la cartella dei libri di cucina all'interno di un tarball, trasferire quel tarball insieme runlist.json
al nodo remoto di cui abbiamo eseguito il provisioning sopra ed eseguire il comando chef-solo:
(Il comando seguente deve essere eseguito all'interno del nodo o del "client client" e non della stazione di lavoro Chef)
$ chef-solo --recipe-url $(pwd)/chef-solo.tar.gz -j $(pwd)/runlist.json --chef-license=accept
Oppure ecco un one-liner (da eseguire da ./my-chef-project/
CWD su Chef Workstation):
tar zvcf chef-solo.tar.gz ./cookbooks &&\
scp chef-solo.tar.gz runlist.json [email protected]:~/ &&\
ssh [email protected] 'chef-solo --recipe-url $(pwd)/chef-solo.tar.gz -j $(pwd)/runlist.json --chef-license=accept'
Questo è tutto! Guarda l'output standard riempire con l'attività dello Chef cercando di convertire il tuo nodo in quello che hai specificato nei libri di cucina. Chef-solo installerà tutte le gemme necessarie per tutti i libri di cucina. Se il comando chef-solo ha esito positivo, avremo un'applicazione Django funzionante in esecuzione dietro nginx sulla scatola di Ubuntu. Passare al dominio / IP per testarlo.
Nota: ricorda che in django potrebbe essere necessario impostare questo dominio / ip ALLOWED_HOSTS
nell'elenco in settings.py
.
Rispondere alle modifiche
Ogni volta che apportiamo una modifica al contenuto della nostra directory di progetto (ricette, modelli o codice sorgente dell'applicazione, ecc.), Eseguiamo semplicemente la riga precedente sopra dalla directory di progetto.
Suggerimento: se il libro di cucina è controllato in versione con git (come dovrebbe), una buona raccomandazione è quella di impostare i ganci git per eseguire questo one-liner.
Ospitare il tarball (opzionale)
Se osservi attentamente l'ultimo comando chef-solo, nota che --recipe-url
è destinato a prendere un URL. Ciò significa che puoi avere un flusso di lavoro in cui un elemento della configurazione costruirà il tuo tarball chef-solo, caricarlo da qualche parte e configurare il nodo per estrarre periodicamente da esso.
Suggerimento: Usa l'arricciatura per estrarre periodicamente il tarball modificato come cronjob. curl -z $file
onorerà le If-Modified-Since
intestazioni e scaricherà la tar ball solo se il file remoto è stato modificato dal timestamp sul locale esistente $file
.