Running seeds in production

almirsarajcic

almirsarajcic

Created 6 months ago

If you’re deploying apps using Elixir releases and Docker containers, you’ve noticed Mix is not available, so you can’t run any mix tasks. Running mix phx.gen.release helps with the migrations, but if you want to also run seeds, you need to do it on your own.

In the file lib/omedis/release.ex add the following:

def seed do
  load_app()
  Application.ensure_all_started(@app)

  for repo <- repos() do
    {:ok, _fun_return, _apps} =
      Ecto.Migrator.with_repo(repo, fn repo ->
        # Run the seed script if it exists
        seed_script = priv_path_for(repo, "seeds.exs")

        if File.exists?(seed_script) do
          Code.eval_file(seed_script)
        end
      end)
  end
end

defp priv_path_for(repo, filename) do
  app = Keyword.get(repo.config(), :otp_app)

  repo_underscore =
    repo
    |> Module.split()
    |> Enum.at(-1)
    |> Macro.underscore()

  priv_dir = "#{:code.priv_dir(app)}"

  Path.join([priv_dir, repo_underscore, filename])
end

Then, update rel/overlays/bin/migrate to include this line:

exec ./my_app eval 'MyApp.Release.migrate && MyApp.Release.seed'

Add the following steps to the runner stage of the Dockerfile:

COPY --chown=nobody:root docker-entrypoint.sh ./
RUN chmod +x docker-entrypoint.sh
ENTRYPOINT ["/bin/sh", "docker-entrypoint.sh"]

Finally, create a docker-entrypoint.sh file:

#!/bin/sh

bin/migrate

exec "$@"

Here’s a working example: https://github.com/3Stones-io/omedis/pull/383/files.
Mind you, this application is using Ash, so migrations are a little different than a normal Phoenix application.

Make sure running seeds is idempotent operation, meaning it should not fail if the records already exist.