Контејнеризирање на PHP микросервиси со Docker: Оркестрација за беспрекорно распоредување
Микросервисите не стануваат подготвени за распоредување само затоа што се поделени во помали репозиториуми или директориуми. Вистинскиот тест доаѓа кога на секоја услуга ѝ се потребни сопствено време на извршување, конфигурација, мрежен пристап, поврзување со база на податоци, здравствена проверка и патека за издавање. Docker им дава на PHP тимовите дисциплиниран начин да ги спакуваат тие аспекти, така што услугата се однесува предвидливо — од лаптопот на развивачот до продукциска платформа.
Целта не е секој подвижен дел да се стави во контејнери само заради тоа. Целта е да се создаде повторлива оперативна граница: истата PHP верзија, потребните екстензии, апликацискиот код и командата за стартување патуваат заедно. Таа доследност намалува позната категорија на неуспеси: код што бил исправен, но се извршувал во средина што суптилно се разликувала.
Започнете со мала, експлицитна PHP слика
Сликата на микросервисот треба да го содржи она што ѝ е потребно на услугата за да работи, и малку повеќе од тоа. За типична PHP HTTP услуга, тоа значи PHP време на извршување, неопходни екстензии, Composer зависности, апликациски код и команда за влез. Алатките само за развој не треба неформално да протекуваат во продукциската слика.
Повеќестепеното градење го задржува Composer достапен при инсталирањето на зависностите, без да го направи дел од конечната слика за време на извршување.
FROM composer:2 AS dependencies
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --prefer-dist --no-interaction --no-scripts
FROM php:8.3-cli
WORKDIR /app
COPY --from=dependencies /app/vendor /app/vendor
COPY . .
EXPOSE 8080
CMD ["php", "-S", "0.0.0.0:8080", "-t", "public"]
Овој пример е намерно едноставен. Вградениот PHP сервер може да биде корисен за мала услуга или локален работен тек, но продукциското HTTP ракување често користи PHP-FPM зад веб-сервер или модел на процеси управуван од платформата. Важниот избор во дизајнот е командата на контејнерот да биде експлицитна и да одговара на начинот на кој е наменето да работи услугата.
Копирајте ги манифестите за зависности пред изворниот код на апликацијата. Docker потоа може повторно да го искористи слојот за инсталирање зависности кога се менува само апликацискиот код. Тоа ги забрзува итеративните градења, притоа зачувувајќи ја репродуцирливоста преку composer.lock.
Дефинирајте договори меѓу услугите
Контејнерите го олеснуваат стартувањето на услугите; не дефинираат како услугите треба да зависат една од друга. Тоа е архитектонска одговорност. PHP услугата треба да ги познава своите надредени зависности преку конфигурација, а не преку тврдокодно внесени имиња на хостови, акредитиви или претпоставки за локалната инфраструктура.
За локален развој, Docker Compose е корисен за опишување на мал систем и неговата мрежа меѓу услуги.
services:
orders:
build: ./orders
environment:
DATABASE_URL: "mysql://app:secret@db:3306/orders"
INVENTORY_BASE_URL: "http://inventory:8080"
depends_on:
db:
condition: service_healthy
ports:
- "8080:8080"
inventory:
build: ./inventory
db:
image: mysql:8
environment:
MYSQL_DATABASE: orders
MYSQL_USER: app
MYSQL_PASSWORD: secret
MYSQL_ROOT_PASSWORD: root-secret
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 3s
retries: 10
Во оваа мрежа, inventory и db се имиња на услуги што се разрешуваат како имиња на хостови. Тоа е практично локално, но пошироката поука е поважна: конфигурацијата треба да ги изразува крајните точки на зависностите, а околините за распоредување треба да ги обезбедат точните вредности.
Исто така, разликувајте помеѓу „контејнерот се стартуваше“ и „зависноста е подготвена“. Процес на база на податоци може да постои додека сè уште се иницијализира. Compose здравствените проверки можат да го подобрат локалното однесување при стартување, но апликацијата сепак треба да се справува со привремени неуспеси на поврзувањето. Краток, ограничен повторен обид со постепено зголемување на чекањето е разумен при стартување; бесконечни повторни обиди што кријат лоша конфигурација не се.
Одржувајте ја услугата без состојба
Контејнерите по дизајн се заменливи. Третирањето на нивниот локален датотечен систем како трајно складиште создава проблеми при скалирање, повторни распоредувања и закрепнување. Чувајте ги трајните податоци во соодветниот надворешен систем: релациските податоци во база на податоци, споделените датотеки во објектно или мрежно складиште и привремената состојба за координација во услуга наменета за таа цел кога е потребно.
Овој принцип исто така ги појаснува миграциите на базата на податоци. Не дозволувајте секоја реплика на апликацијата да се натпреварува да извршува миграции при стартување. Извршете ги миграциите како посебен чекор на распоредување или како посветена еднократна задача, а потоа стартувајте ја новата верзија на апликацијата. Тоа раздвојување ги прави неуспесите видливи и спречува настанот на хоризонтално проширување да стане настан за управување со шемата.
Конфигурацијата е интерфејс, а не погодност
Променливите на околината се практичен механизам за испорака на нетајна конфигурација, како што се порти, нивоа на логирање, прекинувачи за функции и URL-адреси на услуги. Тајните бараат построго ракување: внесете ги преку платформата за распоредување или одобрен механизам за управување со тајни, избегнувајте нивно зачувување во Compose датотеки и никогаш не ги вградувајте во слој на слика.
Потврдете ја потребната конфигурација кога процесот започнува. Услуга што не може да се поврзе затоа што недостига DATABASE_URL треба јасно да откаже, наместо да продолжи со имплицитна резервна вредност. Јасните неуспеси го скратуваат одговорот на инциденти и го одржуваат усогласено однесувањето во развој и продукција.
Градете за набљудливост и достоинствен неуспех
Во дистрибуиран систем, барањето може да не успее откако ќе ја напушти вашата услуга. Истекувања на време, структурирани логови, идентификатори за корелација и значајни здравствени крајни точки ја претвораат таа неизвесност во нешто што операторите можат да го дијагностицираат. Секој излезен HTTP повик треба да има истек на време. Без него, бавна надолна зависност може да го потроши капацитетот на работниците сè додека услугата не изгледа недостапна.
Повторните обиди бараат расудување. Повторувањето барање за читање по привремен мрежен неуспех може да биде соодветно. Повторувањето неидемпотентна операција, како создавање нарачка, може да создаде дупликати освен ако услугата што прима поддржува клуч за идемпотентност. Безбедната стандардна поставка е да се обидувате повторно само кога операцијата и видот на неуспех го прават прифатливо дуплираното извршување.
Изложувајте здравствени информации внимателно. Крајна точка за живост треба да одговори дали процесот може да продолжи да работи. Крајна точка за подготвеност треба да одговори дали безбедно може да прима сообраќај. Ако услугата мора да достигне база на податоци пред да може да опслужува барања, подготвеноста може да ја одразува таа зависност; живоста вообичаено не треба привремен прекин на базата да го претвора во континуирани рестартирања на контејнерот.
Направете го распоредувањето намерно здодевно
Сигурен канал за распоредување гради една непроменлива слика, ја тестира, ја означува со следлив идентификатор на верзија и го промовира токму тој артефакт низ околините. Повторното градење од гранка за секоја околина внесува избеглива неизвесност: наводно истото издание може да содржи различно разрешување на зависности, содржина на основната слика или состојба на изворот.
- Извршете единечни и интеграциски тестови пред објавување на сликата за издание.
- Скенирајте ги и ажурирајте ги основните слики преку намерен процес на одржување.
- Користете конфигурација и тајни обезбедени од секоја околина, а не изменета содржина на сликата.
- Распоредете компатибилни промени на апликацијата и шемата во низа што поддржува враќање назад.
- Следете ја стапката на грешки, латентноста и логовите за време на пуштањето пред да го проширите сообраќајот.
Компатибилноста на шемата заслужува посебно внимание. Побезбеден образец е прво додавање: додајте nullable колона или нова табела, распоредете код што може да работи и со старата и со новата форма, пополнете ги податоците наназад ако е потребно, а потоа отстранете ги застарените структури во подоцнежно издание. Docker го стандардизира времето на извршување, но не може да направи некомпатибилна промена на базата на податоци повратна.
Контејнерот е почеток на оперативниот дизајн
Контeјнеризирањето на PHP микросервиси е вредно затоа што ги прави претпоставките за времето на извршување конкретни. Поттикнува мали слики, експлицитни зависности, повторливи градења и преносливи артефакти за распоредување. Но контејнерите не ги бришат прашањата на дистрибуираните системи. Тие ги прават тие прашања доволно видливи за добро да се дизајнираат.
Најсилниот резултат не е паметна Compose датотека или најмалата можна слика. Тоа е услуга што стартува предвидливо, откажува јасно, ја чува својата состојба на вистинското место и може да биде заменета без драма. Кога секој PHP микросервис ги следи тие навики, оркестрацијата станува помалку борба со платформата, а повеќе испорачување промени со сигурност.