Git Product home page Git Product logo

exrm's Introduction

Elixir Release Manager

Build Status

Thanks to @tylerflint for the original Makefile, rel.config, and runner script which inspired this project!

Usage

You can build a release with the release task:

  • mix release

This task constructs the complete release for you. The output is sent to rel/<project>. To see what flags you can pass to this task, use mix help release.

One really cool thing you can do is mix release --dev. This will symlink your application's code into the release, allowing you to make code changes, recompile with MIX_ENV=prod mix compile, and rerun your release with rel/<project>/bin/<project> console to see the changes. Being able to rapidly test and tweak your release like this goes a long way to making the release process less tedious!

  • mix release.clean [--implode]

Without args, this will clean up the release corresponding to the current project version.

With --implode, all releases, configuration, generated tools, etc., will be cleaned up, leaving your project directory the same as if exrm had never been run. This is a destructive operation, as you can't get your releases back unless they were source-controlled, so exrm will ask you for confirmation before proceeding with the cleanup.

NOTE: Umbrella projects work a little differently. Each sub-project is built into it's own release, but contains all of it's dependencies

Getting Started

This project's goal is to make releases with Elixir projects a breeze. It is composed of a mix task, and build files required to successfully take your Elixir project and perform a release build, and a simplified configuration mechanism which integrates with your current configuration and makes it easy for your operations group to configure the release once deployed. All you have to do to get started is the following:

Add exrm as a dependency to your project

  defp deps do
    [{:exrm, "~> 0.14.10"}]
  end

Fetch and Compile

  • mix deps.get
  • mix deps.compile

Perform a release

  • mix release

Configuration

There are two forms of configuration I will deal with here. One is configuration for the release process, the latter is handling application configuration for your release. The following custom release configuration is supported:

  • sys.config - This is the configuration file the release will use in production. I would use config/config.exs or config/myapp.conf instead of this, but it's there if you want it.
  • vm.args - This file contains line-separated arguments that the Erlang VM will use when booting up. Provide your own here and it will be used instead of the default one. Make sure you provide values for sname and cookie though, or you won't be able to connect to your release!
  • relx.config - This file is used to provide configuration to exrm's underyling relx dependency. The dependency will be going away in the future, but the configuration file will remain (though it may be renamed). See the documentation at relx's GitHub page for more information on what you can provide here. The default one should cover 99% of cases, but if you need to tweak values, you can provide your own relx configuration, by creating a file at rel/relx.config and setting the config values you care about. You do not need to provide the entire configuration, as your customizations will be merged with the defaults exrm uses.

I'm going to go in to more detail on how application configuration works later on, for now just know that when you run mix release for the first time, exrm will warn you that it couldn't find a yourapp.conf and yourapp.schema.exs file, and generates them for you based on your current configuration which is defined in config/config.exs. The .conf is where you will configure your app, and the .schema.exs is where you define the configuration available in the .conf.

Run your app! (my example is based on a simple ping server, see the appendix for more info)

> rel/test/bin/test console
Erlang/OTP 17 [erts-6.0] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Interactive Elixir (0.14.3) - press Ctrl+C to exit (type h() ENTER for help)
iex([email protected])1> :gen_server.call(:test, :ping)
:v1
iex([email protected])2>

See the next few sections for information on how to deploy, run, upgrade/downgrade, and remotely connect to your release!

Release Configuration

Elixir has support for providing configuration using Elixir terms in a config/config.exs file. While this is perfectly usable, it's not very simple for your operations group to work with, and generally contains no useful documentation on what each setting is for or what they do. To help make configuration much more easy and maintainable, exrm bundles a dependency called conform.

Conform relies primarily on two files: a yourapp.schema.exs file, and a yourapp.conf file. The .conf file is where you will configure your app, and the .schema.exs file is where you define what configuration is available in the .conf, and how it is translated to the final sys.config that your release loads up at runtime.

Conform itself has the best documentation on how to work with these files, and to see an example app which makes use of this, check out the exrm-test project.

Here's a quick rundown on how it works. You probably already have a config.exs file, and if you don't that's fine, it's not required. If you do have one already, you can compile your project and run mix conform.new to generate the conform schema from your current configuration. If you don't have one, check out the conform README on how to create one. Once you have the schema file in your config directory, you can work off the definitions generated from your current config, and/or start adding definitions for config settings you wish to add.

Once your schema is all set, you can generate the default .conf file for your app using mix conform.configure. This will output a .conf file to config/yourapp.conf. This will be bundled with your release, and located in $DEPLOY_DIR/releases/$RELEASE_VER/myapp.conf. Your ops group can then do all their configuration in production via that file.

If you are wondering how that .conf file is usable by the VM, it's very simple. When you run bin/test start, or any other command which boots your app, a conform escript is run which translates the .conf via the schema (also bundled with the release) to Elixir terms, that is then merged over the top of the sys.config which is also bundled with the release, and then saved over the top of the existing sys.config. Once the escript has finished executing, your app is booted using that sys.config file, and everything carries on like normal.

NOTE: Your config/config.exs file is still converted to the sys.config which is bundled with the release. If you wish to hide settings from your end users, put them in there, and remove the definitions for them from your schema file. The sys.config is merged with the configuration which is defined in the .conf, so your settings will still be applied, they just won't be exposed for end users.

Deployment

Now that you've generated your first release, it's time to deploy it! Let's walk through a simulated deployment to the /tmp directory on your machine, using the example app from the Appendix.

  1. mix release
  2. mkdir -p /tmp/test
  3. cp rel/test/test-0.0.1.tar.gz /tmp/
  4. cd /tmp/test
  5. tar -xf /tmp/test-0.0.1.tar.gz

Now to start your app:

bin/test start

You can test if your app is alive and running with bin/test ping.

If you want to connect a remote shell to your now running app:

bin/test remote_console

Ok, you should be staring at a standard iex prompt, but slightly different: iex(test@localhost)1>. The prompt shows us that we are currently connected to test@localhost, which is the value of name in our vm.args file. Feel free to ping the app using :gen_server.call(:test, :ping) to make sure it works.

At this point, you can't just abort from the prompt like usual and make the node shut down. This would be an obviously bad thing in a production environment. Instead, you can issue :init.stop from the iex prompt, and this will shut down the node. You will still be connected to the shell, but once you quit the shell, the node is gone.

If you want to execute a command against your running node without attaching a shell:

bin/test rpc erlang now

or

bin/test rpc calendar valid_date "{2014,3,14}."

Notice that the arguments required are in module, function, argument format. The argument parameter will be evaluated as an Erlang term, and applied to the module/function. Multiple args should be formatted as a list, i.e. [arg1, arg2, arg3]..

Upgrading Releases

So you've made some changes to your app, and you want to generate a new relase and perform a no-downtime upgrade. I'm here to tell you that this is going to be a breeze, so I hope you're ready (I'm using my test app as an example here again):

  1. mix release
  2. mkdir -p /tmp/test/releases/0.0.2
  3. cp rel/test/test-0.0.2.tar.gz /tmp/test/releases/0.0.2/test.tar.gz
  4. cd /tmp/test
  5. bin/test upgrade "0.0.2"

Annnnd we're done. Your app was upgraded in place with no downtime, and is now running your modified code. You can use bin/test remote_console to connect and test to be sure your changes worked as expected.

You can also provide your own .appup file, by writing one and placing it in rel/<app>.appup. This location is checked before generating a new release, and will be used instead of autogenerating an appup file for you.

Downgrading Releases

This is even easier! Using the example from before:

  1. cd /tmp/test
  2. bin/test downgrade "0.0.1"

All done!

Common Issues

I'm starting this list to begin collating the various caveats around building releases. As soon as I feel like I have a firm grasp of all the edge cases, I'll formalize this in a better format perhaps as a "Preparing for Release" document.

  • Ensure all dependencies for your application are defined in either the :applications or :included_applications block of your mix.exs file. This is how the build process knows that those dependencies need to be bundled in to the release. This includes dependencies of your dependencies, if they were not properly configured. For instance, if you depend on mongoex, and mongoex depends on erlang-mongodb, but mongoex doesn't have erlang-mongodb in it's applications list, your app will fail in it's release form, because erlang-mongodb won't be loaded.
  • If you are running into issues with your dependencies missing their dependencies, it's likely that the author did not put the dependencies in the :application block of their mix.exs. You may have to fork, or issue a pull request in order to resolve this issue. Alternatively, if you know what the dependency is, you can put it in your own mix.exs, and the release process will ensure that it is loaded with everything else.

If you run into problems, please create an issue, and I'll address ASAP.

Appendix

You can find the source code for the example application here, and an example umbrella application here. Everything mentioned here should work out of the box with those projects. If it does not, please file a bug!

exrm's People

Contributors

alco avatar asaaki avatar bitwalker avatar ericmj avatar jwarwick avatar markschmidt avatar smpallen99 avatar tsutsu avatar tylerflint avatar vishnevskiy avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.