I feel like I don’t have enough information about ERTS. Where can I find some well-explained docs about why/when I need it when deploying elixir/phoenix app without docker.
My questions are:
When can I run code without ERTS?
How to deploy/hot upgrade without ERTS - edeliver or smth easier?
How can I compile cross-compiled ERTS? I heard there is something like that.
Basically, I feel I’ve missed some chapter about ERTS/deployment and I would like to fill in the gaps.
I just released an email course on that subject http://bit.ly/elixir-release-ecourse
You have to have ERTS to run code. Basically ERTS is the Erlang VM. However if the machine you are going to send your release to already has an Erlang run time system on it, you do not have to include ERTS in your release archive.
Note, the ERTS must match the architecture of the remote machine. You can’t build your release on a Mac, ask that the ERTS (from the Mac) be included in the release, then move that release to a Linux machine and expect it to run properly. The ERTS included in the release has to match that of the destination machine. Which leads to your third question…
(Skipping your second question because I don’t know)
I can’t speak to cross-compiling ERTS itself, but when I needed to deploy to a different runtime architecture than my dev machine, I used Docker.
I developed and debugged my code on a Mac, but needed to deploy it to a machine running CentOS 6. I build a CentOS docker image that included all the tools to build a release (Erlang/OTP, Elixir, Mix, etc) and ran the final release build in a container based on that image. That way when my release tool (Distillery) was bundling in ERTS, it bundled the CentOS ERTS instead of the Mac OS X one.
Thanks for help. In that case, why not install ERTS on the server and just compile without ERTS?
Because it gives you control over the exact version of the ERTS available. with an embedded ERTS you do not need to figure out which packages to install and to figure out if their versions are compatible with your code.
also it means that when you go to deploy there are fewer steps. Just push the release, untar and go. Also you can go grab an old release if you need to for some reason and it will have the correct version of ERTS and everything else
I installed Erlang in Debian/Ubuntu on my server from the official Erlang repository. However, whenever there’s any kind of update to Erlang from this repository, the next time I deploy a release I have to install the new version of Erlang on my workstation (installed via asdf as I want to be able to run different versions there) before building a release so that the version matches exactly. Otherwise the release won’t run.
Next time I set up a new server I’ll simply have the ERTS included in each release to alleviate this potential mismatch. I currently pin Erlang on the server between updates, but I’d rather be in control of the version running in production in a simple fashion via asdf.
Hmm, but if you need to compile the code on same OS, you still probably need to install Erlang on some server? So you are probably gonna use some version manager like asdf. In that instance, why not just use version manager on the server + deploy without ERTS?
Why? You could build the deploy artifacts on the team leads (or another dedicated team members) local dev machine. It has the ERTS installed anyway, because its a requirement for development…
Why? I rarely use it… Most of the time I’m just using my systems erlang and elixir.
asdf is only used if I have very strict requirements.
Because that’s much harder than it sounds…
ERTS - the Erlang runtime system is just like the Java VM. Although a Java class file is cross platform, the JVM isn’t. Likewise, an Erlang/Elixir BEAM file is cross platform but the ERTS isn’t.
- The closes you can get to this is to embed the runtime into your code. However this is not well supported and rarely used.
Usually we pair the runtime and compiled code into a Release. Unlike a Java war file, a Release includes the specific runtime making it easier to deploy to the target hardware. Because it contains a specific runtime its a bit more complicated cross-compiling.
- If you aren’t upgrading the ERTS and already have an ERTS on the target hardware you can create a Upgrade Release. I’ve only experience this with Erlang and not too sure the steps for Elixir.
Important side-note is that (if I recall correctly), you have to include the ERTS in your binary if you want to do hot-code-reloading.
As I understand it, not having tried it, you don’t have to compile Erlang/Elixir code on the same OS, but you do need to use the ERTS that is appropriate to the runtime environment. So long as your application doesn’t contain native code (e.g. a NIF) then you should be able to compile your code on one machine, package it up without ERTS, then deploy it to another machine that already has the correct ERTS installed. You will probably want to match up Elixir and Erlang/OTP versions but the BEAM byte code should be the same.
Correct being the important keyword here: Erlang releases and OTP versions
I haven’t tested this, because we chose to include ERTS from when we first set up distillery, but I don’t think it’s a requirement to hot reload (upgrade release) of your application code. However, it is a requirement if you want to hot reload new ERTS versions.
To be sure, I looked it up:
From the Distillery Documentation on upgrades and downgrades:
It is not possible to use hot upgrades and
include_erts: false in conjunction with one another. This is due to how
release_handler manages information about releases as they are unpacked and installed. ERTS must be packaged in the release in order for hot upgrades/downgrades to properly work.
Thank you for clarifying it. I must now mutate a concept in my memory
I went one step further and verified that release_handler is an OTP module, so this same limitation would apply to any Erlang based release tooling and not be specific to Distillery.