ProHoster > Blog > uprava > Razvoj aplikacija i Blue-Green implementacija, na temelju metodologije The Twelve-Factor App s primjerima u php-u i dockeru
Razvoj aplikacija i Blue-Green implementacija, na temelju metodologije The Twelve-Factor App s primjerima u php-u i dockeru
Jednostavnim riječima, ovaj je dokument osmišljen kako bi pojednostavio razvoj SaaS aplikacija, pomažući informiranjem programera i DevOps inženjera o problemima i praksama s kojima se najčešće susreće u razvoju modernih aplikacija.
Dokument su izradili programeri platforme Heroku.
Aplikacija Twelve-Factor može se primijeniti na aplikacije napisane u bilo kojem programskom jeziku i koristeći bilo koju kombinaciju pozadinskih usluga (baze podataka, redovi poruka, predmemorije itd.).
Ukratko o čimbenicima na kojima se temelji ova metodologija:
Baza koda – Jedna baza koda koja se prati u kontroli verzija – više implementacija
Ovisnosti – Eksplicitno deklarirajte i izolirajte ovisnosti
Konfiguracija – Spremite konfiguraciju u vrijeme izvođenja
Usluge podrške – Razmotrite pozadinske usluge kao dodatne resurse
Izgradi, pusti, pokreni – Strogo odvojite faze montaže i izvedbe
procesi – Pokrenite aplikaciju kao jedan ili više procesa bez stanja
Povezivanje porta – Izvoz usluga putem vezivanja porta
Paralelizam – Skalirajte svoju aplikaciju pomoću procesa
Jednokratnost – Povećajte pouzdanost uz brzo pokretanje i čisto gašenje
Paritet razvoja/operacije aplikacije – Neka vaša razvojna, scenska i proizvodna okruženja budu što sličnija
Sječa drva – Pregledajte dnevnik kao tok događaja
Administrativni poslovi – Obavljanje zadataka administracije/upravljanja korištenjem ad hoc procesa
Možete dobiti više informacija o 12 faktora iz sljedećih izvora:
Plavo-zelena implementacija je metoda isporuke aplikacije na proizvodnja na način da krajnji klijent ne vidi nikakve promjene sa svoje strane. Drugim riječima, implementacija aplikacije s nulom stanke.
Klasična shema BG Deploy izgleda kao ona prikazana na slici ispod.
U startu postoje 2 fizička servera sa apsolutno istim kodom, aplikacijom, projektom, a tu je i ruter (balanser).
Usmjerivač inicijalno usmjerava sve zahtjeve na jedan od poslužitelja (zelen).
U trenutku kada trebate ponovno izdati, cijeli projekt se ažurira na drugom poslužitelju (plava), koji trenutno ne obrađuje nijedan zahtjev.
Nakon što je kod uključen plava poslužitelj je potpuno ažuriran, usmjerivač dobiva naredbu za prebacivanje zelena na plava poslužitelju.
Sada svi klijenti vide rezultat izvršavanja koda plava poslužitelju.
Neko vrijeme, zelen poslužitelj služi kao rezervna kopija u slučaju neuspješne implementacije na plava poslužitelj, au slučaju kvara i grešaka, usmjerivač prebacuje korisnički tok natrag na zelen server sa starom stabilnom verzijom, a novi kod se šalje na reviziju i testiranje.
I na kraju procesa, ažurira se na isti način zelen poslužitelj. Nakon što ga ažurira, usmjerivač prebacuje tijek zahtjeva natrag na zelen poslužitelju.
Sve to izgleda jako dobro i na prvi pogled ne bi trebalo biti nikakvih problema.
Ali budući da živimo u modernom svijetu, opcija s fizičkim prebacivanjem kako je naznačeno u klasičnoj shemi ne odgovara nam. Za sada zabilježite podatke, vratit ćemo im se kasnije.
Loš i dobar savjet
Izjava o odricanju od odgovornosti: Primjeri u nastavku pokazuju pomoćne programe/metodologije koje koristim, možete koristiti apsolutno sve alternative sa sličnim funkcijama.
Većina primjera će se na ovaj ili onaj način presijecati s web razvojem (ovo je iznenađenje), s PHP-om i Dockerom.
Odlomci u nastavku daju jednostavan praktični opis upotrebe faktora koristeći konkretne primjere; ako želite saznati više teorije o ovoj temi, slijedite gornje veze do izvornog izvora.
1. Baza koda
Koristite FTP i FileZilla za učitavanje datoteka na poslužitelje jednu po jednu, nemojte pohranjivati kod nigdje osim na produkcijskom poslužitelju.
Projekt uvijek treba imati jedinstvenu bazu koda, odnosno sav kod dolazi iz jednog ići spremište. Poslužitelji (production, staging, test1, test2...) koriste kod iz ogranaka jednog zajedničkog repozitorija. Na taj način postižemo dosljednost koda.
2. Ovisnosti
Preuzmite sve biblioteke u mapama izravno u korijen projekta. Napravite ažuriranja jednostavnim prijenosom novog koda u mapu s trenutnom verzijom biblioteke. Instalirajte sve potrebne uslužne programe izravno na glavni poslužitelj na kojem se izvodi još 20 usluga.
Projekt uvijek treba imati jasno razumljiv popis ovisnosti (pod ovisnostima također mislim na okolinu). Sve ovisnosti moraju biti eksplicitno definirane i izolirane.
Uzmimo kao primjer kompozitor и Lučki radnik.
kompozitor — upravitelj paketa koji vam omogućuje instaliranje biblioteka u PHP-u. Skladatelj vam omogućuje da navedete verzije striktno ili slobodno i eksplicitno ih definirate. Na poslužitelju može postojati 20 različitih projekata i svaki će imati osobni popis paketa i biblioteka neovisno jedan o drugom.
Lučki radnik — uslužni program koji vam omogućuje da definirate i izolirate okruženje u kojem će se aplikacija izvoditi. Sukladno tome, baš kao i kod skladatelja, ali temeljitije, možemo utvrditi s čime aplikacija radi. Odaberite određenu verziju PHP-a, instalirajte samo pakete potrebne za rad projekta, bez dodavanja bilo čega dodatnog. I što je najvažnije, bez uplitanja u pakete i okruženje glavnog računala i drugih projekata. Odnosno, svi projekti na poslužitelju koji se izvode kroz Docker mogu koristiti apsolutno bilo koji skup paketa i potpuno drugačije okruženje.
3. Konfiguracija
Pohranite konfiguracije kao konstante izravno u kod. Odvojene konstante za testni poslužitelj, odvojene za proizvodnju. Povežite rad aplikacije ovisno o okruženju izravno u poslovnoj logici projekta koristeći if else konstrukcije.
Konfiguracije - to je jedini način na koji bi se implementacije projekta trebale razlikovati. U idealnom slučaju, konfiguracije bi se trebale proslijediti kroz varijable okoline (env vars).
Odnosno, čak i ako pohranite nekoliko konfiguracijskih datoteka .config.prod .config.local i preimenujete ih u vrijeme postavljanja u .config (glavna konfiguracija iz koje aplikacija čita podatke) - to neće biti pravi pristup jer u tom će slučaju informacije iz konfiguracija biti javno dostupne svim programerima aplikacija, a podaci s proizvodnog poslužitelja bit će ugroženi. Sve konfiguracije moraju biti pohranjene izravno u sustavu za implementaciju (CI/CD) i generirane za različita okruženja s različitim vrijednostima potrebnim za određeno okruženje u trenutku implementacije.
4. Usluge trećih strana
Budite striktno vezani za okruženje, koristite različite veze za iste usluge u određenim okruženjima.
Zapravo, ova se točka snažno preklapa s točkom o konfiguracijama, budući da se bez ove točke ne mogu izraditi normalni podaci o konfiguraciji i, općenito, mogućnost konfiguracije neće biti ništa.
Sve veze s vanjskim servisima, kao što su poslužitelji čekanja, baze podataka, servisi za predmemoriju, moraju biti isti i za lokalno okruženje i za okruženje treće strane/produkciju. Drugim riječima, u bilo kojem trenutku, promjenom niza veze, mogu zamijeniti pozive prema bazi #1 s bazom #2 bez promjene koda aplikacije. Ili, gledajući unaprijed, kao primjer, kada skalirate uslugu, nećete morati specificirati vezu na bilo koji poseban način za dodatni poslužitelj predmemorije.
5. Izgradite, pustite, izvršite
Imajte samo konačnu verziju koda na poslužitelju, bez mogućnosti vraćanja izdanja. Nema potrebe za popunjavanjem prostora na disku. Svatko tko misli da može pustiti kod u proizvodnju s greškom je loš programer!
Sve faze postavljanja moraju biti odvojene jedna od druge.
Imati priliku za povratak. Napravite izdanja sa starim kopijama aplikacije (već sastavljene i spremne za bitku) spremljene u brzom pristupu, tako da u slučaju pogrešaka možete vratiti staru verziju. To jest, uvjetno postoji mapa tisak i mapa struja, a nakon uspješne implementacije i sastavljanja mape struja povezan simboličnom vezom s novim izdanjem koje se nalazi unutra tisak s konvencionalnim nazivom broja izdanja.
Ovdje se sjećamo Blue-Green implementacije, koja vam omogućuje ne samo prebacivanje između kodova, već i prebacivanje između svih resursa, pa čak i okruženja s mogućnošću vraćanja svega na staro.
6. Procesi
Pohranite podatke o stanju aplikacije izravno unutar same aplikacije. Koristite sesije u RAM-u same aplikacije. Koristite što više dijeljenja između usluga trećih strana. Oslonite se na činjenicu da aplikacija može imati samo jedan proces i ne dopuštajte skaliranje.
Što se tiče sesija, pohranjujte podatke samo u predmemoriju koju kontroliraju servisi trećih strana (memcached, redis), pa čak i ako imate pokrenuto 20 aplikacijskih procesa, bilo koji od njih, nakon što pristupi predmemorije, moći će nastaviti raditi s klijentom u isto stanje u kojem je korisnik radio s aplikacijom u drugom procesu. Ovim pristupom ispada da bez obzira koliko kopija usluga trećih strana koristite, sve će raditi normalno i bez problema s pristupom podacima.
7. Vezivanje luke
Samo web poslužitelj treba znati kako raditi s uslugama trećih strana. Ili još bolje, instalirajte usluge trećih strana izravno unutar web poslužitelja. Na primjer, kao PHP modul u Apacheu.
Sve vaše usluge moraju biti dostupne jedna drugoj putem pristupa nekoj adresi i portu (localgost:5432, localhost:3000, nginx:80, php-fpm:9000), odnosno iz nginxa mogu pristupiti i php-fpm-u i postgres, i od php-fpm do postgres i nginx i zapravo sa svake usluge mogu pristupiti drugoj usluzi. Na taj način održivost usluge nije povezana s održivošću druge usluge.
8. Paralelizam
Radite s jednim procesom, inače se više procesa neće moći međusobno slagati!
Ostavite mjesta za skaliranje. Docker swarm je odličan za ovo.
Docker Swarm je alat za stvaranje i upravljanje klasterima spremnika između različitih strojeva i hrpe spremnika na istom računalu.
Koristeći swarm, mogu odrediti koliko ću resursa dodijeliti svakom procesu i koliko ću procesa iste usluge pokrenuti, a interni balanser, primajući podatke na danom portu, automatski će ih proxy procesima. Dakle, budući da se opterećenje poslužitelja povećalo, mogu dodati više procesa, čime se smanjuje opterećenje određenih procesa.
9. Jednokratnost
Nemojte koristiti redove za rad s procesima i podacima. Ubijanje jednog procesa trebalo bi utjecati na cijelu aplikaciju. Ako padne jedan servis, sve će propasti.
Svaki proces i uslugu možete isključiti u bilo kojem trenutku i to ne bi trebalo utjecati na druge usluge (naravno, to ne znači da će usluga biti nedostupna za drugu uslugu, ali da se druga usluga neće isključiti nakon ove). Svi procesi moraju biti elegantno prekinuti, tako da kada se prekinu, nikakvi podaci neće biti oštećeni i da će sustav raditi ispravno kada ga sljedeći put uključite. Odnosno, čak i u slučaju hitnog prekida, podaci ne bi trebali biti oštećeni (ovdje je prikladan transakcijski mehanizam, upiti u bazi rade samo u grupama, a ako barem jedan upit iz grupe ne uspije ili se izvrši s pogreška, tada niti jedan drugi upit iz grupe zapravo neće uspjeti).
10. Paritet razvoja/operacije aplikacije
Produkcija, inscenacija i lokalna verzija prijave moraju se razlikovati. U produkciji koristimo Yii Lite framework, a lokalno Yii, tako da radi brže u produkciji!
U stvarnosti bi sve implementacije i rad s kodom trebali biti u gotovo identičnom okruženju (ne govorimo o fizičkom hardveru). Također, bilo koji razvojni zaposlenik bi trebao moći implementirati kod u produkciju ako je potrebno, a ne neki posebno obučeni devops odjel, koji samo zahvaljujući posebnoj snazi može podići aplikaciju u produkciju.
U tome nam pomaže i Docker. Ako se poštuju sve prethodne točke, korištenje dockera dovest će proces implementacije okruženja i na produkcijskom i na lokalnom stroju do unosa jedne ili dvije naredbe.
11. Cjepanice
Zapisujemo zapise u datoteke i baze podataka! Ne čistimo datoteke i baze podataka od zapisa. Kupimo samo tvrdi disk s 9000 Peta bajtova i to je u redu.
Sve zapisnike treba smatrati tokom događaja. Sama aplikacija ne bi trebala biti uključena u obradu dnevnika. Dnevnici bi se trebali ispisati ili na stdout ili poslati putem protokola kao što je udp, tako da rad s zapisnicima ne stvara probleme za aplikaciju. graylog je dobar za ovo. Graylog koji prima sve logove putem udp-a (ovaj protokol ne zahtijeva čekanje odgovora o uspješnom prijemu paketa) ni na koji način ne ometa aplikaciju i bavi se samo strukturiranjem i obradom logova. Logika aplikacije ne mijenja se u radu s takvim pristupima.
12. Poslovi administracije
Za ažuriranje podataka, baza podataka itd. upotrijebite zasebno stvorenu krajnju točku u API-ju, njezino izvršavanje 2 puta zaredom rezultirat će dupliciranjem svega. Ali nisi glup, nećeš dvaput kliknuti, a migracija nam ne treba.
Svi administrativni zadaci trebaju se izvoditi u istom okruženju kao i sav kod, na razini izdanja. Odnosno, ako trebamo promijeniti strukturu baze podataka, onda to nećemo raditi ručno mijenjajući nazive stupaca i dodajući nove kroz neke vizualne alate za upravljanje bazom podataka. Za takve stvari kreiramo zasebne skripte - migracije, koje se izvršavaju svugdje iu svim okruženjima na isti način sa zajedničkim i razumljivim rezultatom. Za sve druge zadatke, kao što je punjenje projekta podacima, treba koristiti slične metodologije.
Primjer implementacije u PHP, Laravel, Laradock, Docker-Compose
PS Svi primjeri su napravljeni na MacOS-u. Većina ih je također prikladna za Linux. Korisnici Windowsa, oprostite mi, ali dugo nisam radio sa Windowsima.
Zamislimo situaciju u kojoj na računalu nemamo instaliranu nijednu verziju PHP-a i baš ništa.
Instalirajte najnovije verzije programa docker i docker-compose. (ovo se može naći na internetu)
git clone https://github.com/Laradock/laradock.git &&
ls
Za Laradock ću reći da je jako cool stvar, koja sadrži puno spremnika i pomoćnih stvari. Ali ne bih preporučio korištenje Laradocka kao takvog bez izmjena u proizvodnji zbog njegove redundantnosti. Bolje je izraditi vlastite spremnike na temelju primjera u Laradocku, to će biti puno optimiziranije, jer nitko ne treba sve što je tamo u isto vrijeme.
2. Konfigurirajte Laradock za pokretanje naše aplikacije.
cd laradock &&
cp env-example .env
2.1. Otvorite direktorij habr (nadređena mapa u koju je laradock kloniran) u nekom editoru. (U mom slučaju PHPStorm)
U ovoj fazi samo projektu dajemo ime.
2.2. Pokrenite sliku radnog prostora. (U vašem slučaju, slikama će trebati neko vrijeme da se izgrade)
Radni prostor je posebno pripremljena slika za rad s okvirom u ime programera.
Ulazimo u kontejner pomoću
docker-compose up -d workspace &&
docker-compose exec workspace bash
2.4. Nakon instalacije provjeravamo je li direktorij s projektom kreiran i prekidamo sastavljanje.
ls
exit
docker-compose down
2.5. Vratimo se na PHPStorm i postavimo ispravan put do naše laravel aplikacije u .env datoteci.
3. Dodajte sav kod u Git.
Da bismo to učinili, stvorit ćemo repozitorij na Githubu (ili bilo gdje drugdje). Idemo u direktorij habr u terminalu i izvršimo sljedeći kod.
echo "# habr-12factor" >> README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin [email protected]:nzulfigarov/habr-12factor.git # здесь будет ссылка на ваш репо
git push -u origin master
git status
Provjerimo je li sve u redu.
Radi praktičnosti, preporučujem korištenje nekog vizualnog sučelja za Git, u mom slučaju je to GitKraken. (ovdje je link za preporuku)
4. Pokrenimo!
Prije početka, provjerite da ništa ne visi na portovima 80 i 443.
docker-compose up -d nginx php-fpm
Stoga se naš projekt sastoji od 3 odvojene usluge:
nginx - web poslužitelj
php-fpm - php za primanje zahtjeva s web poslužitelja
radni prostor - php za programere
Trenutno smo postigli da smo izradili aplikaciju koja zadovoljava 4 točke od 12, a to su:
1. Baza koda — sav kod je u jednom repozitoriju (mala napomena: možda bi bilo ispravno dodati docker unutar laravel projekta, ali to nije važno).
2. Ovisnosti - Sve naše ovisnosti izričito su zapisane u application/composer.json i u svakoj Docker datoteci svakog spremnika.
3. Usluge podrške — Svaki od servisa (php-fom, nigx, workspace) živi vlastitim životom i povezan je izvana i kada se radi s jednim servisom, drugi neće biti pogođen.
4. procesi — svaka usluga je jedan proces. Svaka od usluga ne održava unutarnje stanje.
5. Povezivanje porta
docker ps
Kao što vidimo, svaka usluga radi na svom portu i dostupna je svim ostalim uslugama.
6. Paralelizam
Docker nam omogućuje stvaranje više procesa istih usluga s automatskim balansiranjem opterećenja između njih.
Zaustavimo kontejnere i progurajmo ih kroz zastavu --ljestvica
docker-compose down &&
docker-compose up -d --scale php-fpm=3 nginx php-fpm
Kao što vidimo, stvorene su kopije php-fpm kontejnera. Ne trebamo ništa mijenjati u radu s ovim spremnikom. Također mu nastavljamo pristupati na portu 9000, a Docker nam regulira opterećenje između kontejnera.
7. Jednokratnost - svaki spremnik može biti ubijen bez ozljeđivanja drugog. Zaustavljanje ili ponovno pokretanje spremnika neće utjecati na rad aplikacije tijekom sljedećih pokretanja. Svaki kontejner također se može podići u bilo kojem trenutku.
8. Paritet razvoja/operacije aplikacije - sve naše sredine su iste. Pokretanjem sustava na poslužitelju u produkciji, nećete morati ništa mijenjati u svojim naredbama. Sve će se temeljiti na Dockeru na isti način.
9. Sječa drva — svi zapisnici u ovim spremnicima idu u stream i vidljivi su na Docker konzoli. (u ovom slučaju, zapravo, s drugim domaćim spremnicima, to možda neće biti slučaj ako ne vodite računa o tome)
docker-compose logs -f
Ali postoji kvaka u tome što zadane vrijednosti u PHP-u i Nginxu također pišu zapisnike u datoteku. Za ispunjavanje 12 faktora potrebno je zatvoriti pisanje dnevnika u datoteku u konfiguracijama svakog spremnika zasebno.
Docker također pruža mogućnost slanja zapisa ne samo na stdout, već i na stvari kao što je graylog, koji sam spomenuo gore. A unutar grayloga, možemo upravljati zapisima kako želimo, a naša aplikacija to ni na koji način neće primijetiti.
10. Administrativni poslovi — sve administrativne zadatke rješava laravel zahvaljujući artisan alatu točno onako kako bi kreatori aplikacije od 12 faktora željeli.
Kao primjer, pokazat ću kako se neke naredbe izvršavaju.
Ulazimo u kontejner.
docker-compose exec workspace bash
php artisan list
Sada možemo koristiti bilo koju naredbu. (imajte na umu da nismo konfigurirali bazu podataka i predmemoriju, tako da se polovica naredbi neće ispravno izvršiti, jer su dizajnirane za rad s predmemorijom i bazom podataka).
11. Konfiguracije i 12. Izgradi, pusti, pokreni
Htio sam ovaj dio posvetiti Blue-Green Deploymentu, ali se pokazalo preopširnim za ovaj članak. O tome ću napisati poseban članak.
Ukratko, koncept se temelji na CI/CD sustavima poput Jenkins и Gitlab CI. U oba, možete postaviti varijable okruženja povezane s određenim okruženjem. Sukladno tome, u ovoj situaciji bit će ispunjena točka c Konfiguracije.
I poanta o Izgradi, pusti, pokreni rješava se ugrađenim funkcijama s nazivom Cjevovod.
Cjevovod omogućuje vam da podijelite proces implementacije u mnoge faze, ističući faze sastavljanja, puštanja i izvršenja. Također u Pipelineu možete izraditi sigurnosne kopije, i zapravo bilo što. Ovo je alat s neograničenim potencijalom.
Aplikacijski kod je na Github.
Ne zaboravite inicijalizirati podmodul prilikom kloniranja ovog repozitorija.
PS: Svi ovi pristupi mogu se koristiti s bilo kojim drugim uslužnim programima i programskim jezicima. Glavna stvar je da se suština ne razlikuje.