jeremyjh
Releases of course are not a new thing at all, but I’ve only used them in one prior project that used distillery and edeliver for deployment to a VPS. At work we use Heroku and the buildpack and guides for that have always focused on mix deployment. Actually I’m contemplating writing a new buildpack that would use releases, and migrating to that. The other strategy available on Heroku is using Docker images, which would have the advantage of being more portable but still does not support features we really like such as PR apps.
Still, I do not think this should be done “just because”, and frankly, the benefits promoted in the releases documentation do not seem very compelling in a containerized world but I wanted to discuss further in the context of a containerized Phoenix app.
Let’s break them down.
You can do this in a mix project too:
MIX_ENV=prod ERL_FLAGS="-mode embedded" mix phx.server
As far as I know you can pass all VM options either via ERL_ZFLAGS or ERL_FLAGS.
I see the benefit in traditional server deployments but in the context of a dockerized application we achieve the same thing (as do traditional Heroku buildpack slugs) - at the end of the build you have a single artifact to deploy and manage. Yes your source code is included and that may be a factor for ISV doing on-premise deployment but this is not relevant to me or my projects. In any case the BEAM code is not obfuscated and can be decompiled to Erlang quite easily.
I may be missing something of significance here because I do not use umbrella projects but I think I can supply different configuration to each application in an Umbrella project. Maybe someone can provide an example that sheds some light on this?
Again this is very relevant in traditional server deployments, but in containers it works fine to just use mix commands (and they are the same commands you use in dev!); the container itself is the entry point that will be started/stopped/restarted.
Trending in Discussions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming











Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
benwilson512
Does this actually work? This just crashes for me. It was my understanding that embedded mode requires that there be a list of the beam files the application actually needs so that it can eager load them. Part of what a release does is compile this list.
Sort of. We build and run in containers. The build container is enormous since it requires that we have a working Erlang / Elixir, plus all the dependencies you need to build those. The run container is an incredibly minimal Linux image with just the release on it. This difference is even more stark for applications that contain various NIFs and need build tools for that (Rust).
If you use releases, you have a much smaller image overall, and you’re basically guaranteed that the only layer to change per version is just the release itself.
Really though it’s a cost benefit analysis question. If you don’t use releases you still need to manually re-implement (without mistakes!) embedded mode, setting up a remsh, and optimize your docker images for building as well as execution, etc. You can get rid of all that headache by just calling
mix release.jeremyjh
Yes it seems to work fine locally for me in MIX_ENV=prod mode, but I admit I don’t use it in production. It does indeed crash in MIX_ENV=dev. Perhaps its not actually working in embedded mode when there is no manifest? If that’s the case its definitely an advantage to using releases, though I’ve never observed latency issues on restarts I haven’t tried to measure them either.
This is a really good point and is very compelling.
sasajuric
At Aircloak, we have containerized deployments, and we still use OTP releases. Besides what @benwilson512 said, there are some other benefits, such as getting a remote iex shell, or the ability to execute custom commands inside the running system. Polite system termination is also supported out of the box.
cnck1387
That’s what I planned to do when I deploy my first Phoenix app but how do you deal with testing that released image? If it’s a super minimal image with nothing but the release, that means you can’t run any test suites against it right?
In other words, if you build that release image on a CI server (based off the bulky dev image having its tests pass), aren’t you effectively shipping an untested release to production?
LostKobrakai
Tests are run in
MIX_ENV=test, while releases build/mix runs inMIX_ENV=prodso you’re essentially never testing the production build to begin with. There will always be some differences between what you ship to production vs what you run tests against (besides maybe for external integration tests).benwilson512
As @LostKobrakai notes, your Elixir test suite is already a different compilation artifact from the production beam files.
This isn’t actually a huge concern though either for
MIX_ENV=prod mix phx.serveror releases. The only thing the test suite can validate is your application logic. It can’t validate that your production config is setup such that your container can actually start. This is what liveliness and readiness checks are for. Your deployment process should be such that no traffic is routed to the new container until it passes both liveliness (your application is running) as well as readiness checks (it has finished the boot process and can handle load) anyway. This is the final kind of validation, and it works perfectly well regardless of how you start your app.cnck1387
Yeah that makes sense. Fire off a health check to a route to ensure it reports a 200 (the app booted and is ready). That’s something I do already in other tech stacks, but Elixir is slightly different in the sense that with a Flask or Rails app, the exact image I built and pushed to Docker Hub in CI is what ends up running in production which in turn is also the exact image I was running locally too.
benwilson512
ehhhh not as much as you might thing. Rails, for example, metaprograms so much based on configuration that you aren’t really running the same thing. A classic example would be Active Record, where whole methods are metaprogrammed in by reflecting on the database tables. You’re running the same code sure, but when it comes to the actual byte code being run it’s all over the map.
If the “use the same image” is a hard requirement by the way, there’s nothing stopping you from doing
mix releasein the same image you domix testin. All this really gives you though in all of these languages is the guarantee that you’re using the same code, but this is somethinggitgives you, you don’t needdockerto give it to you.The release-with-two-images approach has the same code oriented guarantees. You use
gitto make sure you’re running the same code, but that code, just like flask / rails, is parameterized. You insert one set of parameters and do tests, you insert another set of parameters, get a new artifact, and run it in production. It just so happens that in the case of Rails there’s a different ratio of how much parameterization happens at runtime vs compile time.I think the main point I’m trying to make is that
mix testandrspecare not tools for testing production artifacts, and just that your production artifact is on the same docker image as where you ranmix testdoesn’t change that. Validation in production looks more like staging environments, monitoring, and status checks. For example we do run identical images in both staging and production for that purpose precisely.keathley
I worked on a Java system where the readiness checks were the integration test suite. Once integration tests had passed it was safe to add to the load balancer. This strategy also had the benefit of warming up the JVMs. That might be overkill for a lot of people but these ideas don’t need to be mutually exclusive.
benwilson512
Fair enough, and I think that’s a great idea. Those kinds of tests though are not the same kind of test you have with
mix test.