Запустили отдельный промо-сайт для «Хороших админов» — https://промо.хорошиеадмины.рф
Как показала практика, основной сайт админов нам самим очень нравится, но для рекламы он работал не очень хорошо. Поэтому решили сделать отдельную площадку именно под продвижение, тестирование новых идей и услуг.
Там можно быстрее экспериментировать с подачей, проверять гипотезы и смотреть на реакцию посетителей.
Постепенно будем добавлять новые направления, кейсы и пробовать разные рекламные подходы.
#Сайт #Админы
Как показала практика, основной сайт админов нам самим очень нравится, но для рекламы он работал не очень хорошо. Поэтому решили сделать отдельную площадку именно под продвижение, тестирование новых идей и услуг.
Там можно быстрее экспериментировать с подачей, проверять гипотезы и смотреть на реакцию посетителей.
Постепенно будем добавлять новые направления, кейсы и пробовать разные рекламные подходы.
#Сайт #Админы
❤4
Немного истории про Docker в нашей компании.
На самом деле Docker мы используем уже очень давно, просто долгое время это было скорее инфраструктурным инструментом для админов, а не инструментарием для отдела разработки. Точную дату уже даже сложно вспомнить, но массово применять контейнеры начали примерно в районе 2020 года, когда у нас появились XWiki и другие службы инфраструктуры на Linux.
Docker тогда отлично решал простую задачу — развертывание софта со сложными зависимостями. У многих продуктов это вообще рекомендуемый способ установки: скачал контейнер, запустил и не думаешь о том, установлена ли в системе Java или PHP нужной версии.
Потом контейнеры постепенно начали проникать и в разработку.
Например, еще с 2021 года в QS: Спецодежда все SQL-миграции начали тестироваться перед релизом. Мы проверяем что:
— скрипты обновления не содержат ошибок и могут применяться к базе;
— пользователь сможет обновиться даже с самой первой версии программы;
— схема базы после обновления полностью совпадает со схемой чистой установки текущей версии.
В какой-то момент (2022 год) стало понятно, что тестировать это надо сразу на разных версиях MariaDB и MySQL, потому что различия в синтаксисе все же встречаются.
И вот тут Docker оказался очень удобным решением. Мы поднимали нужные версии баз в контейнерах на тестовом сервере и прогоняли полный набор проверок. На тот момент полный цикл тестов занимал больше двух часов. Но сами контейнеры уже были заранее развернуты на тестовом сервере и просто запускались или останавливались по необходимости.
Позже (уже 2025) контейнеры начали использовать и для визуального тестирования. На проекте Ямщик почти год назад через Docker поднимались контейнеры с приложением и Selenium-браузером для автоматического прогона UI-тестов.
Примерно тогда же пришли к мысли, что для тестов из C# кода тоже можно поднимать контейнеры с базами, тем самым значительно подняв актуальность тестов. Потому что наши основные тесты служб долгое время работали на SQLite в памяти. Это создавало проблемы: часть ошибок просто не воспроизводилась, а часть тестов была усеяна различными хаками из-за отличий синтаксиса SQLite от MySQL/MariaDB. При том что у нас большая часть тестов служб по сути интеграционные, потому что основная логика так или иначе завязана на базу данных.
В итоге постепенно перевели тесты служб на контейнеры с MariaDB и даже MongoDB, а заодно переписали и старые тесты SQL-скриптов на использование контейнеров прямо на тестируемой машинке — будь это рабочее место разработчика или сборочный сервер Jenkins. Для тестов поднимался контейнер, в нем разворачивалась база данных и прогонялись тесты.
Более того, это впоследствии позволило запускать пачки тестов параллельно по 10 штук, что сократило время тестирования в разы. В результате тестирование стало не только ближе к реальному продакшену, но и заметно быстрее — полный прогон сократился примерно с двух часов до 10-13 минут.
#Разработка #Docker
На самом деле Docker мы используем уже очень давно, просто долгое время это было скорее инфраструктурным инструментом для админов, а не инструментарием для отдела разработки. Точную дату уже даже сложно вспомнить, но массово применять контейнеры начали примерно в районе 2020 года, когда у нас появились XWiki и другие службы инфраструктуры на Linux.
Docker тогда отлично решал простую задачу — развертывание софта со сложными зависимостями. У многих продуктов это вообще рекомендуемый способ установки: скачал контейнер, запустил и не думаешь о том, установлена ли в системе Java или PHP нужной версии.
Потом контейнеры постепенно начали проникать и в разработку.
Например, еще с 2021 года в QS: Спецодежда все SQL-миграции начали тестироваться перед релизом. Мы проверяем что:
— скрипты обновления не содержат ошибок и могут применяться к базе;
— пользователь сможет обновиться даже с самой первой версии программы;
— схема базы после обновления полностью совпадает со схемой чистой установки текущей версии.
В какой-то момент (2022 год) стало понятно, что тестировать это надо сразу на разных версиях MariaDB и MySQL, потому что различия в синтаксисе все же встречаются.
И вот тут Docker оказался очень удобным решением. Мы поднимали нужные версии баз в контейнерах на тестовом сервере и прогоняли полный набор проверок. На тот момент полный цикл тестов занимал больше двух часов. Но сами контейнеры уже были заранее развернуты на тестовом сервере и просто запускались или останавливались по необходимости.
Позже (уже 2025) контейнеры начали использовать и для визуального тестирования. На проекте Ямщик почти год назад через Docker поднимались контейнеры с приложением и Selenium-браузером для автоматического прогона UI-тестов.
Примерно тогда же пришли к мысли, что для тестов из C# кода тоже можно поднимать контейнеры с базами, тем самым значительно подняв актуальность тестов. Потому что наши основные тесты служб долгое время работали на SQLite в памяти. Это создавало проблемы: часть ошибок просто не воспроизводилась, а часть тестов была усеяна различными хаками из-за отличий синтаксиса SQLite от MySQL/MariaDB. При том что у нас большая часть тестов служб по сути интеграционные, потому что основная логика так или иначе завязана на базу данных.
В итоге постепенно перевели тесты служб на контейнеры с MariaDB и даже MongoDB, а заодно переписали и старые тесты SQL-скриптов на использование контейнеров прямо на тестируемой машинке — будь это рабочее место разработчика или сборочный сервер Jenkins. Для тестов поднимался контейнер, в нем разворачивалась база данных и прогонялись тесты.
Более того, это впоследствии позволило запускать пачки тестов параллельно по 10 штук, что сократило время тестирования в разы. В результате тестирование стало не только ближе к реальному продакшену, но и заметно быстрее — полный прогон сократился примерно с двух часов до 10-13 минут.
#Разработка #Docker
❤1
Но при этом до полноценного использования Docker в продакшене для развертывания служб мы тогда еще не дошли.
Хотя предложения «давайте уже использовать Docker для деплоя» в команде звучали давно 🙂 И я долго отбивался от этого. Потому что это объективно еще один слой абстракции, дополнительная конфигурация и усложнение инфраструктуры.
И на тот момент я не очень понимал, что конкретно мы от этого выиграем. Кроме аргумента «сейчас так модно» 🙂
Тем более что деплой у нас и так уже был почти полностью автоматизирован через Jenkins-скрипты. Большая часть наших служб написана на .NET — поставил один раз runtime на сервер и забыл. С зависимостями проблем почти не было.
Из ручной работы в основном оставалась настройка reverse proxy (Apache/Nginx), получение сертификатов Let's Encrypt и перенос конфигурации при миграции служб между серверами.
А служб у нас к сегодняшнему моменту набралось уже около 25. И это именно наши Endpoint-ы и сервисы, без учета различных cron-скриптов и стороннего софта.
Когда службы начали все чаще переезжать между серверами — из-за балансировки нагрузки, перехода на .NET 8 и других инфраструктурных задач — стало понятно, что ручная настройка proxy и сертификатов начинает напрягать все сильнее.
А тут еще и новый программист пришел из мира микросервисов 🙂 Плюс у админов появились задачи задачи, где так или иначе приходится поддерживать клиентские Docker Swarm-кластеры. И дополнительный опыт не помешает.
В общем, все постепенно сошлось в одной точке, и стало понятно — пора.
Но про то, как именно мы сейчас перевозим службы в Docker и что из этого получилось, расскажем уже в следующих постах 🙂
#Разработка #Docker
Хотя предложения «давайте уже использовать Docker для деплоя» в команде звучали давно 🙂 И я долго отбивался от этого. Потому что это объективно еще один слой абстракции, дополнительная конфигурация и усложнение инфраструктуры.
И на тот момент я не очень понимал, что конкретно мы от этого выиграем. Кроме аргумента «сейчас так модно» 🙂
Тем более что деплой у нас и так уже был почти полностью автоматизирован через Jenkins-скрипты. Большая часть наших служб написана на .NET — поставил один раз runtime на сервер и забыл. С зависимостями проблем почти не было.
Из ручной работы в основном оставалась настройка reverse proxy (Apache/Nginx), получение сертификатов Let's Encrypt и перенос конфигурации при миграции служб между серверами.
А служб у нас к сегодняшнему моменту набралось уже около 25. И это именно наши Endpoint-ы и сервисы, без учета различных cron-скриптов и стороннего софта.
Когда службы начали все чаще переезжать между серверами — из-за балансировки нагрузки, перехода на .NET 8 и других инфраструктурных задач — стало понятно, что ручная настройка proxy и сертификатов начинает напрягать все сильнее.
А тут еще и новый программист пришел из мира микросервисов 🙂 Плюс у админов появились задачи задачи, где так или иначе приходится поддерживать клиентские Docker Swarm-кластеры. И дополнительный опыт не помешает.
В общем, все постепенно сошлось в одной точке, и стало понятно — пора.
Но про то, как именно мы сейчас перевозим службы в Docker и что из этого получилось, расскажем уже в следующих постах 🙂
#Разработка #Docker
👍4❤1🔥1
В прошлом посте рассказывал, как Docker постепенно появился в нашей разработке. Но использовать его для развертывания служб мы долго не спешили.
Когда все же решили переходить, поставили себе несколько практических целей:
— перенос службы на новый сервер должен сводиться к изменению одной строчки в Jenkins или Swarm-файле;
— новый сервер должен подготавливаться максимально просто: поставил Docker и готово;
— в случае аварии перенос службы на другую машину должен занимать не часы и не дни, а около 10–15 минут, пока обновляются DNS записи;
— в будущем должна появиться возможность перейти на Docker Swarm и попробовать онлайн-отказоустойчивость.
При аварийном переносе обычно съедают настройки, конфигурация, сертификаты, файлы и прочие "мелочи", про которые вспоминаешь только когда сервер уже лежит. Мы хотели чтобы аварийный перенос ничем не отличался от обычного деплоя. По сути остается только дождаться обновления DNS.
Первой задачей стало сделать службы полностью stateless.
Адреса баз данных, пароли, токены и прочие настройки принципиально никогда не хранились в коде. Обычно они лежали в
На некоторых проектах мы уже пробовали хранить конфигурацию в Git и просто выкладывать нужные файлы на сервер. Практика оказалась удобной: есть история изменений, ревизии, откаты. Поэтому решили не создавать еще одну точку отказа в виде отдельного хранилища конфигураций и продолжить использовать Git.
Рассматривали вариант хранить настройки прямо внутри контейнера вместе с приложением. Но тогда для смены пароля к базе пришлось бы пересобирать контейнер и заново его публиковать.
В итоге остановились на варианте с передачей конфигурации через Docker композ файл. Так многие настройки можно менять без пересборки приложения.
Следующей проблемой оказались файлы в локальной файловой системе.
Например, Ямщик хранил фотографии и аватарки в папках на сервере. Служба постоматов сохраняла видео сдачи спецодежды тоже в локальных файлах.
При переезде службы на другой сервер все это превращалось бы в отдельную задачу. Поэтому службы переписали на использование S3. Благо такая инфраструктура у нас уже давно была развернута.
Параллельно начали всплывать архитектурные особенности.
Например, сервис отправки электронной почты исторически находился внутри службы мобильного приложения. Хотя фактически уже использовался множеством других систем. Логично было выделить его в отдельную службу.
То же самое касается задач по расписанию. Если завтра служба будет запущена в нескольких экземплярах, такие процессы начнут выполняться одновременно на всех нодах. Поэтому подобные вещи заранее планируем выносить в отдельные сервисы.
Отдельно пришлось решать вопрос логирования.
Раньше службы работали через systemd. При отправке сообщения об ошибке можно было просто прочитать последние строки журнала и приложить их к отчету.
После переезда в Docker эта схема перестала работать. Более того, во время первых экспериментов со Swarm стало понятно, что стандартного docker logs нам тоже не хватит.
В итоге появился собственный логер, который держит последние 300 строк в памяти и может отправить их вместе с сообщением об ошибке на сервер.
На текущий момент из примерно 25 наших служб в Docker уже переведены 7. Остальные продолжают переезжать.
В следующем посте расскажем уже про взгляд со стороны администрирования: Traefik, registry, автоматическое получение сертификатов и то, что в итоге получилось у нас вместо классической схемы с Nginx на каждом сервере.
#Разработка #Docker
Когда все же решили переходить, поставили себе несколько практических целей:
— перенос службы на новый сервер должен сводиться к изменению одной строчки в Jenkins или Swarm-файле;
— новый сервер должен подготавливаться максимально просто: поставил Docker и готово;
— в случае аварии перенос службы на другую машину должен занимать не часы и не дни, а около 10–15 минут, пока обновляются DNS записи;
— в будущем должна появиться возможность перейти на Docker Swarm и попробовать онлайн-отказоустойчивость.
При аварийном переносе обычно съедают настройки, конфигурация, сертификаты, файлы и прочие "мелочи", про которые вспоминаешь только когда сервер уже лежит. Мы хотели чтобы аварийный перенос ничем не отличался от обычного деплоя. По сути остается только дождаться обновления DNS.
Первой задачей стало сделать службы полностью stateless.
Адреса баз данных, пароли, токены и прочие настройки принципиально никогда не хранились в коде. Обычно они лежали в
/etc на сервере. Но если служба должна легко переезжать между серверами, хранить конфигурацию на конкретной машине уже нельзя.На некоторых проектах мы уже пробовали хранить конфигурацию в Git и просто выкладывать нужные файлы на сервер. Практика оказалась удобной: есть история изменений, ревизии, откаты. Поэтому решили не создавать еще одну точку отказа в виде отдельного хранилища конфигураций и продолжить использовать Git.
Рассматривали вариант хранить настройки прямо внутри контейнера вместе с приложением. Но тогда для смены пароля к базе пришлось бы пересобирать контейнер и заново его публиковать.
В итоге остановились на варианте с передачей конфигурации через Docker композ файл. Так многие настройки можно менять без пересборки приложения.
Следующей проблемой оказались файлы в локальной файловой системе.
Например, Ямщик хранил фотографии и аватарки в папках на сервере. Служба постоматов сохраняла видео сдачи спецодежды тоже в локальных файлах.
При переезде службы на другой сервер все это превращалось бы в отдельную задачу. Поэтому службы переписали на использование S3. Благо такая инфраструктура у нас уже давно была развернута.
Параллельно начали всплывать архитектурные особенности.
Например, сервис отправки электронной почты исторически находился внутри службы мобильного приложения. Хотя фактически уже использовался множеством других систем. Логично было выделить его в отдельную службу.
То же самое касается задач по расписанию. Если завтра служба будет запущена в нескольких экземплярах, такие процессы начнут выполняться одновременно на всех нодах. Поэтому подобные вещи заранее планируем выносить в отдельные сервисы.
Отдельно пришлось решать вопрос логирования.
Раньше службы работали через systemd. При отправке сообщения об ошибке можно было просто прочитать последние строки журнала и приложить их к отчету.
После переезда в Docker эта схема перестала работать. Более того, во время первых экспериментов со Swarm стало понятно, что стандартного docker logs нам тоже не хватит.
В итоге появился собственный логер, который держит последние 300 строк в памяти и может отправить их вместе с сообщением об ошибке на сервер.
На текущий момент из примерно 25 наших служб в Docker уже переведены 7. Остальные продолжают переезжать.
В следующем посте расскажем уже про взгляд со стороны администрирования: Traefik, registry, автоматическое получение сертификатов и то, что в итоге получилось у нас вместо классической схемы с Nginx на каждом сервере.
#Разработка #Docker
👍1
Нам 18! Праздновали по-взрослому, но с детским восторгом!
В первый августовский выходной мы наконец собрались всей командой, чтобы это отметить — и оторвались по полной!
Где празднуют совершеннолетие крутые ИТ-шники? Правильно, в форте Константин в Кронштадте! Ведь если уж гулять, то с ветром, заливом и приключениями.
Мы отложили ноутбуки, надели кроссовки и… полезли на скалы! 🧗♀️ Кто-то впервые в жизни держался за верёвку, кто-то с лёгкостью покорил 9-метровую высоту. Оказалось, фиксить баги на продакшене — это не самое страшное испытание 😂
Потом был веревочный парк, троллей и крики «давай!» — спасибо коллегам, которые подбадривали громче инструкторов. А ещё мы впервые массово встали на сапы! 🏄♂️ Даже те, кто честно признавались: «я никогда не плавал и не собирался». Спойлер: поплыли! И даже не упали! Ну, почти все… 🤭
18 лет — это же время, когда ты уже взрослый, но ещё помнишь, как важно просто быть вместе. Мы не просто коллеги, мы — одна большая ИТ-семья, которая умеет и код писать и сапы покорять.
В первый августовский выходной мы наконец собрались всей командой, чтобы это отметить — и оторвались по полной!
Где празднуют совершеннолетие крутые ИТ-шники? Правильно, в форте Константин в Кронштадте! Ведь если уж гулять, то с ветром, заливом и приключениями.
Мы отложили ноутбуки, надели кроссовки и… полезли на скалы! 🧗♀️ Кто-то впервые в жизни держался за верёвку, кто-то с лёгкостью покорил 9-метровую высоту. Оказалось, фиксить баги на продакшене — это не самое страшное испытание 😂
Потом был веревочный парк, троллей и крики «давай!» — спасибо коллегам, которые подбадривали громче инструкторов. А ещё мы впервые массово встали на сапы! 🏄♂️ Даже те, кто честно признавались: «я никогда не плавал и не собирался». Спойлер: поплыли! И даже не упали! Ну, почти все… 🤭
18 лет — это же время, когда ты уже взрослый, но ещё помнишь, как важно просто быть вместе. Мы не просто коллеги, мы — одна большая ИТ-семья, которая умеет и код писать и сапы покорять.
❤4🔥4👍3🎉1
В недавнем релизе QS: Спецодежда мы написали, что ускорили сохранение отчетов в Excel в 80 раз. Эту оптимизацию сделал наш программист Артем Максимов.
Но путь от жалоб пользователей до такого результата получился довольно интересным.
На медленную выгрузку больших отчетов нам жаловались давно. На некоторых предприятиях годовые выгрузки приходилось формировать вручную прямо из базы.
Отчеты строятся через внешнюю библиотеку Majorsilence Reporting. Исходный код открыт, но разбираться в большом объеме чужого кода никому особенно не хотелось, поэтому проблему долго откладывали 🙂
Первый шаг сделали при оптимизации экспорта годового прогноза бюджета. Выяснилось, что только сохранение уже рассчитанных строк в Excel занимало около 20 секунд. Заменили NPOI на ClosedXML — и этот этап стал выполняться меньше чем за секунду.
Тогда появилась логичная мысль: в отчетах используется та же библиотека.
В ноябре 2025 года Артем добавил новый вариант форматированного экспорта через ClosedXML. Для отчета объемом 172 страницы получили такие результаты:
На фоне старых 30 минут результат выглядел отличным. Тем более форматированный Excel почти приблизился по скорости к режиму, который просто записывает строки в файл.
Но пользователи продолжили жаловаться. Оказалось, что они и так применяли самый быстрый экспорт без форматирования, однако на реальных отчетах он мог занимать 20 минут и больше.
И уже по первым тестам было видно что-то странное: PDF с разметкой страниц формировался за 3 секунды, а простая таблица Excel — за 23 секунды. Особенно сильно проблема проявлялась после 20 000 строк.
Стало понятно, что дело не только в библиотеке Excel. Артем снова засучил рукава и полез в чужой код 🙂
Нашли два основных узких места.
При создании каждой новой ячейки код несколько раз перебирал массив всех предыдущих ячеек. Чем больше становился отчет, тем медленнее добавлялась каждая следующая ячейка. Этот перебор заменили более эффективным поиском.
Кроме того, для каждой ячейки заново создавался стиль, хотя внутри одной колонки стили были одинаковыми. Этот участок тоже переработали и добавили еще несколько небольших оптимизаций.
Итоговые результаты:
В результате обычный экспорт ускорился в 81 раз, а форматированный — почти в 8 раз. Теперь даже отчет на полмиллиона строк можно выгрузить за вполне приемлемое время.
Мораль всей басни: если медленная сторонняя библиотека имеет открытый исходный код, проблему не обязательно терпеть годами. Иногда достаточно приложить к ней руки и голову.
#Разработка #QSСпецодежда
Но путь от жалоб пользователей до такого результата получился довольно интересным.
На медленную выгрузку больших отчетов нам жаловались давно. На некоторых предприятиях годовые выгрузки приходилось формировать вручную прямо из базы.
Отчеты строятся через внешнюю библиотеку Majorsilence Reporting. Исходный код открыт, но разбираться в большом объеме чужого кода никому особенно не хотелось, поэтому проблему долго откладывали 🙂
Первый шаг сделали при оптимизации экспорта годового прогноза бюджета. Выяснилось, что только сохранение уже рассчитанных строк в Excel занимало около 20 секунд. Заменили NPOI на ClosedXML — и этот этап стал выполняться меньше чем за секунду.
Тогда появилась логичная мысль: в отчетах используется та же библиотека.
В ноябре 2025 года Артем добавил новый вариант форматированного экспорта через ClosedXML. Для отчета объемом 172 страницы получили такие результаты:
Формат Время
────────────────────────────────────────────
PDF 0:03
Excel без форматирования 0:23
Excel, ClosedXML 0:37
Excel, старый NPOI 30:41
На фоне старых 30 минут результат выглядел отличным. Тем более форматированный Excel почти приблизился по скорости к режиму, который просто записывает строки в файл.
Но пользователи продолжили жаловаться. Оказалось, что они и так применяли самый быстрый экспорт без форматирования, однако на реальных отчетах он мог занимать 20 минут и больше.
И уже по первым тестам было видно что-то странное: PDF с разметкой страниц формировался за 3 секунды, а простая таблица Excel — за 23 секунды. Особенно сильно проблема проявлялась после 20 000 строк.
Стало понятно, что дело не только в библиотеке Excel. Артем снова засучил рукава и полез в чужой код 🙂
Нашли два основных узких места.
При создании каждой новой ячейки код несколько раз перебирал массив всех предыдущих ячеек. Чем больше становился отчет, тем медленнее добавлялась каждая следующая ячейка. Этот перебор заменили более эффективным поиском.
Кроме того, для каждой ячейки заново создавался стиль, хотя внутри одной колонки стили были одинаковыми. Этот участок тоже переработали и добавили еще несколько небольших оптимизаций.
Итоговые результаты:
Строк Режим Время
──────────────────────────────────────────────────
10 000 Без форматирования, старый 5:25
10 000 Без форматирования, новый 0:04
10 000 ClosedXML, старый 0:55
10 000 ClosedXML, новый 0:07
100 000 Без форматирования 0:30
100 000 ClosedXML 1:28
500 000 Без форматирования 1:20
500 000 ClosedXML 5:55
В результате обычный экспорт ускорился в 81 раз, а форматированный — почти в 8 раз. Теперь даже отчет на полмиллиона строк можно выгрузить за вполне приемлемое время.
Мораль всей басни: если медленная сторонняя библиотека имеет открытый исходный код, проблему не обязательно терпеть годами. Иногда достаточно приложить к ней руки и голову.
#Разработка #QSСпецодежда
❤🔥1⚡1
Про что хотите следующую историю?
Anonymous Poll
33%
Продолжить про Docker
44%
Ceph
67%
Проект Торпеда Спецодежды