{"id":9051,"date":"2019-05-29T10:26:43","date_gmt":"2019-05-29T13:26:43","guid":{"rendered":"http:\/\/blog.plataformatec.com.br\/?p=9051"},"modified":"2019-11-14T11:49:55","modified_gmt":"2019-11-14T13:49:55","slug":"updating-hex-pm-to-use-elixir-releases","status":"publish","type":"post","link":"http:\/\/blog.plataformatec.com.br\/2019\/05\/updating-hex-pm-to-use-elixir-releases\/","title":{"rendered":"Updating Hex.pm to use Elixir releases"},"content":{"rendered":"
Elixir v1.9 will ship with releases support<\/a> and in this blog post we want to show how we have used this exciting new feature on the Hex.pm project.<\/p>\n (Update: This section is no longer relevant since v1.9 is already out!)<\/p>\n Since Elixir v1.9 is not out yet, we need to use the development version. Locally, my preferred approach is to use the Elixir plugin<\/a> for the asdf-vm<\/a> version manager.<\/p>\n Here’s a couple of ways we may use asdf to install recent development versions:<\/p>\n Per “Deployment” section of A release is built on a host, a machine which contains Erlang, Elixir, and any other dependencies needed to compile your application. A release is then deployed to a target, potentially the same machine as the host, but usually separate, and often there are many targets (either multiple instances, or the release is deployed to heterogeneous environments).<\/p><\/blockquote>\n We deploy Hex.pm using Docker containers and we needed to change our Dockerfile<\/a>. If you’re deploying using buildpacks (e.g. to Heroku or Gigalixir), it should be as simple as setting Elixir 1.9 ships with two new Mix tasks to work with releases:<\/p>\n The sample files generated by On Hex.pm, previously we were building releases using Distillery<\/a> and to work with Elixir releases we needed to make a few small tweaks. Here are the main ones:<\/p>\n See the “Replace Distillery with Elixir releases” PR on Hex.pm repo<\/a> for more details.<\/p>\n We now have a few files that deal with configuring our app\/release, let’s take a step back and see what they can do:<\/p>\n See “Application configuration”<\/a> and “vm.args and env.sh (env.bat)”<\/a> sections for more information.<\/p>\n Finally, we use the The generated release script ( In our Hex.pm deployment we have used two of these commands for now:<\/p>\n In this blog post we’ve walked through using Elixir releases on an existing project, Hex.pm. We’ve installed the development version of Elixir, configured the release, and adjusted our deployment setup to use it. Hex.pm was previously using Distillery, and with minimal changes we were able to update it to use built-in releases support.<\/p>\n Overall, I\u2019m very happy about this change. We\u2019ve ended up with about the same amount of configuration code, but I think it\u2019s a little bit better structured and more obvious.<\/p>\n I especially like new conventions around configuration. Where previously we used workarounds like Building the release is now faster too, on my machine ~2.5s now vs ~5.5s before. Granted, it\u2019s probably the least concern but it\u2019s a nice cherry on top nonetheless.<\/p>\n As of this writing, Hex.pm is already deployed using Elixir releases. Now your turn – try out releases on your project! (And if something goes wrong, submit an issue<\/a>!)<\/p>\n","protected":false},"excerpt":{"rendered":" Elixir v1.9 will ship with releases support and in this blog post we want to show how we have used this exciting new feature on the Hex.pm project. Installing Elixir master (Update: This section is no longer relevant since v1.9 is already out!) Since Elixir v1.9 is not out yet, we need to use the … \u00bb<\/a><\/p>\n","protected":false},"author":70,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[1],"tags":[143],"aioseo_notices":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/9051"}],"collection":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/users\/70"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/comments?post=9051"}],"version-history":[{"count":22,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/9051\/revisions"}],"predecessor-version":[{"id":9547,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/9051\/revisions\/9547"}],"wp:attachment":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/media?parent=9051"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/categories?post=9051"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/tags?post=9051"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}Installing Elixir master<\/h2>\n
# install latest master\n$ asdf install elixir master\n$ asdf local elixir master\n\n# or, install particular revision:\n$ asdf install elixir ref:b8b7e5a\n$ asdf local elixir ref:b8b7e5a\n<\/code><\/pre>\n
mix release<\/code><\/a> documentation:<\/p>\n
elixir_version=master<\/code> in your
elixir_buildpack.config<\/code>.<\/p>\n
Setting up releases<\/h2>\n
\n
mix release.init<\/code><\/a> – generates sample files for releases<\/li>\n
mix release<\/code><\/a> – builds the release<\/li>\n<\/ul>\n
mix release.init<\/code> are optional, if they are not present in your project then the release will be built with default options.<\/p>\n
\n
:releases<\/code> section to
mix.exs<\/code> – this is an optional step but since we don’t deploy on Windows, we only need to generate executable files for UNIX-like systems<\/li>\n
rel\/vm.args<\/code> with
rel\/vm.args.eex<\/code><\/li>\n
rel\/hooks\/pre_configure<\/code> with
rel\/env.sh.eex<\/code><\/li>\n
config\/releases.exs<\/code> for runtime configuration of the release<\/li>\n
mix deps.unlock<\/code> it!)<\/li>\n<\/ul>\n
\n
config\/prod.exs<\/code><\/a> – provides build-time application configuration<\/li>\n
config\/releases.exs<\/code><\/a> – provides runtime application configuration. We’re using the new
Config<\/code><\/a> module and the
System.fetch_env!\/1<\/code><\/a> function, also introduced in Elixir v1.9.0, to conveniently return the environment variable if set, or raise an error.<\/li>\n
rel\/vm.args.eex<\/code><\/a> – provides a static mechanism for configuring the Erlang Virtual Machine and other runtime flags. For now, we use the defaults but if down the line we’d tune the VM, we’d set the options here.<\/li>\n
rel\/env.sh.eex<\/code><\/a> – provides a dynamic mechanism for setting up the VM, runtime flags, and environment variables.<\/li>\n<\/ul>\n
RELEASE_NODE<\/code> and
RELEASE_COOKIE<\/code> variables are used by the release script, see “Environment variables”<\/a> section in the documentation for all recognized variables. The
POD_A_RECORD<\/code> variable we have there is specific to our deployment environment on Hex.pm, we deploy it to Google Kubernetes Engine.<\/p>\n
mix release<\/code> task to actually assemble the release:<\/p>\n
$ mix release\n* assembling hexpm-0.0.1 on MIX_ENV=dev\n* using config\/releases.exs to configure the release at runtime\n* creating _build\/dev\/rel\/hexpm\/releases\/0.0.1\/vm.args\n* creating _build\/dev\/rel\/hexpm\/releases\/0.0.1\/env.sh\n\nRelease created at _build\/dev\/rel\/hexpm!\n\n# To start your system\n_build\/dev\/rel\/hexpm\/bin\/hexpm start\n\nOnce the release is running:\n\n# To connect to it remotely\n_build\/dev\/rel\/hexpm\/bin\/hexpm remote\n\n# To stop it gracefully (you may also send SIGINT\/SIGTERM)\n_build\/dev\/rel\/hexpm\/bin\/hexpm stop\n\nTo list all commands:\n\n_build\/dev\/rel\/hexpm\/bin\/hexpm\n<\/code><\/pre>\n
Running the release<\/h2>\n
bin\/hexpm<\/code>) has many commands:<\/p>\n
$ _build\/dev\/rel\/hexpm\/bin\/hexpm\nUsage: hexpm COMMAND [ARGS]\n\nThe known commands are:\n\nstart Starts the system\nstart_iex Starts the system with IEx attached\ndaemon Starts the system as a daemon\ndaemon_iex Starts the system as a daemon with IEx attached\neval \"EXPR\" Executes the given expression on a new, non-booted system\nrpc \"EXPR\" Executes the given expression remotely on the running system\nremote Connects to the running system via a remote shell\nrestart Restarts the running system via a remote command\nstop Stops the running system via a remote command\npid Prints the OS PID of the running system via a remote command\nversion Prints the release name and version to be booted\n<\/code><\/pre>\n
\n
bin\/hexpm start<\/code> – we use it as the start command to be run in our Docker container<\/li>\n
bin\/hexpm eval<\/code> – we use it to run DB migrations and other maintenance scripts. For migrations, the command is:
bin\/hexpm eval 'Hexpm.ReleaseTasks.migrate()'<\/code>.<\/li>\n<\/ul>\n
Summary<\/h2>\n
config :app, {:system, \"ENV_VAR\"}<\/code> and
\"${ENV_VAR}\"<\/code> (and
REPLACE_OS_VARS=true<\/code>), we now have a clear distinction between build-time and runtime configuration.
mix release<\/code><\/a> documentation does a really good job of explaining configuration aspects in particular but also the whole release process in general.<\/p>\n