bryanhuntesl

bryanhuntesl

Bundling scripts (mix ecto.setup etc) with new elixir releases

I’ve done this a lot when using distillery - for example, bundling a script which will execute an ecto.migration task.

Here’s an example of with this kind of configuration.

The reason this is important is for kubernetes. Kubernetes has various lifecycle hooks such as healthcheck, startup, etc.

It’s very nice to provide the cluster administrators with the means to run extra tasks - and it’s even nicer when you package this with the application so that you have targets like this :

docker run --rm -ti \
                -e POSTGRES_HOSTNAME=postgres.notifications \
                -e POSTGRES_PASSWORD=postgres \
                -e POSTGRES_DATABASE=notifications_dev \
                -e DATADOG_AGENT_HOSTNAME=localhost \
                -e DATADOG_AGENT_APM_PORT=8126 \
                -e EXQ_HOST=redis.notifications \
                -e EXQ_PASSWORD= \
                -e EXQ_PORT=6379 \
                -e EXQ_NAMESPACE=exq \
                --name notificatons \
                --network notifications \
                --hostname notifications  \
                -p 4000:4000 \
                foo/notifications:latest help
Usage: notifications COMMAND [ARGS]

The known commands are:

    start                  Starts the system
    start_iex              Starts the system with IEx attached
    daemon                 Starts the system as a daemon
    daemon_iex             Starts the system as a daemon with IEx attached
    eval "EXPR"            Executes the given expression on a new, non-booted system
    rpc "EXPR"             Executes the given expression remotely on the running system
    remote                 Connects to the running system via a remote shell
    restart                Restarts the running system via a remote command
    stop                   Stops the running system via a remote command
    pid                    Prints the OS PID of the running system via a remote command
    version                Prints the release name and version to be booted
--> run_migration          Run ecto migration
--> update_email_templates Update email templates (for example)

ERROR: Unknown command help

Marked As Solved

josevalim

josevalim

Creator of Elixir

Elixir v1.10 supports overlays, so you can also just drop those scripts in rel/overlays/bin/ without changing your mix.exs. :slight_smile:

Also Liked

josevalim

josevalim

Creator of Elixir

You can define them in lib. Here is an example from Phoenix release guides: https://hexdocs.pm/phoenix/releases.html#ecto-migrations-and-custom-commands

LostKobrakai

LostKobrakai

That‘s what I‘ve gone with:

josevalim

josevalim

Creator of Elixir

@bryanhuntesl to be clear, I mean it could be called bin/setup-db and inside it does ./my_app eval "..." and that’s all. :slight_smile:

bryanhuntesl

bryanhuntesl

This stuff is pretty ugly but I works - so I’m going to include it here in case anyone else needs to set this up for kubernetes pod initialization…

mix.exs :

defmodule Examples.Mixfile do
  use Mix.Project

  def project do
    [
      app: :examples,
      version: "0.0.1",
      elixir: "1.10.1",
      elixirc_paths: elixirc_paths(Mix.env()),
      compilers: Mix.compilers(),
      start_permanent: Mix.env() == :prod,
      aliases: aliases(),
      deps: deps(),
      releases: [
        examples: [
          steps: [:assemble, &copy_extra_files/1]
        ]
      ],
      test_coverage: [tool: ExCoveralls]
    ]
  end

  defp copy_extra_files(release) do
    dst = release.path <> "/bin/"

    ["create-db.sh", "migrate-db.sh", "setup-db.sh"]
    |> Enum.each(fn f -> File.cp!("rel/" <> f, dst <> f) end)

    release
  end

 .... ....
end

rel/create-db.sh :

#!/bin/sh

/opt/app/bin/examples eval "Application.load(:examples);  Confex.resolve_env!(:examples); dbconf = Confex.fetch_env!(:examples, Examples.Repo); Application.put_env(:examples, Examples.Repo, dbconf); [ :crypto, :logger, :ssl, :telemetry, :postgrex, :ecto ] |> Enum.each(&(Application.ensure_all_started(&1))); IO.puts(inspect(Examples.Repo.__adapter__.storage_up( Examples.Repo.config)));" 

rel/migrate-db.sh :

#!/bin/sh

/opt/app/bin/examples eval "Application.load(:examples);  Confex.resolve_env!(:examples); dbconf = Confex.fetch_env!(:examples, Examples.Repo); Application.put_env(:examples, Examples.Repo, dbconf); [ :crypto, :logger, :ssl, :telemetry, :postgrex, :ecto , :ecto_sql ] |> Enum.each(&(Application.ensure_all_started(&1))); Examples.Repo.start_link ; Ecto.Migration.Supervisor.start_link ; Ecto.Migrator.run(Examples.Repo, Application.app_dir(:examples, \"priv/repo/migrations\"), :up, [all: true])"

rel/setup-db.sh

#!/bin/sh

/opt/app/bin/create-db.sh
/opt/app/bin/migrate-db.sh

Where Next?

Popular in Questions Top

yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
LegitStack
I’m hoping you guys can give me some general advice and perhaps code examples if you’re feeling up to it. I’m very interested in Elixir,...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

Other popular topics Top

JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
peerreynders
Manning 2016 Halloween weekend sale via Deal of the Day Friday, October 28 - Half off all MEAPs - code WM102816LT Saturday, October 29 ...
326 29600 154
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

We're in Beta

About us Mission Statement