Надвор од Dockerfile-ови: Архитектирање за еволуција на контејнери подготвени за продукција
Dockerfile може да направи една апликација извршлива. Тоа е корисно, но не е исто што и подготовката на апликацијата за продукциска средина.
Јазот се појавува кога една услуга мора постојано да се распоредува, да се набљудува под оптоварување, безбедно да се надградува и да биде разбирлива за луѓето што не ја напишале нејзината прва верзија. Контенеризацијата го менува пакувањето; таа не ги отстранува архитектонските одлуки поврзани со конфигурацијата, податоците, процесите, мрежното поврзување, безбедноста или откажувањето.
Најодржливата стратегија за контејнери започнува со третирање на сликата како еден дел од поширок оперативен договор. Апликацијата треба да се однесува предвидливо, без разлика дали работи на лаптоп, во континуирана интеграција или зад балансер на оптоварување во продукциска средина.
Градете слики за повторливост, а не за погодност
Продукциската слика треба да го содржи она што е потребно за извршување на услугата и малку повеќе. Алатките за развој, метаподатоците за контрола на изворниот код, локалните ингеренции и кешовите на менаџерот на пакети ги прават изградбите побавни, поголеми и потешки за разбирање.
За PHP апликација, повеќефазната изградба често е разумна основа. Една фаза инсталира зависности и компајлира сите потребни средства; завршната фаза ги содржи PHP runtime-от, кодот на апликацијата и само runtime библиотеките што навистина ѝ се потребни.
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-fpm
WORKDIR /var/www/app
COPY --from=dependencies /app/vendor ./vendor
COPY . .
CMD ["php-fpm"]
Овој пример намерно е нецелосен: вистинската слика мора да ги инсталира и PHP екстензиите и библиотеките на оперативниот систем што ги бара нејзината апликација. Важниот принцип е дека инсталирањето на зависности е одвоено од runtime-от. Кога composer.lock не се менува, Docker може повторно да го употреби слојот со зависности, правејќи ги изградбите попредвидливи и побрзи.
Важно е и фиксирањето на верзии. Ознака на слика како php:8.3-fpm е погодна, но со текот на времето може да се разреши во различни основни слики. Тимовите треба да одлучат каде им е потребна репродуцибилност и да ја забележат таа одлука во нивниот процес на изградба и издавање. Целта не е засекогаш да се замрзне секоја зависност; туку промените да бидат намерни и прегледливи.
Конфигурацијата припаѓа надвор од сликата
Сликата треба да биде пренослива низ средини. Ако содржи име на хост на база на податоци, API клуч, URL специфично за распоредување или прекинувач за функционалност, на секоја средина ѝ е потребна сопствена варијанта на сликата. Тоа брзо ги претвора издавањата во конфигурациска загатка.
Наместо тоа, внесувајте конфигурација специфична за средината при извршување. Променливите на околината функционираат добро за мали, експлицитни вредности како APP_ENV, DATABASE_URL и поставки за логирање. Тајните бараат дополнително внимание: избегнувајте да ги вградите во слика, да ги зачувате во репозиториум или да ги изложите во логови и дијагностички излез.
Вчитувањето на конфигурацијата треба јасно да откаже кога задолжителните вредности недостасуваат или се неправилно форматирани. Контејнер што успешно се стартува, а потоа откажува дури откако ќе почне да опслужува сообраќај, создава многу потежок инцидент од оној што веднаш одбива неважечка конфигурација.
Валидирајте ја конфигурацијата рано
Направете ја валидацијата при стартување дел од границата на апликацијата. Проверете дали постојат задолжителните поставки, анализирајте ги низите за поврзување и потврдете дека некомпатибилните опции не се овозможени заедно. Не мора нужно да се поврзувате со секоја надворешна зависност при стартување; тоа може да претвори привремен прекин на зависна услуга во непотребен неуспех при распоредување. Валидирајте го она што може да се валидира локално, а потоа справувајте се со оддалечените неуспеси преку вообичаените патеки за повторување и грешки.
Одделете ги веб-барањата од работата во заднина
Контејнерот обично треба да има една главна одговорност. За PHP услугите, тоа често значи дека еден контејнер извршува PHP-FPM, друг извршува worker за редица, а обратен прокси или платформа го насочува HTTP сообраќајот. Тие може да ја делат истата слика на апликацијата, но треба да користат различни команди и правила за скалирање.
Ова раздвојување го прави оперативното однесување видливо. Веб-процесите можат да се скалираат со обемот на барања. Worker-ите можат да се скалираат со длабочината на редицата. Закажаната задача може да се извршува како наменска задача, наместо како бесконечна јамка скриена во веб-контејнерот.
- Одржувајте го обработувањето на HTTP барања одзивно и ограничено со тајмаути.
- Worker-ите нека потврдуваат работа само по успешна обработка.
- Дизајнирајте ги задачите да бидат идемпотентни, бидејќи повторувањата и дупликатната испорака се нормални појави.
- Осигурете се дека елегантното гасење ја запира новата работа пред процесот да заврши.
Елегантното гасење е особено важно за време на постепени распоредувања. Кога процесот добива сигнал за прекинување, треба да престане да прифаќа нови барања или задачи, да ја заврши безбедната работа во тек во ограничен период и да заврши. Ако ова однесување недостасува, распоредувањата можат да создадат неуспешни барања што може да се избегнат или делумно обработени пораки.
Направете ги промените во базата на податоци распоредливи
Контејнерите се ефемерни; базата на податоци не е. Третирајте ги миграциите на шемата како грижа при издавање, а не како нешто што секој веб-контејнер го обидува при подигнување. Повеќе реплики што се стартуваат истовремено може да се натпреваруваат за преземање заклучувања, да ја применат истата промена или да работат со шема што сè уште се менува.
Побезбеден образец е миграциите да се извршат еднаш, преку контролиран чекор на издавање или наменска задача. Уште поважно, дизајнирајте ги миграциите за компатибилност низ постепено распоредување. Додајте nullable колона пред кодот да зависи од неа. Распоредете код што може да ги чита и старите и новите претставувања. Пополнете ги податоците одделно кога е потребно. Отстранете ги старите колони или однесување само откако сите извршувани верзии повеќе не зависат од нив.
Овој пристап на проширување и стеснување е помалку драматичен од голема миграција, но го штити периодот кога старите и новите верзии на апликацијата коегзистираат.
Набљудливоста е дел од договорот за контејнерот
Здрав процес не е автоматски и здрава услуга. На контејнерите им се потребни корисни сигнали за операторите и системите за распоредување.
- Запишувајте ги логовите на апликацијата во стандарден излез или стандарден излез за грешки, во структуриран облик што може да се пребарува.
- Изложете лесна здравствена крајна точка што ја разликува достапноста на процесот од подготвеноста на зависностите, кога платформата ги поддржува двата концепта.
- Прикачете идентификатори на барање или корелација за еден неуспешен API повик да може да се следи низ услугите.
- Мерете латентност, стапки на грешки, старост на редицата и притисок врз ресурсите, наместо да се потпирате на рестартирања на контејнерот како дијагноза.
Проверките на здравјето треба да бидат мали и сигурни. Проверката на живост обично одговара дали процесот е заглавен. Проверката на подготвеност одговара дали треба да прима сообраќај. Избегнувајте која било крајна точка да извршува скапа работа или да зависи од секоја опционална интеграција. Во спротивно, мониторингот може да засили веќе деградирана ситуација со повторно отстранување на здрав капацитет.
Оптимизирајте за промени, а не само за првото распоредување
Најсилното Docker поставување е она што ги прави идните промени побезбедни. Одржувајте го Dockerfile читлив. Документирајте ги претпоставките за runtime-от близу до кодот. Тестирајте ја изградената слика во континуирана интеграција, а не само изворното стебло. Извршувајте проверки на зависности, конфигурација и стартување врз истиот артефакт што ќе биде распореден.
Подготвеноста за продукција не е контролна листа завршена по додавањето на CMD. Таа е архитектонска навика: градете непроменливи артефакти, безбедно внесувајте конфигурација, одделувајте ги оптоварувањата, внимателно развивајте ги податоците и направете го откажувањето видливо. Dockerfile го започнува разговорот. Вистинската инженерска вредност доаѓа од дизајнирањето на она што се случува откако контејнерот ќе се стартува.