Deli

Provides a deploy task for Elixir applications, using a couple of edelivertasks under the hood.

Releases are built using distillery, locally, through docker.

Git tags are autogenerated, and deli will ask to bump app version, if there are new commits since last version bump. You can switch to a custom versioning strategy if that’s not good.

Configuration

Add deli to your deps:

def deps do
  [
    # ...
    {:deli, "~> 0.1.28", runtime: false}
  ]
end

You don’t need to add edeliver or distillery, as they’re already included.

No need for edeliver config (for basic scenario). You will need to setup distillery.

Then add some configuration in your config/config.exs:

config :deli,
  hosts: [
    staging: [
      "staging-01.your_app.com",
      "staging-02.your_app.com"
    ],
    prod: [
      "prod-01.your_app.com",
      "prod-02.your_app.com",
      "prod-03.your_app.com",
      "prod-04.your_app.com",
      "prod-05.your_app.com",
      "prod-06.your_app.com"
    ]
  ]

See lib/deli/config.ex for all configuration options (and their defaults).

Deploy

$ mix deli

The task above does full cycle deploy:

It will assume staging environment by default.

To target prod environment, do:

$ mix deli -t prod

It will ask for confirmation after release is built, before deploy. If you don’t want that extra step, pass -y when calling this task.

Other tasks provided by deli

# Starts all hosts for target prod
$ mix deli.start -t prod

# Stops all hosts for target prod, without confirmation
$ mix deli.stop -t prod -y

# Restarts all hosts for target staging that match ~r/02/
$ mix deli.restart -h 02

# Cleans autogenerated config files
$ mix deli.clean

# Does only docker release phase
$ mix deli.release

# Does only deploy/restart/check (release should be available)
$ mix deli.deploy

# Checks status
$ mix deli.status -t prod

# Checks version
$ mix deli.version

# Opens a IEx remote console from local machine
$ eval $(mix deli.shell)

# Opens a local observer connected to remote node
$ eval $(mix deli.shell -o)

# When there are more than one host for target,
# eval will just work if you filter it to just return one host
$ eval $(mix deli.shell -h 01)

# If you don't know yet how to filter, use it without eval,
# and it will do the port forwarding and print out the command to connect,
# but before, it lets you choose the host:
$ mix deli.shell
[0] staging-01.myapp.com
[1] staging-02.myapp.com
Choose a number: 0
iex --name local@127.0.0.1 --cookie awesome_cookie --remsh myapp@127.0.0.1

Run mix tasks (locally) in remote nodes

By using Deli.Command, you can have this:

# runs locally
$ mix my_app.xyz --arg_example=1

# runs in all prod hosts
$ mix my_app.xyz --arg_example=1 -t prod

# runs in prod hosts matching ~r/03/
$ mix my_app.xyz --arg_example=1 -t prod -h 03

Configuring controller

By default, the release binary (/opt/APP/bin/APP) is used to control the app (start, stop, restart, status, ping), but systemd’s systemctl can be configured as the app controller:

config :deli, controller: Deli.Controller.Systemctl

You can configure any module that implements the Deli.Controller behaviour. Beware during v0.x.x this contract is not stable.

Edeliver and Distillery

Releases should be configured in your application with distillery.

You don’t need to think about edeliver with deli (unless you want to). Deli generates any config needed for edeliver, and adds them to your gitignore by default. If you want to maintain a custom version, just remove from .gitignore, and also remove the comment line saying autogenerated by deli. Edeliver mix commands are available to you. But if you use the systemctl controller, avoid using edeliver admin commands (start / stop / …)

At the moment, this package exists for reusing among similarly configured apps. It might not be flexible enough for your needs yet.

Potential future work