GitHub - burrito-elixir/burrito: Wrap your application in a BEAM Burrito!
source link: https://github.com/burrito-elixir/burrito
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Burrito
Cross-Platform Elixir Deployments
What Is It?
Background
Burrito is our answer to the problem of distributing Elixir CLI applications across varied environments, where we cannot guarantee that the Erlang runtime is installed, and where we lack the permissions to install it ourselves. In particular, we have CLI tooling that must be deployed on-premise, by consultants, into customer environments that may be running MacOS, Linux, or Windows.
Furthermore, these tools depend on NIFs that we need to cross-compile for any of the environments that we support, from one common build server, running in our CI environment.
We were heavily inspired by Bakeware, which lays a lot of the ground work for our approach. Ultimately we implemented and expanded upon many of Bakeware's ideas using. Zig.
Feature Overview
- Builds a self-extracting archive for a Mix project, targeting Windows, MacOS, and Linux, containing:
- Your compiled BEAM code
- The required ERTS for your project
- Compilation artifacts for any elixir-make based NIFs used by the project
- Provides a "plugin" interface for injecting Zig code into your application's boot sequence
- We use this to perform automatic updates and licensing checks (see
lib/versions/release_file.ex
for details)
- We use this to perform automatic updates and licensing checks (see
- Automatically uninstalls old versions of the payload if a new version is run.
Technical Component Overview
Burrito is composed of a few different components:
- Mix Release Module - A module that is executed as a Mix release step. This module takes care of packing up the files, downloading and copying in different ERTS runtimes, and launching the Zig Archiver and Wrapper.
- Zig Archiver - A small Zig library that packs up an entire directory into a tar-like blob. This is known as the "payload" -- which will contain all the compiled BEAM code for your release, and the ERTS for the target platform. This is Gzip compressed and then embedded directly into the wrapper program.
- Zig Wrapper - This is portable cross-platform Zig code that wraps around the payload generated during the Mix release process.
Burrito Produced Binary
┌────────────────────────────────┐
│ │
│ Zig Wrapper Binary │ <---- Compiled from `wrapper.zig`
│ │
├────────────────────────────────┤
│ Payload Archive │
│ ┌────────────────────────────┐ │
│ │ │ │
│ │ ERTS Native Binaries │ <------ If cross-compiling, this is downloaded from a build server
│ │ │ │
│ └────────────────────────────┘ │
│ │ <---- This bottom payload portion is generated by `archiver.zig`
│ ┌────────────────────────────┐ │
│ │ │ │
│ │ Application BEAM Code │ │
│ │ │ │
│ └────────────────────────────┘ │
│ │
└────────────────────────────────┘
End To End Overview
- You build a Burrito wrapped binary of your application and send it to an end-user
- The end-user launches your binary like any other native application on their system
- In the background (first-run only) the payload is extracted into a well defined location on the system. (AppData, Application Support, etc.)
- The wrapper executes the Erlang runtime in the background, and transparently launches your application within the same process
- Subsequent runs of the same version of that application will use the previously extracted payload
Quick Start
Disclaimer
Burrito was built with our specific use case in mind, and while we've found success with deploying applications packaged using Burrito to a number of production environments, the approach we're taking is still experimental.
That being said, we're excited by our early use of the tooling, and are eager to accept community contributions that improve the reliability of Burrito, or that add support for additional platforms.
Preparation and Requirements
NOTE: Due to current limitations of Zig, some platforms are less suited as build machines than others: we've found the most success building from Linux and MacOS. The matrix below outlines which build targets are currently supported by each host.
Target Host Host Host Host
Windows x64 Linux MacOS (x86_64) MacOS (Apple Silicon)** Windows x64 Linux MacOS (x86_64) * MacOS (Apple Silicon)**
* NIFs implemented using elixir-make
cannot be cross-compiled from Linux to MacOS, pending a proposed linker change in Zig
** It's possible that Rosetta can execute the x86_64 MacOS binaries, however we do not have access to an Apple Silicon machine to verify this. Automated testing of Apple silicon builds is blocked on support for Apple Silicon in Github Actions.
You must have the following installed and in your PATH:
- Zig (master/nightly - we do not support 0.8.0) --
zig
- Gzip --
gzip
- 7z --
7z
- GNU Patch --
patch
Mix Project Setup
- Add
burrito
to your list of dependencies:
defp deps() do [{:burrito, github: "burrito-elixir/burrito"}] end
- Create a
releases
function in yourmix.exs
, add and configure the following for your project:
def releases do [ example_cli_app: [ steps: [:assemble, &Burrito.wrap/1], burrito: [ targets: [:darwin, :win64, :linux] ] ] ] end
(See the Mix Release Config Options for additional options)
- To build a release for the platforms defined in your
mix.exs
file:MIX_ENV=prod mix release
- You can also override the target platforms using the
BURRITO_TARGET
environment variable
- To build a release for Windows:
MIX_ENV=prod BURRITO_TARGET=win64 mix release
- To build a release for MacOS:
MIX_ENV=prod BURRITO_TARGET=darwin mix release
- To build a release for Linux:
MIX_ENV=prod BURRITO_TARGET=linux mix release
In order to speed up iteration times during development, if the Mix environment is not set to prod
, the binary will always extract its payload, even if that version of the application has already been unpacked on the target machine.
Mix Release Config Options
targets
- A list of atoms, the targets you want to build for (:darwin
,:win64
,:linux
) whenever you run amix release
command -- if not defined, defaults to native host platform only.debug
- Boolean, will produce a debug build if set to true. (Default:false
)no_clean
- Boolean, will not clean up after building if set to true. (Default:false
)plugin
- String, a path to a Zig file that contains a functionburrito_plugin_entry()
which will be called before unpacking the payload at runtime. See the example application for details.
Build-Time Environment Variables
BURRITO_TARGET
- Override the list of targets provided in your release configuration. (ex:BURRITO_TARGET=win64
,BURRITO_TARGET=linux,darwin
)
Application Entry Point
For Burrito to work properly you must define a :mod
in your project's Mix config:
def application do [ mod: {MyEntryModule, []} ] end
This module must implement the callbacks defined by the Application
module, as stated in the Mix documentation:
defmodule MyEntryModule do def start(_, _) do # Returning `{:ok, pid}` will prevent the application from halting. # Use System.halt(exit_code) to terminate the VM when required end end
If you wish you retrieve the argv passed to your program use this snippet:
args = :init.get_plain_arguments() |> Enum.map(&to_string/1)
Maintenance Commands
Binaries built by Burrito include a built-in set of commands for performing maintenance operations against the included application:
./my-binary maintenance uninstall
- Will prompt to uninstall the unpacked payload on the host machine.
Known Limitations and Issues
Runtime Requirements
Minimizing the runtime dependencies of the package binaries is an explicit design goal, and the requirements for each platform are as follows:
Windows
- MSVC Runtime for the Erlang version you are shipping
- Windows 10 Build 1511 or later (for ANSI color support)
Linux
- Any distribution with glibc
- libncurses-5
MacOS
- No runtime dependencies, however a security exemption must be set in MacOS Gatekeeper unless the binary undergoes codesigning
Libc Support
For Linux builds, we currently only produce glibc linked binaries. We have plans to add support for musl-libc in the future!
Contributing
Welcome!
We are happy to review and accept pull requests to improve Burrito, and ask that you follow the established code formatting present in the repo!
Everything in this repo is licensed under The MIT License, see LICENSE
for the full license text.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK