Iznad kontejnera: Arhitektura Dockera za održivu otpornost pozadinskog sustava
Docker može učiniti da backend djeluje prekrasno jednostavno: zapakirajte aplikaciju, pokrenite nekoliko servisa i isporučite je. Ta je jednostavnost vrijedna, ali je također mjesto na kojem mnogi sustavi prerano prestanu razmišljati. Spremnik je mehanizam isporuke, a ne strategija otpornosti.
Održiva otpornost backenda proizlazi iz eksplicitnog definiranja granica oko spremnika: kako se servisi pokreću, otkazuju, oporavljaju, komuniciraju, pohranjuju stanje i razvijaju. Docker pomaže provoditi te granice. Ne bira ih umjesto vas.
Počnite s neuspjehom, a ne s Dockerfileom
Korisno arhitekturno pitanje nije „Može li se ovo pokrenuti u spremniku?” Gotovo sve može. Umjesto toga pitajte: „Što se događa kada je ova ovisnost spora, nedostupna, ponovno pokrenuta ili poslužuje neočekivane podatke?” Odgovor bi trebao biti razumljiv bez čitanja svakog retka koda aplikacije.
Za PHP API to znači razdvajanje odgovornosti. Web proces trebao bi obrađivati zahtjeve. Radnik reda čekanja trebao bi obrađivati asinkroni rad. Zakazani poslovi trebali bi se izvršavati kao neovisno upravljani procesi. PostgreSQL ili MySQL trebali bi upravljati trajnim relacijskim podacima. Redis može podržavati predmemoriranje, sesije, ograničavanje broja zahtjeva ili redove čekanja, ali ne bi smio neprimjetno postati jedina kopija ključnog poslovnog stanja.
Te su razlike važne jer svaka komponenta otkazuje na drugačiji način. Ponovno pokretanje PHP radnika obično je sigurno ako je rad idempotentan. Ponovno pokretanje baze podataka operativni je događaj s implikacijama za veze, oporavak i integritet podataka. Tretiranje obaju kao zamjenjivih „servisa” u jednoj Compose datoteci može prikriti razliku sve dok je produkcija ne otkrije.
Gradite male slike, ali projektirajte veće ugovore
Produkcijska slika trebala bi sadržavati ono što je procesu potrebno za izvođenje, a ne cijelo razvojno okruženje. Izgradnje u više faza često su čist način da se alati za izgradnju i razvojne ovisnosti zadrže izvan konačne slike.
FROM composer:2 AS dependencies
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --prefer-dist --no-interaction --optimize-autoloader
FROM php:8.3-fpm-alpine
WORKDIR /var/www
COPY --from=dependencies /app/vendor ./vendor
COPY . .
CMD ["php-fpm"]
Ovo je namjerno samo početna točka. Stvarna aplikacija može zahtijevati PHP ekstenzije, web poslužitelj ili obrnuti proxy, dozvole datoteka i korak izgradnje za frontend resurse. Važno načelo je ponovljivost: slika bi trebala biti sastavljena od deklariranih ulaza, a implementacija bi trebala koristiti određenu verziju slike umjesto ponovne izgradnje iz promjenjive grane na poslužitelju.
Sama minimalnost slike ne stvara pouzdanost. Širi ugovor jest da konfiguracija dolazi putem mehanizama specifičnih za okruženje, tajne nisu ugrađene u slojeve, zapisnici idu na standardni izlaz ili standardnu pogrešku te da proces ispravno odgovara na signale prekida. Docker čini te prakse prirodnima; otporan dizajn čini ih nezaobilaznima.
Redoslijed pokretanja učinite pitanjem spremnosti
Jedna česta zamka jest pretpostavka da je pokrenuti spremnik spremna ovisnost. Proces baze podataka može raditi dok se još oporavlja, primjenjuje inicijalizacijski rad ili odbija veze. Red čekanja može prihvatiti TCP vezu, ali još ne biti upotrebljiv za namjeravanu operaciju aplikacije.
Pokretanje aplikacije stoga bi trebalo tolerirati privremene neuspjehe ovisnosti. Koristite ograničene ponovne pokušaje s postupnim povećanjem čekanja, jasno bilježenje pogrešaka i način neuspjeha koji orkestratoru omogućuje ponovno pokretanje procesa kada oporavak nije moguć. Nemojte se oslanjati samo na fiksna čekanja poput sleep(10); ona promjenjivo vrijeme pokretanja pretvaraju u ponavljajući uvjet utrke.
Provjere zdravlja trebale bi odražavati odluku koju podržavaju. Osnovna provjera živosti odgovara na pitanje je li proces živ. Provjera spremnosti odgovara na pitanje može li sigurno primati promet. Za API, spremnost može potvrditi da je učitana ključna konfiguracija i da se može uspostaviti veza s bazom podataka. Ne bi trebala izvršavati skup upit za izvješće niti ovisiti o tome jesu li sve opcionalne integracije zdrave.
Neka ponovni pokušaji budu sigurni
Ponovni pokušaji mogu pojačati incident ako svaki zahtjev opetovano pokreće isti skupi poziv prema nizvodnom sustavu. Postavite razumne vremenske rokove, ograničite broj pokušaja i razlikujte prolazne neuspjehe od pogrešaka validacije. Neispravno oblikovan zahtjev trebao bi odmah vratiti pogrešku klijentu; privremeno nedostupan pružatelj plaćanja može opravdati ponovni pokušaj ili asinkroni put oporavka.
Pri pisanju u vanjske sustave koristite ključeve idempotentnosti ili pravila jedinstvenosti na razini aplikacije tamo gdje to domena dopušta. Ako se radnik sruši nakon slanja zahtjeva, ali prije bilježenja uspjeha, ponovni pokušaj ne smije neprimjetno stvoriti drugo terećenje, e-poruku ili narudžbu.
Spremnici bi trebali biti zamjenjivi; podaci ne bi trebali
Najčišće operativno pravilo jednostavno je: brisanje i ponovno stvaranje spremnika aplikacije ne smije izgubiti poslovne podatke. Prenesene datoteke, zapisi baze podataka, generirani izvozi i stanje poruka svi trebaju promišljena mjesta za pohranu.
Za baze podataka koristite trajnu pohranu kojom se upravlja s jednakom pažnjom kao i samom bazom podataka: sigurnosne kopije, testiranje obnove, kontrola pristupa, nadzor i planiranje kapaciteta. Montirani volumen jest trajnost, a nije plan sigurnosnog kopiranja. Ako oporavak nikada nije testiran u izoliranom okruženju, organizacija ima pretpostavku, a ne postupak oporavka.
Za prijenose datoteka izbjegavajte vezivanje trajnih podataka uz životni ciklus web spremnika. Pohranjujte datoteke u odgovarajuću trajnu uslugu ili strategiju volumena, zadržite metapodatke u bazi podataka i definirajte što se događa kada pohrana privremeno nije dostupna. API bi trebao vratiti smislenu pogrešku, a ne prijaviti uspjeh prije nego što datoteka ima trajno odredište.
Koristite Compose radi jasnoće, a ne kao arhitekturni dijagram
Docker Compose izvrstan je za lokalni razvoj, a može biti koristan i u manjim kontroliranim implementacijama. Njegova je najveća vrijednost često komunikacijska: deklarira servise, mreže, volumene i očekivanja okruženja potrebna za pokretanje sustava.
services:
api:
image: example-api:1.4.0
environment:
APP_ENV: production
DATABASE_URL: ${DATABASE_URL}
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
Ova konfiguracija ne uklanja potrebu za rukovanjem ponovnim pokušajima na razini aplikacije, strategijom sigurnosnih kopija ili upravljanjem tajnama. Ona samo čini vidljivim dio ugovora tijekom izvođenja. Tretirajte je kao izvršivu dokumentaciju, a zatim dodajte operativnu dokumentaciju za migracije, vraćanja prethodnog stanja, odgovor na incidente i obnovu podataka.
Implementirajte promjene kao reverzibilne operacije
Otpornost je najvidljivija tijekom promjene. Nova slika može uključivati migraciju sheme, promjenu konfiguracije ili ažuriranje ovisnosti koje se drukčije ponaša pod produkcijskim prometom. Plan implementacije trebao bi odgovoriti na tri pitanja prije izdanja: što se mijenja, kako se provjerava zdravlje i kako se vraća prethodno poznato dobro stanje?
Migracije baze podataka zaslužuju poseban oprez. Kada je moguće, preferirajte aditivne, povratno kompatibilne promjene: dodajte stupac koji dopušta NULL, implementirajte kod koji može obrađivati oba oblika, popunite podatke, a zatim uklonite staro ponašanje u kasnijem izdanju. Povezivanje nepovratne promjene sheme s jednim uvođenjem aplikacije čini vraćanje prethodnog stanja daleko opasnijim.
- Verzionirajte slike nepromjenjivo i zabilježite implementiranu verziju.
- Pokrenite migracije kao eksplicitan korak koji se može promatrati.
- Postavite ograničenja resursa na temelju izmjerenog ponašanja aplikacije.
- Izložite strukturirane zapisnike i smislene metrike aplikacije.
- Vježbajte obnovu podataka i vraćanje izdanja prije nego što to hitan slučaj zahtijeva.
Spremnik je početak discipline
Docker zaslužuje svoje mjesto time što softver čini prenosivim, a granice procesa konkretnima. Zrela uporaba Dockera nije direktorij pun definicija spremnika; to je backend koji se može ponovno pokrenuti, promatrati, mijenjati i oporaviti bez oslanjanja na sreću ili nedokumentirane ručne korake.
To je trajna promjena perspektive. Gradite spremnike koje je lako zamijeniti, servise koji iskreno govore o neuspjehu ovisnosti i putove podataka projektirane za oporavak. Kada su te odluke postavljene, Docker prestaje biti arhitektura i postaje ono što bi trebao biti: pouzdan temelj za nju.