Lage kokeboken
Siste trinn
Det er mange måter å automatisere prosessen med å sette opp og konfigurere en boks. Uansett grunn, hvis hele systemet vårt på dette tidspunktet består av bare en enkelt boks, er det overkill å sette opp en full SCM (Software Configuration Management)-infrastruktur. Shell-skript er ett alternativ, men vi kan også bruke en nedstrippet versjon av SCM som er tilgjengelig i noen av verktøyene der ute. Chef er et av de populære alternativene og "chef-solo" er Chefs frittstående konfigurasjonsmodus der vi ikke krever en ekstra node for å fungere som en "kokk-server". Alt den trenger er en URL eller en sti til en tarball-pakke som inneholder kokkebøker. Sammenlignet med shell-skript er denne typen tilnærming mer deklarativ og effektiv ut av boksen og er også en god introduksjon for å komme i gang med SCM-er eller IaC-prosesser (Infrastructure as Code).
Noen få andre fordeler med å bruke kokk-solo:
- Komponerbarhet: Bruk fellesskapets kokebøker fra kokkens supermarked eller andre steder.
- Gratis og åpen kildekode; lisensiert under den tillatelige Apache 2.0-lisensen.
- Tilgang til resten av kokkens økosystem (InSpec, ChefSpec, Cookstyle, Foodcritic, chef-shell etc)
- Kokebøkene og oppskriftene kan senere tilpasses til en klient/server-modus.
Og noen ulemper:
- Noen fellesskaps kokebøker på Chef-supermarkedet er utdaterte, ødelagte og ikke vedlikeholdt.
- Chef-solo kan ikke løse avhengigheter på egen hånd.
'Oppskriftene' inne i en kokkebok har en rubinbasert DSL som beskriver at 'ressurser' er i en bestemt tilstand på en node. La oss fortsette med en gjennomgang for å bli kjent med noen få kokk-konsepter som også kan brukes for kokk-solo. Målet vårt er å sette opp en Ubuntu-node som kjører en Python/Django-webapp ved å bruke Gunicorn og NGINX.
Note: We do not necessarily require ChefDK to be installed on our "Chef workstation" (our machine), although with it, we can use 'chef generate' commands to start-off with a directory structure for creating cookbooks, recipes and more. In this article, we will assume ChefDK is installed on our workstation. Commands were run using the version 4.7.26-1 of ChefDK.
(Alt fra dette tidspunktet og fremover, med mindre annet er spesifisert, skal kjøres på vår maskin, også referert til som 'Chef Workstation')
Lage kokeboken
Kokebøker i kokk er en gjenbrukbar enhet som inneholder alt som trengs for å støtte et konfigurasjonsscenario. Kokebøker kan inneholde flere "oppskrifter", og "oppskrifter" består for det meste av ressursmønstre. default.rber standardoppskriften som kjøres når kokeboken refereres til i en kjøreliste . Ulike oppskrifter gir mulighet for separasjon av bekymringer. For denne opplæringen vil vi imidlertid legge til alle ressursdeklarasjoner i én hovedoppskriftsfil, som er default.rb.
Lag en mappe som heter "my-chef-project" og lag en mappe inne i den kalt "kokebøker". Fra ./my-chef-project/cookbooks/, kjør:
$ chef generate cookbook my-cookbook
Katalogstrukturen vår vil nå se slik ut:
.
└── 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
Legger til pakker
Det første trinnet for å sette opp noden vår er å identifisere hvilke pakker som kreves av appen vår. Noden vår er valgt til å være Ubuntu, så vi kan stole på APT-pakkebehandleren for å samle avhengighetene. Installering av pakkene levert av OS-distribusjonen er da en bit av kaken:
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'
Disse er ganske selvforklarende. Den første linjen vil oppdatere apt-depotet, og de følgende linjene vil installere disse pakkene.
Note: The packages following 'nginx' are needed for compiling some of the python dependencies through pip. These may differ based on your python/django project dependencies specified in requirements.txt. You can use a trial and error method to determine these packages that you need to include in your cookbook. To do that, perform a manual sudo pip install -r requirements.txt (Note: This installs packages system wide!) on a freshly instantiated ubuntu machine to see if it runs successfully. If not, the stderr should give you hints on what packages are missing.
Opprette linux-brukere
Når vi er ferdige med å legge til de nødvendige pakkene, må vi opprette en ikke-privilegert Linux-bruker som vil eie applikasjonens kildekode.
user 'bob' do
uid 1212
gid 'users'
home '/home/bob'
shell '/bin/bash'
password '$1$alilbito$C83FsODuq0A1pUMeFPeR10'
end
Merk at passordet er et shadow hash-format som brukes i Linux. Det kan utledes ved hjelp av OpenSSL:
$ openssl passwd -1 -salt alilbitof mypassword
Inkludert appkilden
La oss nå inkludere Django-applikasjonens kildekode i kokeboken vår. Plasser kildekoden i ./my-chef-project/cookbooks/my-cookbook/files/default/myapp/
Opprett ./my-chef-project/cookbooks/my-cookbook/files/defaultkatalogen hvis den ikke eksisterer.
Instruksjoner for å kopiere disse filene til en ekstern plassering på noden vår er beskrevet ved hjelp av ekstern_katalog- ressursen:
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
Trekker inn pythonavhengighetene
For å installere python-pakkene i requirements.txtkan vi bruke execute- ressursen til å kjøre en vilkårlig kommando. I dette tilfellet må vi utføre pip-installasjonskommandoen over den:
execute 'install python dependencies' do
command 'pip3 install -r requirements.txt'
cwd '/home/bob/myapp'
end
Note: Bear in mind that this is going to execute as the root user and the python libraries will be installed system-wide. If our node is designated to exclusively run this one single python app, then it isn't much of a problem. Despite that, a better option to keep things clean and sane is to find and use a community cookbook that manages python installations or 'virtualenvs'. (or at the very least, write a series of execute blocks to replicate this). Using virtualenvs in python ensures that any python based system tools or other python projects will not be affected
Sette opp Gunicorn & NGINX
Nå er det på tide å forberede Gunicorn WSGI HTTP-serveren med NGINX som vår omvendte proxy. Nginx brukes også til å håndtere alle de statiske eiendelene fra Django.
For å feste Gunicorn som en tjeneste på Ubuntu, kan Systemd brukes. Den systemd_unit ressursen er inkludert i Chef siden versjon 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
Nå må vi inkludere en standard NGINX proxy-konfigurasjon til denne Gunicorn-serveren som vist nedenfor. Dette utdraget kan gå inn i ./my-cookbook/templates/nginx.conf.erb. Opprett malkatalogen hvis den ikke eksisterer.
Note: Chef's templates support embedded ruby files that can contain variables, ruby expressions and statements. Although this file has the 'erb' extension, we did not use any of the ruby statements or expressions. Also, for the sake of simplicity, we only have a non HTTPS nginx config here (gentle reminder; please do not do this in production!)
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/;
}
}
Note: There is also an alternative and a better config, where, for instance the Gunicorn server is bound to a unix domain socket instead of a TCP loopback connection. It's worth exploring that for performance reasons.
For å kopiere over denne konfigurasjonen til nettstedsaktivert mappe på noden, bruk malressursen fra Chef.
template '/etc/nginx/sites-available/example.com.conf' do
source 'nginx.conf.erb'
owner 'root'
group 'root'
mode '0744'
end
Aktivering av konfigurasjoner på nginx gjøres vanligvis ved å lage en symbolkobling som peker til konfigurasjonen på sites-availablei nginx- sites-enabledmappen. Symbolkoblinger kan deklareres i kokkebøker med koblingsressursen som vist nedenfor:
link '/etc/nginx/sites-enabled/example.com.conf' do
to '/etc/nginx/sites-available/example.com.conf'
end
og for å slette standard konfigurasjonssymlink:
link '/etc/nginx/sites-enabled/default' do
action :delete
end
Starter NGINX
Og til slutt, for å fyre opp nginx-tjenesten:
service 'nginx' do
action :enable
action :start
end
Rundlister
Kjørelister i kokk er en ordnet liste over roller eller oppskrifter i en kokebok som vil bli utført i rekkefølge på noden. Vi har én kokebok "min-kokebok" og "standard"-oppskriften inni den som vi må kjøre på Ubuntu-boksen, så runlist.json i prosjektkatalogen vår ( ./my-chef-project/runlist.json) skal se slik ut:
{
"run_list": [
"recipe[my-cookbook::default]"
]
}
Siste trinn
Vår kokebok for Chef solo er klar til å bli servert. Det er på tide å klargjøre en Ubuntu 18.04-maskin og installere ChefDK på den:
$ ssh root@example.com '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'
Når vi går tilbake til Chef-arbeidsstasjonen vår , er alt vi trenger å gjøre å legge kokebok-mappen i en tarball, overføre den tarballen sammen med runlist.jsontil den eksterne noden vi klargjorde ovenfor og kjøre chef-solo-kommandoen:
(Kommandoen nedenfor skal kjøres inne i noden eller 'kokkklienten' og ikke Chef Workstation)
$ chef-solo --recipe-url $(pwd)/chef-solo.tar.gz -j $(pwd)/runlist.json --chef-license=accept
Eller her er en one-liner (som skal kjøres fra ./my-chef-project/CWD på Chef Workstation):
tar zvcf chef-solo.tar.gz ./cookbooks &&\
scp chef-solo.tar.gz runlist.json root@example.com:~/ &&\
ssh root@example.com 'chef-solo --recipe-url $(pwd)/chef-solo.tar.gz -j $(pwd)/runlist.json --chef-license=accept'
Det er det! Se standardutgangen fylles opp med kokkaktivitet som prøver å konvergere noden din til det du har spesifisert i kokebøkene. Chef-solo vil installere alle edelstenene som kreves for alle kokebøkene. Hvis chef-solo-kommandoen er vellykket, vil vi ha en fungerende Django-applikasjon som kjører bak nginx på Ubuntu-boksen. Naviger til domenet/IP-en for å teste det.
Note: Remember that in django you may need to set this domain/ip in the ALLOWED_HOSTS list in settings.py.
Reagerer på endringer
Hver gang vi gjør endringer i innholdet i prosjektkatalogen vår (oppskrifter, maler eller applikasjonens kildekode osv.), kjør ganske enkelt den ovennevnte one-liner fra prosjektkatalogen.
Tip: If the cookbook is version controlled with git (as it should), one good recommendation is to set git hooks to run this one-liner.
Vert for tarballen (valgfritt)
Hvis du ser nøye på den siste chef-solo-kommandoen, legg merke til at den --recipe-urler ment å ta en URL. Dette betyr at du kan ha en arbeidsflyt der en CI vil bygge din chef-solo tarball, laste den opp et sted og konfigurere noden til å trekke fra den med jevne mellomrom.
Tip: Use curl to pull the changed tarball periodically as a cronjob. curl -z $file will honor If-Modified-Since headers and will only download the tar ball if the remote file has been changed since the timestamp on the existing local $file.