Как стать автором
Обновить

Комментарии 21

Для обновления через бинарные патчи можно попробовать подключить https://github.com/inconshreveable/go-update. Помимо бинарных патчей есть возможность проверять подпись через gpg.
Правда проект давно не обновлялся.

Спасибо, кажется, я когда-то его уже смотрел, но не помню, чем не устроил. Нужно будет еще раз внимательно глянуть.

Платой за компактный размер будет время на запуск, так как предварительно требуется распаковка.

Это только самое очевидное. А вот вам еще немножко очевидностей до кучи:

1. Плата за упаковщих — это повышенный расход оперативной памяти. Упаковщик сначала распаковывает весь код в память, потом передает ему управление. Т.е. в памяти будут как остатки распаковывающего кода, так и весь код программы.
При нормальной работе программы в память грузятся только те страницы памяти, к которым осуществляется доступ (т.к. практически все ОС используют memory mapping для загрузки исполняемых файлов в память).

2. Плата за упаковщик — срабатывание эвристического анализатора у некоторых антивирусов. Причем срабатывать может не на все версии программы, а только на некоторые билды. С точки зрения антивируса упаковщик занимается подозрительными вещами — раскладывает данные по памяти и передает им управление, да еще и манипулирует атрибутами страниц памяти.

3. Плата за упаковщик — повышенный риск глюков. Упаковщик тоже не боженька писал, в нем возможны ошибки. В результате программа может глючить или вообще не запускаться на некоторых машинах.

4. Нужно еще суметь правильно вкрячить упаковщик в систему сборки (это, наверное, не про go, но все-таки). Если у вас на каждый чих запускается upx и пять секунд пакует бинарь, на двадцатый раз вы будете тихо ненавидеть этот ползущий индикатор. :)

Мало того: без упаковщика при запуска нескольких копий программы код будет замаплен в RAM только один раз, а с упаковщиком — сколько копий программы запускаешь, столько раз и будет занято место в RAM под целиком распакованное приложение.

Мы же о Go-программах говорим, правда? ) Которые статически собираются по-умолчанию. Если думать о запуске разных копий программы, то тогда и про динамическую линковку надо думать.

> Если думать о запуске разных копий программы, то тогда и про динамическую линковку надо думать.

Необязательно. Конечно, запуски разных программ не смогут разделять общие библиотеки, но запуски одной и той же программы разделять память с кодом вполне сможет.
  1. Плата за упаковщих — это повышенный расход оперативной памяти.
    В контексте программы-демона это не очень актуально. В моем конкретном случае разница составляет ~10 Кб на 5 Мб, то есть 0,2%. Сегмент кода будет прогружен полностью и сразу.
  2. Плата за упаковщик — срабатывание эвристического анализатора у некоторых антивирусов
    В контексте Linux-серверов меня опять таки это не беспокоит. Но на Windows, да, этот момент более актуален.
  3. Плата за упаковщик — повышенный риск глюков… может глючить или вообще не запускаться…
    На счет глючить — скорее, нет. Упаковщик не меняет ваш код. Потенциальное место для новых проблем — лишь сам код распаковки. Однако UPX довольно взрослый проект. Шансов, что баги будут в моем собственном кода — на порядок выше.
  4. Нужно еще суметь правильно вкрячить упаковщик в систему сборки
    Это стандартная задача подготовки debug и release-сборок. Я конечно же, не занимаюсь отладкой и профилированием пострипанного и упакованного бинарника. Да, upx — это еще одна дополнительная зависимость на сборке, но профит того стоит (в моем случае, как минимум).

В контексте Linux-серверов меня опять таки это не беспокоит. Но на Windows, да, этот момент более актуален.

Вы забыли ключевое слово «пока».
Пока что да, на линуксе и антивирусы-то редко ставят. Но у меня был неприятный опыт, когда на сервере стоял, кажется, Касперский для линукс. Он упорно удалял один из скриптов на перле, считая его вирусом — в результате у клиентов не обновлялась статистика в личном кабинете. Пришлось бодаться с сисадмином, которому синдром вахтера не давал прописать исключения в конфиг.

На счет глючить — скорее, нет. Упаковщик не меняет ваш код.

Бгг.
Сам-то код не трогает, а вот релокейшены по всему коду фиксит.

Распаковщику приходится брать на себя функции системного загрузчика. А там, поверьте, мрачно, есть где запутаться и напортачить в коде. Тем более что код кроссплатформенный и не везде одинаково хорошо протестирован.

Потенциальное место для новых проблем — лишь сам код распаковки.

Не-а. Обновляются операционки, чуть-чуть меняется логика работы системного загрузчика — этого может быть достаточно для того, чтобы ВСЕ ваши упакованные бинари вдруг перестали запускаться на определенной системе.
И да, в упаковщиках тоже могут быть ошибки.
И да, в упаковщиках тоже могут быть ошибки.

В любом коде могут быть ошибки :) Что ж после этого код не писать и чужими наработками не пользоваться?


Пока что да, на линуксе и антивирусы-то редко ставят.

Можете глянуть в профиле мое место работы :) Я довольно хорошо в курсе насколько часто на Linux-серверах бывает DrWeb и Kaspersky. Но суть даже не в этом. Антивирусам прекрасно знакомы все более-менее популярные упаковщики и анализ выполняется распакованного кода.


Тем более что код кроссплатформенный и не везде одинаково хорошо протестирован.

Код там конкретный под каждую платформу/архитектуру. Кода относительно немного и он не такой магический, как может показаться на первый взгляд (говорю это в первую очередь в контексте ELF/Linux). Не хочу спорить кто и где хорошо или плохо протестирован. Но проект не вчера появился и является достаточно стабильным и популярным. Пользоваться ли им в своем проекте — решать вам. Но убеждать меня в том, что он глючит и плохо работает, а ближаший апдейт CentOS'а — рассыпется, немного странно.

Но убеждать меня в том, что он глючит и плохо работает, а ближаший апдейт CentOS'а — рассыпется, немного странно.

Немного странно то, что вы мне приписываете слова, которых я не говорил. Можно цитату, где я вас убеждаю, что UPX глючит и плохо работает?

Я говорю, что использование UPX потенциально может привести к проблемам. UPX работает на низком уровне и заменяет собой системный загрузчик — очевидно, если логика работы системного загрузчика поменяется, то и программы, ужатые UPX, перестанут запускаться. По-моему, это очевидно и спорить тут не о чем.

И слон в комнате, которого тут не заметили: сегмент памяти с кодом программы будет открыт на запись. Другими словами, у вас будет сегмент памяти, доступный и для записи, и для исполнения. Это совершенно отвратительная ситуация с точки зрения безопасности

Временно, полагаю. Не проверял, но почти уверен, что UPX по окончанию распаковки возвращает всем секциям те права доступа, которые были до упаковки.

Спасибо за ссылку! Интересная статья. И очень хорошо запрятанная :) Интересно, как вы на нее вышли?

В Go, мне, как раз, нравится то, что приложение собирается статически и можно не беспокоиться о том, что на какой-то машине не заработает. Конечно, не 100%, но спокойнее.

А что касается размера, то `-ldflags="-s -w"` достаточно (с учётом, что изначально приложение весит 30M+, а с этой опцией ужимает до 10M-15M). Ну, или просто убрать debug информацию с помощью команды `strip -s APPLICATION`.

По upx: да, хорошая программа, знаю давно, но пару раз на Go программах (когда язык только начал распространяться), результирующее приложение вылетало при старте. Возможно, потом это починили, т.к. в последнее время с таким не сталкивался. Но для production, всё равно, его не использую — достаточно удаления debug информации.

P.S. Спасибо за информацию о Sentry. Нужно как-нибудь поизучать его. Всегда полезно быть в курсе работы приложения.

У меня ситуация в том, что чем меньше размер бинарника, тем больше будет трафика при раздаче обновления. То есть работает формула "одно обновление" = "размер бинарника" х "количество машин". Машин в потенциале предполагается очень много. Собственно, этим и были вызваны описанные выше упражнения :)

А заливать архив и распаковывать на сервере не проще? Всё равно, после заливки выполняются дополнительные действия, вызываемые на сервере. Ну, как минимум, перезапуск приложения. Можно добавить и разархивирование. 7z, xz сжимают неплохо. Как уже писали, с upx будут накладные расходы по памяти.
А заливать архив и распаковывать на сервере не проще?

Я кратко упоминал этот вариант, но не раскрывал деталей. Суть в том, что это еще одна зависимость. Целевые машины не находятся под прямым контролем и хочется минимального вмешательства. По размерам tar.gz и бинарник после upx были эквивалентны. То есть сделать так можно, но, нет — это не проще.


Как уже писали, с upx будут накладные расходы по памяти.

Выше в комментариях показывал пример. 10 Кб накладных расходов.

Bittorent и пусть друг у друга качают
После того как коллега на работе сделал сервис на Java/Micronaut, который я ранее практически до того же функционала сделал на Go, я уточнил в какого размера докер образ у него оно собирается… ну и мой был 6Мб(FROM scratch), а у него 300Мб+. И вот после этого что-то еще жать в бинарике Go — даже в голову не приходило.
Но спасибо за идеи — попользую немного на своих поделках.
Зарегистрируйтесь на Хабре , чтобы оставить комментарий