Dockerizacija zastarjelog PHP-a: pragmatičan put prema modernizaciji
Naslijeđeni PHP rijetko ne uspijeva zato što je sam jezik inherentno neupravljiv. Ne uspijeva zato što je njegovo izvršno okruženje postalo nevidljivo: ručno konfiguriran poslužitelj, zastarjelo proširenje, cron zadatak za koji nitko nije zadužen i koraci implementacije koje pamti jedna osoba. Docker ne prepisuje tu povijest. Aplikaciji daje stabilnu granicu oko nje, što je često najsigurniji prvi korak prema modernizaciji.
Praktični cilj nije učiniti staru bazu koda modernom naizgled. Cilj je učiniti njezino ponašanje ponovljivim, razumljivim i sigurnijim za izmjene.
Započnite očuvanjem stvarnosti
Naslijeđena aplikacija može ovisiti o određenoj verziji PHP-a, modulu Apachea, biblioteci za slike, upravljačkom programu baze podataka, postavci vremenske zone ili direktoriju s mogućnošću pisanja. Takve ovisnosti tretirajte kao zahtjeve koje treba otkriti, a ne kao nedostatke koje treba ukloniti prvoga dana.
Prije odabira osnovne slike, popišite što pokrenuti sustav zapravo treba:
- Verziju PHP-a i omogućena proširenja.
- Web-poslužitelj i korijenski direktorij dokumenata.
- Potrebne vrijednosti PHP konfiguracije, osobito ograničenja prijenosa, zapisivanje pogrešaka, sesije i vremensku zonu.
- Putanje s mogućnošću pisanja za prijenose, datoteke predmemorije, zapisnike i generirana izvješća.
- Vanjske servise kao što su MySQL, Redis, SMTP, pohrana objekata i zakazani zadaci.
- Konfiguraciju specifičnu za okruženje koja je trenutačno ugrađena u datoteke ili postavke poslužitelja.
Ovaj popis sprječava čestu pogrešku: izgradnju spremnika urednog izgleda koji potajno izostavlja ključno proširenje ili usmjerava Apache na pogrešan direktorij. Spremnik koji ne može reproducirati ponašanje u produkciji nije modernizacija; on je novi mehanizam za prekide rada.
Izgradite malo, eksplicitno izvršno okruženje
Za aplikaciju posluženu putem Apachea, službena PHP Apache slika može olakšati izradu prvog spremnika. Prikvačite konkretnu verziju PHP-a koja je kompatibilna s aplikacijom i njezinim ovisnostima. Izbjegavajte korištenje nekvalificirane oznake latest: ponovljivost je svrha.
FROM php:8.2-apache
RUN docker-php-ext-install pdo_mysql
RUN a2enmod rewrite
COPY . /var/www/html/
RUN chown -R www-data:www-data /var/www/html/var
EXPOSE 80
Ovaj je primjer namjerno skroman. Instalira PDO MySQL proširenje, omogućuje Apacheova pravila prepisivanja, kopira aplikaciju i web-poslužiteljskom korisniku daje pristup poznatom direktoriju s mogućnošću pisanja. U stvarnom projektu ispravna verzija PHP-a i proširenja moraju proizaći iz popisa ovisnosti, a ne iz osobne preferencije.
Nemojte cijelu aplikaciju učiniti zapisivom. Odredite direktorije kojima je zaista potreban pristup za pisanje i zadržite izvorni kod samo za čitanje gdje je to moguće. Ta razlika poboljšava i otklanjanje pogrešaka i sigurnost: neočekivana pisanja lakše je uočiti.
Izričito postavite korijenski direktorij dokumenata
Mnogi stariji okviri izlažu samo direktorij public ili web. Ako Apache poslužuje korijenski direktorij repozitorija, konfiguracijske datoteke i interni kod mogu postati dostupni. Namjerno postavite korijenski direktorij dokumenata i osigurajte da pravila prepisivanja usmjeravaju zahtjeve na prednji kontroler kada ga aplikacija treba.
Isto tako, nemojte pretpostaviti da je postojeća datoteka .htaccess aktivna. Apache mora dopustiti nadjačavanja za relevantni direktorij ili se pravila moraju premjestiti u konfiguraciju virtualnog hosta. Nakon promjene ove granice testirajte uobičajene rute, nedostajuće stranice, prenesene datoteke i statičke resurse.
Odvojite konfiguraciju aplikacije od slike
Slike bi trebale sadržavati kod i ovisnosti izvršnog okruženja. Vrijednosti specifične za okruženje trebale bi se dostaviti tijekom izvršavanja putem varijabli okruženja, montirane konfiguracije ili sustava za upravljanje tajnama primjerenog okruženju implementacije.
Compose datoteka usmjerena na razvoj može učiniti ovisnosti servisa vidljivima:
services:
app:
build: .
ports:
- "8080:80"
environment:
APP_ENV: development
DB_HOST: db
DB_NAME: legacy_app
DB_USER: legacy_user
DB_PASSWORD: change-me
depends_on:
- db
db:
image: mysql:8.0
environment:
MYSQL_DATABASE: legacy_app
MYSQL_USER: legacy_user
MYSQL_PASSWORD: change-me
MYSQL_ROOT_PASSWORD: root-change-me
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
To je korisno za lokalni razvoj, ali nije strategija za produkcijske tajne. Nemojte ugraditi vjerodajnice u sliku, predavati stvarne lozinke u repozitorij niti pretpostaviti da depends_on znači da je baza podataka spremna prihvatiti veze. Ona upravlja redoslijedom pokretanja, a ne spremnošću na razini aplikacije.
Naslijeđene aplikacije često odmah pokušaju uspostaviti vezu s bazom podataka i ne uspiju ako se MySQL još inicijalizira. Robusno rješenje je ponašanje ponovnog pokušaja na razini aplikacije s ograničenim odgodama i korisnim zapisivanjem. Ako promjena aplikacije još nije izvediva, osigurajte da platforma za implementaciju ima provjere stanja i ponašanje ponovnog pokretanja koje odgovara načinu neuspjeha aplikacije. Važno je učiniti ponašanje pri pokretanju namjernim, a ne sretnom slučajnošću.
Upravljajte stanjem bez pretvaranja da ne postoji
Spremnici su potrošni. Naslijeđeni PHP sustavi često nisu. Mogu zapisivati prijenose na disk, koristiti datotečne sesije, generirati minijature ili lokalno nadopisivati zapisnike. Dockeriziranje aplikacije otkriva to stanje, što je vrijedno jer je skriveno stanje jedna od najtežih prepreka pouzdanoj implementaciji.
Klasificirajte svaku zapisivu putanju:
- Prijenosi i datoteke koje generiraju korisnici: koristite trajnu pohranu, poput upravljanog volumena ili pohrane objekata, uz plan sigurnosnog kopiranja i oporavka.
- Predmemorija i privremene datoteke: zadržite ih potrošnima kada je moguće i osigurajte da ih aplikacija može ponovno izgraditi.
- Zapisnici: dajte prednost standardnom izlazu i standardnoj pogrešci kako bi ih platforma izvršnog okruženja mogla dosljedno prikupljati.
- Sesije: datotečne sesije mogu raditi za jednu instancu, ali prije skaliranja na više spremnika aplikacije potrebna je zajednička pohrana sesija.
Nemojte montirati cijelo izvorno stablo u produkcijski spremnik samo kako biste sačuvali prijenose ili omogućili hitne popravke. To zamagljuje implementirani artefakt i čini vraćanja na prethodnu verziju nepouzdanima. Montirajte samo putanje podataka koje zahtijevaju trajnost.
Iskoristite kontejnerizaciju za stvaranje ugovora o implementaciji koji se može testirati
Dockerfile postaje sažeta izjava o tome kako se aplikacija pokreće. To ga čini izvrsnim mjestom za dodavanje provjere. Izgradite sliku u kontinuiranoj integraciji, pokrenite je i izvršite mali skup provjera visoke vrijednosti: krajnju točku za provjeru stanja, reprezentativnu stranicu, put povezivanja s bazom podataka te korak migracije ili provjere sheme gdje je primjenjivo.
Migracije baze podataka zaslužuju posebnu opreznost. Migraciju je možda sigurno pokrenuti jednom, ali nesigurno ju je pokrenuti istodobno iz više web-spremnika. Dodijelite jednoj komponenti implementacije odgovornost za migracije, potvrdite da je mehanizam migracije idempotentan ili zaštićen te zadržite plan vraćanja koji prepoznaje da je promjene baze podataka često teže poništiti nego kod aplikacije.
Također odvojite web-zahtjeve od pozadinskog rada. Cron zadatak koji se izvodi unutar Apache spremnika može privremeno funkcionirati, ali povezuje raspoređivanje sa životnim ciklusom web-poslužitelja. Definirajte zakazane zadatke kao zasebne poslove ili servise kada to okruženje implementacije podržava. Isto načelo vrijedi za radnike reda čekanja: trebali bi imati vlastiti proces, zapisnike, pravilo ponovnog pokretanja i ograničenja resursa.
Modernizirajte slojevito, a ne jednim velikim skokom
Docker je platforma za postupno poboljšanje. Kada se aplikacija pokreće predvidljivo, sljedeće promjene postaju manje rizične: dodajte automatizirane testove oko kritičnog ponašanja, premjestite vjerodajnice iz datoteka, standardizirajte zapisnike, uvedite provjere stanja, ažurirajte jednu ovisnost odjednom i naposljetku nadogradite PHP.
Nemojte kombinirati sve te promjene u prvom nastojanju kontejnerizacije. Nadogradnja PHP-a može otkriti zastarjelo ponašanje; nadogradnja baze podataka može promijeniti SQL načine rada ili autentifikaciju; nadogradnja okvira može izmijeniti usmjeravanje i sesije. Kada se sve promijeni odjednom, neuspjehe je teško dijagnosticirati. Stabilan spremnik oko postojećeg ponašanja svakoj kasnijoj izboljšanju daje jasnu osnovu.
Spremnik je početak operativne jasnoće
Najbolji ishod nije repozitorij s Dockerfileom. To je aplikacija čije su pretpostavke izvršnog okruženja vidljive, čije se ovisnosti mogu ponovno stvoriti i čija se implementacija može testirati prije nego što dosegne korisnike.
Zato je Dockeriziranje naslijeđenog PHP-a toliko vrijedno. Ono pretvara nakupljeno operativno usmeno znanje u verzioniranu konfiguraciju. Kod može i dalje biti star, ali više nije zarobljen u starom načinu pokretanja — a to je često najpragmatičniji korak modernizacije koji tim može poduzeti.