Performance and security advantages of mix releases

Hello everyone!

I was discussing with a colleague at work today about the possible use cases that would require using a mix release and I would like to know if there are any gaps in my current understanding of when you should reach out to a release versus simply running the code with mix.

BTW, I already know we have an excellent topic in the official docs about releases here and many other topics in the forums as well, but I want to contextualize some things first so you can have a better understanding on why I’m asking about this now…

The way I’ve always seen it, the main advantage of releases has always been the fact that it’s self-contained. However, I don’t think I’ve seen many topics about other aspects, like configuration, performance, and security (just to name a few).

I’ve been coding in Elixir for quite some time now and for the times I used Phoenix in production I have always deployed it using releases (mostly for convenience), and I must say that I’ve never needed to tweak the VM configurations beyond the very basics. So in a way, I could say that I haven’t used release’s “full potential” yet (so to speak).

Performance-wise, my current understanding is that there are some out-of-the-box improvements because of code preloading and the custom flags that you can pass to the VM and that’s it.

I never managed to find the time to dive too deep into Elixir/Erlang internals, but I have the impression that sometimes people can be led to think (in a very strict way) of something like mix phx.server as “development mode only” and running it as a release as “production mode only” (mainly because mix is in fact, a development tool).

So, just to clarify: I’m asking because I want to be better equipped to answer this type of question in the future in a very objective way and I hope that the answers to this thread can shed some light on this particular portion of the subject - as we all know, developers can sometimes be very “dogmatic” about their ways so this would help destigmatize the subject a little bit. Cheers! :blush:

3 Likes

I’m curious about this too. I’ve seen some tutorials that recommend using mix. Although by “recommend” I mean they just say to use it with no explanation.

I recently pushed an app to AWS for the first time using releases (I usually use Fly). It’s an app that will see very little usage so I’m just building on the target server with mix release. I’m using systemd to run it and definitely appreciate the bin directory you get with releases (start/stop/etc). Having output automatically connected to standard io was also helpful as it JustWorks™ with systemd’s journal. I’m a bit of a ditz when it comes to ops-type stuff so it’s probably pretty easy with mix as well.

Anyway, ya, again very curious myself.

Pretty sure this thread is still relevant Always use Releases

8 Likes

Great post. I think the main issue with people using releases before was related to 2 critical things:

  1. Properly configuring things like distillery, before releases were officially created, was not that easy, it took some iterations for the library to get polished;
  2. The lack of runtime configuration made it even harder, I remember having some hacky distillery configuration that would read ENV variables at runtime, not easy to maintain and to configure.
4 Likes

Completely agree on both counts. With runtime.exs and built in mix release I think we’re in a far better spot today.

2 Likes

The EEF Security WG’s deployment hardening guidelines document has some things to say about the security benefits of releases.

6 Likes

Yes, it’s one of the main threads on the subject that we have here, but I think it mostly paints releases in the light of being a “convenient” way of deploying Elixir. Like I mentioned before, this also has always being my perception, but I’m looking for a more pragmatic discussion on the topics of configuration, performance, and security.

I do believe releases are good fit for the use cases we have outlined in the docs, but I also can see a more “dogmatic” view on the subject that could consider not using a release almost like an anti-pattern. Do you understand what I mean?

Thanks @voltone, this is also very helpful!

1 Like

In the end many things will be the same between using releases or not. There will always be the erlang VM (globally installed or in case of releases it also can be bundled), there will always be (a subset) of otp applications, there will always be the applications you depend on, there will always be your application(s). Unless you specifically work around that modules once compiles should result in the exact same bytecode being executed.

The parts where things differ are how things are started up / loaded, how many additional applications or pieces of code will run and potentially how local the parts needed to run are to themselfes on the filesystem.

Judging which option is ok or not depends on how much those differences are worth to people.

Most often I’d expect some (sub- or superset) of the following:

  • Precompiling saves resources on the app server in favor of doing it on a build server
  • Shipping only compiled data and no longer needing source files makes deployments faster
  • Bundling everything (including erts/otp) makes a release less dependant on preexisting things on an app server
  • Bundling just exactly everything lessens the overhead when running a release
  • Precompiling enforces a differenciation between config being applied to compiled code or config being provided at runtime and not compiled into changes of code
  • Start scripts show exactly in which order things are started up, which aids debugging
  • Releases come with helpful script for remote access, rpc without the overhead of needing all of Mix to run a mix task
  • While the prev. might be a downside this means there’s a clear differenciation what would be used on a production system vs on a development system

There are likely more. But I don’t think there’s any hard facts pushing this (way) beyond “conveniences”.

6 Likes

Thanks @LostKobrakai! I couldn’t have hoped for a better answer.

I wonder if we have other resources like the ones @voltone shared that covers more ground beyond said “conveniences” (even if not that concrete). I would be very interested in getting my hands on content like this.

I would suggest just checking out the generated files in the release directory and the docs https://www.erlang.org/doc/design_principles/release_structure to “demistify” them.

You’ve got a release resource file .rel that lists all the included applications+versions.
From that + the .app files :systools generates a boot script which is just a list of instructions for the Erlang runtime system.
Which code to load, applications to start.

mix release just builds on top of that and adds some convenient scripts to start/stop your release, handle runtime config and so on.

I see Elixir/Erlang releases mostly as a packaging convention, so i think you already used them to their full potential.

And you don’t need releases to change the VM config.
(elixir|iex) --erl "..." -S mix phx.server for example.

1 Like