Оптимизация Docker-образов с кодом приложения для production через более грамотное кэширование слоёв и мультистадийную сборку.
- 00:01:23 Установка пакетов в образе
- 00:03:04 Отключение скриптов установки
- 00:03:53 Производительность сборки слоёв
- 00:05:40 Перемещение слоя с vendor
- 00:08:26 Установка OPcache
- 00:10:40 Мультистадийная сборка
- 00:16:00 Обзор результата
Скрытый контент (код, слайды, ...) для подписчиков.
Открыть →Чтобы не пропускать новые эпизоды подпишитесь на наш канал @deworkerpro в Telegram
Подскажите как быть к примеру с папкой изображений, если это интернет-магазин, не будешь же ее в образ копировать.
Использовать для изображений отдельный файловый хостинг и загружать на него файлы из PHP по S3 или FTP.
А есть ли еще какие-то варианты, можно же монтировать файлы через volumes прямо внутрь нужных контейнеров для прода?
Если сервер один, то по аналогии с базами данных можно примонтировать папку
uploads
через вольюм. Но если серверов будет не один, а несколько с балансировкой, то к нескольким серверам одну папку примонтировать не получится.Добрый вечер.
Подскажите, как побороть проблему с сохранением файлов.
Требуется генерировать pdf файл на сайте.
Использую symfony bundle для генерации pdf, файл сохраняю в public/pdf.
После сохранения вывожу ссылку на файл.
На localhost всё работает, а когда выгружаю на рабочий сервер, то ссылка на файл не работает, выдаёт 404.
Посмотрел контейнеры fpm и nginx на localhost, в директории public/pdf, в обоих контейнерах, сохраняет файл.
На рабочем сайте файл сохраняется только в контейнере fpm, а в nginx его нет. Как я понимаю, при попытке открыть файл по ссылке обращение идёт к контейнеру nginx? Но раз в нём нет файла, то и получаю 404. И естественно, при deploy теряю все сгенерированные файлы.
В чём может быть причина?
Причина в том, что на продакшене nginx и php-fpm - это отдельные контейнеры со своими копиями папки
public
, очищающимися после перезапуска.Если они запущены на одном сервере, то как временное решение можно в продакшене через volumes создать общий том для файлов, который примонтировать в оба сервиса по адресу public/pdf.
Но как более корректное решение все сгенерированные или загруженные пользователем файлы обычно помещают в отдельный сервис файлового хранилища со своим томом:
И потом уже из php-fpm загружают в него файлы по FTP или S3. А из nginx-контейнера можно сделать проксирование на это хранилище по какому-нибудь префиксу
/static
Директория data не важно где будет расположена? Или в корне системы или в директории /home/username?
Зависит от того, какой сервис хранилища будете использовать.
использовать, как Вы сказали, более корректное, в отдельном сервисе storage. Как в Вашем примере выше.
Но пока сайт не совсем рабочий, в стадии разработки, думаю сделать простой вариант, хранение через volume.
Вы имеете ввиду так сделать?
Понял, буду пробовать.
В этом случае ссылка на файл будет такой?
http://domain.ru/pdf/file.pdf
Да, если добавите проксирование в nginx:
Не совсем понял.
Если я хочу вместо http://storage использовать доменное имя сайта, то как в этом случае?
Так или нет?
Нет. Это внутреннее проксирование рядом с проксированием на php-fpm.
Спасибо, буду пробовать.
Думаю, что получится)
А почему именно api-php-fpm?
Исправил.
Благодарю за помощь.
Пошёл пробовать.
Добрый вечер.
Не получается что-то.
Вроде сделал всё как Вы рекомендуете, но получаю ошибку 502
Вот полный конфиг nginx в production
Значит сервис storage не поднялся.
Это понятно. Может что-то не так делаю. Смотрел Ваши репозитории, для api и frontend у Вас созданы отдельные директории, со своими файлами конфигураций.
В моём случае нет директории storage. Нужно ли её создавать и создавать в ней файл конфигурации для nginx?
Нужно не просто создать папку, а в docker-compose объявить полноценный сервис файлового хранилища storage на основе образа вроде minio для работы по протоколу S3 или какого-нибудь другого для работы по FTP. И ему как для postgres объявить volume и placement.
Понятно, буду пробовать.
По поводу простого варианта хранилища
Добавил в docker.yml, файлы записываются и отображаются по ссылке. Но при попытке обновить файл всё равно отображается старая версия.
Добавил разрешение за запись
Файлы стали перезаписываться.
Но иногда надо всё-равно обновить страницу просмотра файла, чтобы отобразилась новая версия. Это связано с кэшем в docker? Как сделать, чтобы файлы не кэшировались?
Кэш обычно в браузере по заголовкам из nginx. Можете запретить кеширование pdf-файлов через Cache-Control.
В конфигурации nginx?
Да, в вашей секции:
Благодарю за подсказки.
Либо вместо этого использовать любой готовый файловый хостинг, чтобы не поднимать свой storage.
В этом вопросе ещё до конца не определились. Неизвестно, сколько файлов будет в конечном счёте.
Хотя думаю, что надо разобраться со своим storage, лишним не будет.
только тогда как будет выглядеть ссылка на файл?
Также.
в prod режиме как изменить параметры в файле параметров (напр.: params.php), где виде масива, хранится параметры: 'limitRowTable' => 20, 'limitRowSearchTable' => 35, и т.д. ? Каждый раз передеплоит сайт ?
Да, все изменения через передеплой.
а где лудшее тогда хранит таких параметров для многократного использования?
Часть можно хранить в переменных окружения.
у Вас на локалке стоит Ubuntu 18 или Debian.? (никак не получается make site error: ERROR! The file hosts.yml is marked as executable, but failed to execute correctly. If this is not supposed to be an executable script, correct this with
chmod -x hosts.yml
. ERROR! problem running /var/www/projects/auction/provisioning/hosts.yml --list ([Errno 8] Exec format error) ERROR! hosts.yml:6: Expected key=value host variable assignment, got: ssh )На локалке Ubuntu.
если у меня Ubuntu 16.04.6, то ansible-playbook будет ли коректно действовать?
Утилита популярная, так что везде должна работать.
а будет чат (с centrifugo или под.)?
Будут уведомления с Centrifugo.
:)
Наконец, сегодня деплоил проект https://demo-auction.skucai.com
Деплой заработал с исключением: для docker login задействовало 2 параметра - Username и Password, а в provisioning/docker-login.yml указанно 3: Registry, Username, Password. (В хостинге делал напрямую docker login). Почему не сработало make docker-login?
Я еще не дошел до полного деплоя, не могли бы вы добавить в ДНС www поддомен? Мне кажется, что в скрипте сербота должен быть www поддомен для получения сертификата.
Т.е. я так понял, что бы сделали образ builder, де факто проинсталлированный композер с вендором, просто чтобы второй + n раз не скачивать/устанавливать?
Да, сделали чтобы собирать чистовые образы легковесными без лишнего мусора.
в каком образе, в каком месте (при быльде для прода) собырается-копируется каталог api/src? Напр. api/public копируется в api/docker/production/nginx/Dockerfile (стр.: COPY ./public ./public), а где есть (COPY ./crc ./src) ни где ненашёл :(...
Какой сервер нужен для работы проекта? Я заказал на vscale самый дешевый за 200 руб. в месяц на убунте. Но похоже он не вывозит. При поднятии контейнеров пишет Killed и докер демон полностью отрубается.
Удалось поднять 3 контейнера на продакшн: gateway, frontend, registry. Реестр контейнеров поднял на этом же сервере заранее, запушил туда свои контейнеры и переподнял вот эти три. Не понятно сейчас с сервером что делать, я вроде видел что у Дмитрия тоже за 200 р. сервер, но на Debian. Перезаказать на Debian?
У нас пока Debian за 200. Со временем потребуется наращивание мощности или числа виртуалок для добавления прочего софта.
Чтобы процессы не отваливались из-за нехватки памяти в пиках можно добавить файл подкачки:
Применил. Заработало! Текущий проект поднялся!
Дмитрий, а разве OPCache не идет по умолчанию в php? Из документации: Это расширение доступно по умолчанию с PHP 5.5.0
Или докер образ alpine его не содержит?
В образах его по умолчанию нет. Список встроенных можно вывести командой:
Огромный минус - ссылка на гитхаб под каждым видео ведёт на некий финальный результат. Полностью не соответствует тому, что происходит на видео. Почему бы не бранчевать результат работы каждого выпуска? В том же мастере хранить актуальный-финальный результат на какой-то момент времени.
Ветки здесь не подойдут, так как все коммиты идут друг за другом. Только можно разметить тэгами.
Без разметки неудобно только при просмотре на GitHub или в консоли. Но если использовать любой GUI или пользоваться вкладкой Git/Log в PHPStorm, то смотреть коммиты и переключаться будет удобнее.
Может не совсем корректно описал, мы немного о разном. Предложение было такое: итогом работы в рамках конкретного урока является бранч, а мастер, например, финальный результат. И тут неважно, как были сделаный коммиты, пусть они даже были засквошены, главное, что в бранче лежит результат, достигнутый в рамках урока, который можно скопировать для опытов. Сейчас очень неудобно копаться в истории гита, даже в гуи.
Я и пишу, что от бранчей здесь не больше пользы, как от тегов. На тег также мождо сделать checkout.
а почему на dev мы запускали
apk update
, а на prod нет?Вместо
apk update && apk add
удобнее использовать сразуapk add --no-cache
а почему Вы говорите что ставим флаг --no-scripts, потом показываете следующей коммит и там его уже нету, аналогично его и нету в проекте на гитхабе?
Во всех строках с установкой
hirak/prestissimo
он есть.Прошу прощения за некропостинг, но хотелось бы понять, как правильно готовить многоэтапную сборку, когда нужно поставить ряд стандартных расширений пхп, которых нет в алпейне, но которые нужны почти всегда - gd, imap, intl, zip - для всех них необходимо поставить кучу пакетов и сходниками в контейнер (libzip-dev, libpng-dev, libwebp-dev, libfreetype6-dev. libmemcached-dev и тд.
Соответственно, в новый контейнер надо перенести .so собранные расширения пхп, чтобы в новом контейнере были только сами расширения, а не исходные коды, необходимые для их сборки...
вот хотелось бы этот момент уточнить, как это правильно делать.
Можно собрать отдельно по
docker-php-ext-install
, а потом уже в чистовик скопировать*.so
файлы, доустановитьlibzip
вместоlibzip-dev
, включить поdocker-php-ext-enable
как здесь. Но выигрыш от отсутствия исходников будет незначительный.Спасибо. Все понял.
Добрый вечер.
Дмитрий, подскажите пожалуйста, в примере по Вашей ссылке для директории extensions используется такая директория.
Из чего формируется название директории no-debug-non-zts-20200930?
Если использовать подход при установке расширений, как показано по ссылке, то непонятно как угадать название директории.
Формируется из версии PHP API, которую можно подсмотреть в информации:
Благодарю.
Дмитрий, как композер узнает про проектные классы если вы инсталите до копирования проекта, после копирования тогда необходимо RUN composer dump
Он пропишет себе в дамп папку
src
из секции "autoload". Сами классы его не интересуют.тогда почему при обращении и сборке как у Вас сервис говорит не могу найти \API\Hi класс, но стоит мне сначало скопировать и проинталировать или запустить composer dump - работает
А вы перед сборкой копируете composer.json и composer.lock?
Да, стоит копировать src вместе то работает, как только выношу как у Вас то теряются классы, но только composer dump лечит
Дмитрий, каждый раз надо перелогиниваться через гугл, может можно пофиксить?
Получается, что на продакшне мы копируем проект в 3 разных образа? В nginx, в php-fpm и в php-cli? Если так, то для чего это делается (можно же через volume из одного места пробросить)? С подходом через копирование в образы работать будет быстрее или это классический способ такой?
Это классический подход, когда всё приложение запаковано в образ, а через volume подключаются только папки для хранения данных. Про это ответил ранее на похожий вопрос про образы.
Или войти через: