Crystal Programming. Введение на основе проекта в создание эффективных, безопасных и читаемых веб-приложений и приложений CLI - Джордж Дитрих
Шрифт:
Интервал:
Закладка:
Прежде чем создавать выпуск, вам следует убедиться, что вы обновили все ссылки на версию в исходных файлах, например, в shard.yml или любых константах VERSION.
Если проект представляет собой библиотеку, то это все, что нужно. Другие приложения смогут использовать новую версию, shards install или shards update, в зависимости от того, является ли это новой или существующей зависимостью. Если проект представляет собой приложение, необходимо выполнить еще несколько шагов, чтобы пользователи могли загружать готовые двоичные файлы для его использования.
Создание производственных двоичных файлов
Хотя это было предсказано в Главе 6 «Параллелизм», в основном мы собирали двоичные файлы с помощью команды crystal build file.cr и ее эквивалента. Эти команды подходят для разработки, но они не создают полностью оптимизированный двоичный файл для производственной рабочей нагрузки/среды, подходящий для распространения.
Чтобы создать двоичный файл выпуска, нам нужно передать флаг --release. Это сообщит бэкэнду LLVM, что он должен применить к коду все возможные оптимизации. Другой вариант, который мы можем передать, — это --no-debug. Это заставит компилятор Crystal не включать символы отладки, в результате чего двоичный файл будет меньшего размера. Остальные символы можно удалить с помощью команды strip. Дополнительную информацию см. на https://man7.org/linux/man-pages/man1/strip.1.html.
После сборки с использованием этих двух вариантов вы получите меньший по размеру и более производительный двоичный файл, который будет пригоден для тестирования или использования в производственной среде. Однако он не будет переносимым, а это означает, что для него по-прежнему потребуется, чтобы у пользователя были установлены все среды выполнения Crystal и системные зависимости для конкретных приложений. Чтобы создать более портативный двоичный файл, нам нужно будет статически связать его.
Статическое связывание так же просто, как добавление параметра --static, но с одной особенностью. Загвоздка в том, что не все зависимости хорошо работают со статическим связыванием, причем главным нарушителем является libc, учитывая, что от него зависит Crystal. Вместо этого можно использовать musl-libc, который имеет лучшую поддержку статического связывания. Хотя это и не единственный способ, рекомендуемый способ создания статического двоичного файла — использовать Alpine Linux. Предоставляются официальные образы Crystal Docker на основе Alpine, которые можно использовать для упрощения этого процесса.
Для этого требуется, чтобы собственные зависимости приложения имели статические версии, доступные в базовом образе. Флаг --static также не гарантирует на 100%, что полученный двоичный файл будет полностью статически связан. В некоторых случаях статическое связывание может быть менее идеальным, чем динамическое связывание.
Например, если в зависимости обнаружена и исправлена критическая ошибка, двоичный файл необходимо будет перекомпилировать/выпустить с использованием новой версии этого пакета. Если бы он был динамически связан, пользователь мог бы просто обновить пакет, и он начал бы использовать новую версию.
Статическая компоновка также увеличивает размер двоичного файла, поскольку он должен включать код всех его зависимостей. В конце концов, стоило бы подумать, какой подход вам следует использовать в зависимости от требований распространяемой вами программы.
Пример команды для этого будет выглядеть так:
docker run --rm -it -v $PWD:/workspace -w /workspace crystallang/crystal:latest-alpine crystal build app.cr --static --release --no-debug
При этом контейнер запускается с использованием последнего образа Crystal Alpine, монтируется в него текущий каталог, создается статический рабочий двоичный файл, а затем происходит выход и удаление контейнера.
Мы можем обеспечить статическую компоновку полученного двоичного файла с помощью команды ldd, доступной в Linux. Пользователи macOS могут использовать otool -L. Передача этой команды с именем нашего двоичного файла вернет все общие объекты, которые он использует, или статически связанные, если их нет. Эту команду можно использовать для проверки новых двоичных файлов, чтобы предотвратить любые неожиданности в дальнейшем, когда вы запустите их в другой среде.
Теперь, когда у нас есть портативный, готовый к использованию двоичный файл, нам нужен способ его распространения, чтобы пользователи могли легко его установить и использовать. Однако если ваше приложение предназначено для внутреннего использования и его не нужно распространять среди конечных пользователей, все, что вам нужно сделать на этом этапе, — это развернуть двоичный файл и запустить его. Существует множество способов сделать это, в зависимости от вашего варианта использования, но на высоком уровне все сводится к копированию/перемещению двоичного файла туда, где он должен находиться, и его запуску.
Распространение вашего бинарного файла
Простейшей формой распространения было бы добавление двоичного файла, который мы создали в предыдущем разделе, к ресурсам выпуска. Это позволит любому загрузить и запустить его, при условии, что для его комбинации ОС/архитектуры существует двоичный файл. Бинарный файл, который мы создали в предыдущем разделе, будет работать на любом компьютере, использующем ту же базовую ОС и архитектуру, на которой он был скомпилирован — в данном случае x86_64 Linux. Для других архитектур ЦП/ОС, таких как macOS и Windows, потребуются специальные двоичные файлы.
Через Docker
Другой распространенный способ распространения двоичного файла — включение его в образ Docker, который затем можно использовать напрямую. Портативность Crystal упрощает создание таких изображений. Мы также можем использовать многоэтапные сборки для создания двоичного файла в образе, содержащем все необходимые зависимости, а затем извлечь его в более минимальный образ для распространения. Результирующий Dockerfile для этого процесса может выглядеть так:
FROM crystallang/crystal:latest-alpine as builder
WORKDIR /app
COPY ./shard.yml ./shard.lock ./
RUN shards install –production
COPY . ./
RUN shards build --static --no-debug --release –production
FROM alpine:latest
WORKDIR /
COPY --from=builder /app/bin/greeter .
ENTRYPOINT ["/greeter"]
Во-первых, мы должны использовать базовый образ Crystal Alpine в качестве основы с псевдонимом builder (подробнее об этом позже). Затем мы должны установить наш WORKDIR, который представляет, на чем будут основываться будущие команды каталога. Далее нам необходимо скопировать shard.yml и shard.lock-файлы для установки любых осколков, не зависящих от разработки. Мы делаем это как отдельные шаги, чтобы они рассматривались как разные слои изображения. Это повышает производительность, поскольку эти шаги будут повторяться только в том случае, если что-то изменится в одном из этих файлов, например, при добавлении или редактировании зависимости.
Наконец, в качестве последней команды на этом этапе сборки мы создаем статический двоичный файл выпуска, который в конечном итоге будет создан в /app/bin, поскольку это расположение вывода по умолчанию. Теперь, когда этот шаг завершен, мы можем перейти ко