Задать вопрос
  • Как правильно обработать параллельные запросы в Telegram Bot?

    @MadridianFox
    Web-программист, многостаночник
    Возможно вы запускаете код в виде одного потока, как иногда советуют для быстрого старта разработки.
    Обычно веб-приложения на php запускаются через php-fpm - менеджер процессов, который держит пул процессов, обрабатывающих входящие запросы. Если процессов не хватает - он создаёт новые, а когда они простаивают - завершает лишние.
    Связки php-fpm + nginx хватает для подавляющего большинства веб-приложений.

    Ещё стоит подумать о выводе обработки сообщений из веб-приложения в фон. Телеграму не интересно ждать 10-20 секунд когда отработает логика вашего приложения. И это и не нужно. Вы получили запрос, сразу ответили телеграму что всё ок, и можете положить сообщение в БД и дальше обработать его совсем другим процессом.
    Часто для этого используются очереди сообщений. Веб-приложение кладёт сообщение в очередь, а другая программа следит за тем есть ли что-то в очереди, и если есть, то обрабатывает.
    Хорошая реализация обработчика очередей на php - laravel queue. Сообщения кладутся в redis (или в БД если так хочется).
    Ответ написан
    Комментировать
  • Оптимизация WordPress сайта установленного в Kubernetes (несколько реплик/копий)?

    @MadridianFox
    Web-программист, многостаночник
    Проще всего будет определить в какую папку всё это складывается и вынести её в PersistentVolume (PV). Ваш k8s конечно же должен иметь возможность создания PV с типом ReadWriteMany - это когда поды на разных машинах могут подключать к себе один и тот же PV. Проще всего выделить в инфраструктуре NFS сервер и настроить кубер работать с ним.

    В результате в манифесте деплоймента будет что-то типа
    volumes:
      - name: optimized-assets
        persistentVolumeClaim:
          claimName: my-optimized-assets-pvc
    containers:
      - name: app
        image: "my.registry.org/wp-site:v1.2.3"
        volumeMounts:
        - name: optimized-assets
          mountPath: /var/www/public/assets


    немного теории

    Запуская веб-приложение в нескольких экземплярах на разных машинах/контейнерах, необходимо позаботиться о том чтобы некоторые его части шарились (share) между всеми экземплярами.
    Обычно речь про
    - папку загрузок
    - сессии пользователя
    - кэш

    В идеале для всего этого стоит использовать отдельные сервисы, например сессии и кэш можно хранить в memcached или redis, а загрузки хранить не файлами на диске, а в S3.

    Но можно делать проще. Те же загрузки - это файлы на диске, значит папку с этими файлами можно расшарить между экземплярами через nfs.

    Немного отдельно стоит кэш кода. Это когда приложение может скопилировать шаблоны, минифицировать скрипты, сохранять байткод. Обычно это не шарится между контейнерами, а выполняется при старте контейнера, либо при сборке образа.
    Ответ написан
    Комментировать
  • Как получить id страницы до ее создания в Ларавель?

    @MadridianFox
    Web-программист, многостаночник
    При сохранении модели в БД, фреймворк автоматически получает её id, и он становится доступным через одноимённое поле.
    Как уже писали выше, делает это вот так
    $myModel->save();
    echo $myModel->id;

    Когда вам нужно записать данные в связанные таблицы, то вам определённо нужено делать это последовательно.
    Вы не можете сначала сохранить строку в связанную таблицу с вымышленным id, а потом сохранить модель в первую таблицу с этим id - проверка целостности не позволит использовать несуществующий foreign key.
    Поэтому код сохранения нескольких связанных записей нужно свести к
    $myModel->save();
    
    $relatedModel = new RelatedModel();
    $relatedModel->my_model_id = $myModel->id;
    
    $relatedModel->save();


    Если вдруг, как-то так получилось, что как-то невообразимым образом при сохранении первой модели нужно знать id второй модели, а при созранении второй - id первой, то у вас проблема - схема БД и логика приложения неправильные.
    Если это какое-то легаси, не ваше, которое нельзя исправить и просто надо как-то доработать, ну тогда поверх одних неправильных решений придётся делать свои осознанно "неправильные" решения, например отказываться от FK на поле, делать его nullable, разбивать сохранение записи на несколько этапов - сначала все данные без id связи, потом отдельно id связи после того как она сама будет создана в БД.
    Ну это так, мысли вслух про странные случаи.

    И опять же, как уже писали, для правильно реализованных моделей есть функции-хелперы, упрощающие связывание моделей
    $myModel->save();
    $myModel->relatedModels()->attach($relatedModel);
    Ответ написан
    Комментировать
  • Как организовать локальные домены при разработке?

    @MadridianFox
    Web-программист, многостаночник
    Я обычно поднимаю ещё один контейнер с nginx, который слушает порты 80 и 443 на хосте и раскидывает запросы в разные контейнеры по доменам или по локейшенам.
    Чтобы не прописывать вручную в hosts домены, когда сервисов много, использую nip.io
    Такие же домены назначаю как hostname контейнерам, для единообразия.
    А чтобы не писать однотипные конфиги nginx - https://hub.docker.com/r/jwilder/nginx-proxy/

    Для управления самоподписанными сертификатами для разработки есть https://github.com/FiloSottile/mkcert
    Ответ написан
    Комментировать
  • Как узнать реальный IP адрес клиента в подсети Docker?

    @MadridianFox
    Web-программист, многостаночник
    Нужно чтобы "снаружи" относительно сети докера был L7 прокси, который видит ip клиента, и который добавит этот ip в заголовки запроса.
    Ответ написан
    Комментировать
  • Как анализировать JS и PHP ошибки на своем сайте?

    @MadridianFox
    Web-программист, многостаночник
    Есть saas сервисы мониторинга, которые дают free tier. Нужно только установить их агент на свой сервер и немного настроить.
    Примеры:
    - grafana cloud
    - newrelic
    - datadog

    Можно собрать подобную систему из opensource (или не совсем open, но бесплатных) компонентов.
    Сбор логов из файлов:
    - vector
    - fluent-bit
    - filebeat

    Хранение логов:
    - elasticsearch
    - loki
    - openobserve
    - victoria logs
    - graylog

    Визуализация:
    - kibana (только вместе с elasticsearch)
    - grafana (loki, victoria)
    - openobserve и graylog имеют свой интерфейс
    Ответ написан
    Комментировать
  • Надо ли ставить на саму машину или можно в Docker?

    @MadridianFox
    Web-программист, многостаночник
    Важно понимать, что докер демон - это сервер, и он работает по сети, т.е. может быть доступен с другой машины или из контейнера.
    Самому дженкинсу докер не нужен (если не используется docker plugin для динамисеского создания агентов в контейнерах). Докер нужен агенту, потому что скорее всего вы хотите в итоге собрать докер образ.
    Однако, и агенту сам докер не нужен, нужен только клиент докера, а докер-демон может быть в другом месте.
    Кроме того, использовать мастер-ноду дженкинса это моветон. Это может помешать работе дженкинса. Лучше выделять отдельных агентов.
    В вашем случае нужно сделать следующее: собрать докер образ агента, в котором помимо самого агента будет докер(клиент) и необходимые вам инструменты.
    Далее запускаете этот образ с монтирования в него сокета докера, тогда докер-клиент внутри контейнера будет работать с докер-демоном на хосте.
    Ну и далее подключаете этот агент к дженкинсу. Сам дженкинс тут может быть вообще без дополнительных инструментов, без докера и даже на другой машине, хотя проще его поднять тут же в докере.
    Это не самая безопасная схема, есть недостатки.

    Другой вариант - собрать образ можно через podman. Это "докер" без демона. Его легче запустить в контейнере. Опять же его надо установить в образ агента.

    Ну или полноценный dind, да. Опять же в агенте.

    Если не хотите а отдельный агент, то да, вам нужно сделать всё это с образом дженкинса и использовать мастер-ноду.
    Ответ написан
    3 комментария
  • Как настроить сервер для правильного обновления веб-приложения React?

    @MadridianFox
    Web-программист, многостаночник
    Кэшируйте отдаваемые ассеты. Тогда nginx сможет ответить на запрос старого файла даже после того как вы обновили содержимое папки.
    Ответ написан
    Комментировать
  • Как запустить php и nginx в одном контейнере?

    @MadridianFox
    Web-программист, многостаночник
    1) Запуск нескольких процессов в одном контейнере противоречит концепции докера. Докер сделан так, чтобы запускать один процесс (не считая дочерних процессов)

    По хорошему вам нужно запускать fpm и nginx в отдельных контейнерах. При этом возникает несколько проблем:
    - нужно чтобы контейнер nginx мог обратиться к контейнеру fpm по сети
    - нужно чтобы nginx мог раздавать статику, которая обычно является частью приложения и находится в контейнере fpm
    - нужно раздавать загружаемые файлы

    Проще всего с загружаемыми файлами. Они в любом случае не должны храниться в контейнере и скорее всего это будет volume, который монтируется в оба контейнера.
    Взаимодействие между контейнерами по сети тоже штука не сложная, но зависит от способа запуска контейнера.
    Если контейнеры запущены через docker run в одной сети (поведение по умолчанию), то они видят друг друга по сети и могут использовать имя контейнера как dns имя.
    Если два контейнера запущены в рамках одного docker-compose.yml файла (это ещё называется docker compose project), то они тоже друг друга видят, но уже не по имени контейнера, а по имени сервиса (ключ под которым контейнер указан в секции services).
    Если приложение запускается в kubernetes, то там по умолчанию все контейнера pod'a имеют общий локалхост и могут обращаться к друг другу через 127.0.0.1.

    Всё это - поведение по умолчанию, которое можно изменить явно указывая какую сеть использовать, какой hostname должен быть у контейнера и т.д.

    Важно: nginx работает с dns в обход стандартных инструментов операционной системы. Если вы используете в директивах proxy_pass, fastcgi_pass доменное имя, а не ip адрес, вам нужно дополнительно указать в конфиге директиву resolver <dns-ip>;, где в качестве нужно указать ip адрес dns сервера.
    Для докера это обычно 127.0.0.11, для кубера это адрес внутреннего dns сервера.

    Раздавать статику можно по разному. Два концептуально разных способа:
    - собрать образ nginx в котором есть статика, тут можно либо наследовать образ как сделали это вы, либо копировать статику в чистый образ nginx, что несколько чище и красивее
    - убрать статику из образа вообще, выделив её в volume или cdn, но тут придётся при отгрузке сервиса актуализировать статику во внешнем хранилище

    2) если очень хочется запустить несколько процессов в контейнере, то нужно запустить один процесс, который запустит остальные. Есть такие программы - менеджеры процессов. Это может быть supervosord, pm2, runit и т.п.
    Это такая программа, основной задачей которой является запуск других программ. Обычно у неё есть свой файл конфигурации, в котором вы описываете какие программы запустить и как это сделать.
    Ещё раз повторю - докер придуман не для этого. Не стоит делать этот приём основным при работе с докером.
    Это костыль. Он иногда нужен, но очень редко.

    3) То что nginx отдаёт код index.php, это проблема не настройки контейнеров, а конфигурации nginx. Если бы проблема была только в контейнерах, то вы бы получили не код скрипта, а 502.
    Первое что бросается в глаза в вашем конфиге - это регулярка в локейшене для обработки php скриптов.
    Попробуйте сделать как здесь.
    Ответ написан
    Комментировать
  • Как максимально ограничить права приложения в контейнере?

    @MadridianFox
    Web-программист, многостаночник
    Попробуйте использовать distorless образ - в нем нет ничего кроме рантайма необходимого вам ЯП. Этот вариант более универсальный.

    Другой вариант - использовать AppArmor. Здесь уже образ не совсем самодостаточный и надо ещё запустить контейнер с особыми флагами. Зато получается именно то что вам нужно - явный запрет на конкретные действия.
    Ответ написан
    Комментировать
  • Запуск проекта django с белого ip?

    @MadridianFox
    Web-программист, многостаночник
    Белый ip назначен вашему роутеру. У вашего компьютера другой ip адрес - адрес приватной сети, обычно начинается на 192.168 или на 10.
    Когда вы запускаете программу с адресом 0.0.0.0, вы говорите ей слушать все сетевые интерфейсы вашего компьютера. Но только вашего компьютера.
    Чтобы настроить доступ к вашему серверу через белый ip, вам нужно настроить на вашем роутере проброс порта. Это может называться иначе. Суть такая: вы говорите роутеру, что если пришло соединение на <адрес-роутера>:<порт-роутера>, то проксировать его на <адрес-компьютера>:<порт-компьютера>.
    Ответ написан
    Комментировать
  • Как сделать так, что бы Jenkis (в docker) запускал jenkins-agent (в docker)?

    @MadridianFox
    Web-программист, многостаночник
    Есть плагин Docker plugin. Он добавляет в дженкинс cloud типа docker. Cloud - это как раз способ запускать и останавливать агенты по требованию.

    При настройке клауда вам потребуется указать адрес докер-демона. Это может быть как tcp host:port, так и unix socket, если вы примонтировали его в контейнер дженкинса.

    При этом, и в контейнер агента можно прокинуть адрес/сокет докера, чтобы иметь возможность из пайплайн работать с докером. Только придётся установить в образ агента пакет самого докера, чтобы в контейнере был доступен клиент докера.

    Далее уже можно в пайплайне как напрямую через bash вызывать docker run/build, так и с помощью плагина Docker pipeline plugin
    Ответ написан
    Комментировать
  • Почему возникает ошибка?

    @MadridianFox
    Web-программист, многостаночник
    Как уже было отмечено в комментарии ку вопросу, этот пакет использует установленный в системе dig.
    В контейнере dig не установлен.
    Добавьте установку соответствующего пакета в Dockerfile и код будет работать и внутри контейнера.
    Ответ написан
    Комментировать
  • Почему я не могу переназначить адрес nginx location?

    @MadridianFox
    Web-программист, многостаночник
    Nginx принимает запрос и проксирует его дальше на основании каких-то правил. Ответ он не преобразует. За ссылки отвечает приложение, т.е. tomcat. Вам нужно так написать код сайта, чтобы в нем была возможность настроить т.н. корень, от которого строятся ссылки.
    Ответ написан
    Комментировать
  • Возможно ли на сервере установить ограничения на определенный каталог или пользователя на скачивание и загрузку?

    @MadridianFox
    Web-программист, многостаночник
    Здесь есть логическое противоречие. Чтобы выполнить задачу, разработчику нужен доступ к файлам и бд. Любое ограничение скажется на скорости выполнения задачи и на качестве результата.
    Если ограничите доступ к коду, например выдав доступ по rdp, то разраб не сможет пользоваться привычными инструментами. Если ограничите скорость соединения, то превратите работу в цирк.

    Как вариант - сделать специальный бэкап БД для разработчика, в котором не будет секретных данных, а вместо них случайный текст. Однако для этого может потребоваться помощь другого фрилансера.

    Тот факт, что вы спрашиваете как ограничить доступ, показывает что вы не в теме, и не сможете предусмотреть все варианты. Кто будет виноват, если следуя одному из советов, вы не предотвратите кражу интеллектуальной собственности?

    Если это настолько важно, то заключайте соответствующий договор с исполнителем.
    Ответ написан
    2 комментария
  • Как создать автозапуск команды в linux?

    @MadridianFox
    Web-программист, многостаночник
    1) зачем вам оборачивать soketi в screen? Лучше напрямую запускать сам soketi
    2) вероятно мешает опция screen -d, потому что type=simple ожидает что программа запустится и продолжит работать
    Ответ написан
    8 комментариев
  • Как использовать istio virtualservice внутри кластера вне mesh сети?

    @MadridianFox
    Web-программист, многостаночник
    Istio не влияет на работу класткрного dns. Обращаясь к нему вы получаете ip подов и всё работает по старому.
    Чтобы трафик шёл через меш, istio добавляет в под init контейнер, который через iptables захватывает весь исходящий трафик и направляет его в сайдкар.

    По хорошему внешние сервисы должны обращаться к внутренним через ingress, который, будучи таким же подом как и все другие, исходящий трафик шлёт уже через меш.
    Если нужно чтобы обращения были по внутренним доменам, то можно давать ингресам такие домены, а на стороне внешнего сервиса поиграться с dns.

    Другой вариант - поднять на стороне внешнего сервиса агент istio - тот же сервис, который работает в сайдкар. Вот официальная документация как раз для такого случая https://istio.io/latest/docs/setup/install/virtual...
    Ответ написан
  • Как организовать связь между контейнерами?

    @MadridianFox
    Web-программист, многостаночник
    Если контейнеры запущены через docker run без указания сети, то они уже в одной сети и могут обращаться друг к другу используя имя контейнера в качестве имени хоста.

    Если контейнеры запускаются через docker-compose, то, по умолчанию, на каждый docker-compose.yml файл создаётся отдельная сеть. Это надо учитывать если сервисы запускаются через разные файлы. В этом случае сеть стоит создать вручную и прописать её использование во всех docker-compose.yml файлах.

    При запуске через docker-compose в качестве имени хоста контейнера используется не имя контейнера, а имя сервиса.

    В обоих случаях имя хоста можно переопределить через опцию hostname. В обоих случаях порты пробрасывать не надо.
    Ответ написан
    Комментировать
  • Laravel. Как тестировать кэширование?

    @MadridianFox
    Web-программист, многостаночник
    Многие фасады в ларавеле позволяют получить мок или задавать ожидания прямо через фасад.
    В документации пример как раз с кешем.
    https://laravel.com/docs/10.x/mocking#mocking-facades
    Ответ написан
    Комментировать
  • Как ограничить доступ к порту на докер контейнере?

    @MadridianFox
    Web-программист, многостаночник
    Чтобы не было доступа к контейнеру можно изначально его не открывать.
    Например не публиковать порт, если это приложение нужно другому контейнеру. Или публиковать порт на локалхост, а не на все интерфейсы.
    Ответ написан
    Комментировать