Докеризирајте го вашиот бекенд: Надвор од основните контејнери за отпорни системи
Контејнер што успешно се стартува не е нужно и бекенд што е подготвен да опслужува сообраќај. Токму тука многу Docker поставувања потфрлаат. Основен Dockerfile може да спакува апликација, но на отпорниот бекенд му се потребни и јасни граници при извршување, предвидлива конфигурација, елегантно справување со зависности и пат до продукциски операции.
Docker е највреден кога го претвора „работи на мојата машина“ во повторлив системски договор. Вашата апликација треба да ги носи своите барања за извршување со себе, додека инфраструктурните аспекти како тајни, трајни податоци, здравствени проверки и политика за распоредување остануваат експлицитни, наместо случајни.
Изградете слика на апликација, не развојна папка
Сликата на бекендот треба да содржи токму она што ѝ е потребно за извршување: соодветни PHP екстензии, код на апликацијата и продукциски зависности. Не треба да се потпира на датотеки монтирани од машината на развивачот ниту на пакети инсталирани интерактивно по стартувањето.
За PHP-FPM апликација што користи PostgreSQL, повеќестепеното градење го задржува Composer надвор од финалната слика за извршување, додека одржува едноставен процес на градење.
FROM composer:2 AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --prefer-dist --no-interaction --optimize-autoloader
FROM php:8.3-fpm-alpine
RUN docker-php-ext-install pdo_pgsql
WORKDIR /var/www/html
COPY --from=vendor /app/vendor ./vendor
COPY . .
USER www-data
CMD ["php-fpm"]
Овој пристап ја прави инсталацијата на зависности повторлива кога lock-датотеката е зачувана во репозиториумот. Исто така избегнува испорачување на Composer и неговите алатки за време на градењето во сликата што работи. Во реална апликација, додајте датотека .dockerignore за локалните зависности, логови, тест-артефакти и датотеки со околински променливи да не станат дел од контекстот за градење.
Бидете намерни во однос на тоа кои промени поништуваат слој од градењето. Копирањето на composer.json и composer.lock пред остатокот од изворниот код му овозможува на Docker повторно да го искористи слојот со зависности кога се менува само кодот на апликацијата. Тоа е мала дизајнерска одлука со значајно влијание врз локалната итерација и брзината на CI.
Одделете ја конфигурацијата од сликата
Сликата треба да биде пренослива меѓу околини. Адреси на бази на податоци, ингеренции, крајни точки за редици, нивоа на логирање и поставки за функции припаѓаат во конфигурацијата при извршување, а не во тврдокодирани PHP-датотеки или вградени слоеви на сликата.
Compose-датотека за развој може да ги направи тие зависности видливи и лесни за стартување заедно.
services:
app:
build: .
environment:
DB_DSN: "pgsql:host=db;port=5432;dbname=app"
DB_USER: "app"
DB_PASSWORD: "development-password"
depends_on:
db:
condition: service_healthy
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: app
POSTGRES_USER: app
POSTGRES_PASSWORD: development-password
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d app"]
interval: 5s
timeout: 3s
retries: 10
volumes:
postgres_data:
Именуваниот волумен ги штити податоците од базата од рутинска замена на контејнери. Здравствената проверка го подобрува редоследот на стартување, но не е замена за отпорноста на апликацијата. Базата на податоци може да стане недостапна откако бекендот веќе е стартуван, при рестартирање, прекин на мрежата, настан за одржување или префрлање при отказ.
За продукција, не третирајте ја пример-лозинката како стратегија за тајни. Обезбедете тајни преку одобрениот механизам за тајни на платформата и ограничете кој може да ги чита. Околинските променливи се практични, но нивните карактеристики на изложеност зависат од средината за извршување, дозволите за проверка на процеси, логовите и алатките за распоредување.
Дизајнирајте за зависности што се привремено недостапни
Бекенд-услугите треба да разликуваат траен неуспех на конфигурацијата од минлив неуспех на зависност. Повторниот обид со погрешно форматиран DSN нема да помогне. Повторниот обид за поврзување со база на податоци при стартување може да биде сосема разумен, особено кога инфраструктурата стартува независно од апликацијата.
Ограничете ги повторните обиди, додајте доцнење и јасно неуспејте откако ќе се исцрпи предвидениот број. Неограничените повторни обиди ги кријат неуспешните распоредувања и може да спречат оркестратор да препознае услуга што не успеала.
<?php
function connectDatabase(): PDO
{
$attempts = 5;
for ($attempt = 1; $attempt <= $attempts; $attempt++) {
try {
return new PDO(
$_ENV['DB_DSN'],
$_ENV['DB_USER'],
$_ENV['DB_PASSWORD'],
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_TIMEOUT => 5,
]
);
} catch (PDOException $exception) {
if ($attempt === $attempts) {
throw new RuntimeException(
'Database connection failed after retries.',
0,
$exception
);
}
usleep($attempt * 200000);
}
}
throw new LogicException('Unreachable retry state.');
}
Ова е намерно скромно. Повторните обиди мора внимателно да се изберат за секоја операција. Повторувањето идемпотентен обид за поврзување е различно од повторување барање за плаќање или запишување во база на податоци чиј исход е непознат. За работа во патеката на барањето, користете истекувања, зачувајте ја идемпотентноста каде што е можно и избегнувајте бавната зависност да се претвори во натрупување PHP работници што чекаат.
Здравствените проверки треба да претставуваат корисна подготвеност
Проверката на процесот одговара на прашањето: „Дали PHP-FPM работи?“ Проверката на подготвеност одговара: „Дали оваа инстанца може безбедно да прифаќа сообраќај?“ Тие се поврзани, но не се идентични.
Изложете лесна крајна точка што ги проверува само зависностите потребни за опслужување на вашата основна патека на барања. Избегнувајте да извршува скапи пребарувања или да ја повикува секоја опционална интеграција. Ако апликацијата не може да стигне до својата примарна база на податоци, можеби е соодветно да врати одговор дека не е здрава. Ако аналитичка услуга е привремено недостапна, отстранувањето на целото API од сообраќајот може да биде контрапродуктивно.
Поставете ја крајната точка за здравје зад вашиот обратен прокси и конфигурирајте ја платформата за распоредување да ја користи. Docker може да рестартира неуспешен процес, но обично само околната платформа може да отстрани нездрава инстанца од сообраќајот, да ја замени или да ја скалира. Контејнерите се примитив за пакување; отпорноста е системско својство.
Направете ги набљудливоста и гасењето дел од дизајнот
Контејнерите се минливи. Запишувајте логови на стандарден излез и стандарден излез за грешки за средината за извршување да може да ги собира. Вклучете идентификатори на барања каде што архитектурата на вашата апликација го поддржува тоа, логирајте неуспеси со доволно контекст за нивно дијагностицирање и никогаш не логирајте ингеренции или необработени чувствителни товарни податоци.
Гасењето заслужува еднакво внимание. Кога контејнерот ќе прими сигнал за прекин, апликацијата треба да престане да прифаќа нова работа, да им дозволи на барањата во тек ограничен период да завршат и чисто да ги затвори врските. На долготрајните работници им треба експлицитно справување со сигнали и безбеден начин да продолжат со задачите без дуплирање несакани ефекти.
Конечно, тестирајте го оперативното однесување, не само успешната патека. Стартувајте од чиста машина со docker compose up --build. Рестартирајте ја базата на податоци додека апликацијата работи. Потврдете дека повторно изградената слика не содржи локални развојни артефакти. Потврдете дека податоците преживуваат замена на контејнерот на апликацијата, но дека намерно отстранетиот волумен на базата на податоци не ги преживува. Овие проверки откриваат дали архитектурата одговара на дијаграмот во вашата глава.
Целта не е Docker-конфигурацијата да се направи сложена. Целта е важните претпоставки да станат видливи: што ѝ треба на услугата, како откажува, како се опоравува и како се набљудува. Откако тие одговори ќе живеат во сликата, конфигурацијата и дизајнот на распоредувањето, контејнерот престанува да биде практична обвивка и станува сигурна единица за испорака на бекенд.