I’m running a Phoenix app on a Kubernetes cluster (through Digital Ocean) and I was able to deploy my app with minimal issues for the most part.
However, for some reason, calling Ecto.Migrator
keeps saying “migrations already up” when in reality, it hasn’t actually done anything. Even the schema_migrations
table is empty.
This isn’t the first time I’ve done a deployment setup like this so I am dumbfounded as to why this is happening in the first place. I definitely have a few migration files in the app, but they have not run at all.
Here is the release task module that I’m using:
defmodule MyApp.ReleaseTasks do
@moduledoc false
@app :my_app
def migrate do
load_app()
# migrate database
for repo <- repos() do
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true))
end
# migrate event store
config = MyApp.EventStore.config()
:ok = EventStore.Tasks.Migrate.exec(config, [])
end
def rollback(repo, version) do
load_app()
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version))
end
def seed do
for repo <- repos() do
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &MyApp.ReleaseTasks.run_seed_for(&1))
end
end
def init_event_store do
load_app()
config = MyApp.EventStore.config()
:ok = EventStore.Tasks.Init.exec(config, [])
end
def run_seed_for(repo) do
seed_script = priv_path_for(repo, "seeds.exs")
if File.exists?(seed_script) do
IO.puts("Running seed script...")
Code.eval_file(seed_script)
end
end
defp repos do
Application.fetch_env!(@app, :ecto_repos)
end
defp load_app do
{:ok, _} = Application.ensure_all_started(:postgrex)
{:ok, _} = Application.ensure_all_started(:ssl)
:ok = Application.load(@app)
end
defp priv_path_for(repo, filename) do
app = Keyword.get(repo.config, :otp_app)
repo_underscore =
repo
|> Module.split()
|> List.last()
|> Macro.underscore()
priv_dir = "#{:code.priv_dir(app)}"
Path.join([priv_dir, repo_underscore, filename])
end
end
This is my app’s config/releases.ex file:
import Config
config :my_app, MyAppWeb.Endpoint,
http: [
port: String.to_integer(System.fetch_env!("PORT")),
transport_options: [socket_opts: [:inet6]]
],
url: [
host: System.fetch_env!("HOST"),
port: String.to_integer(System.fetch_env!("PORT"))
],
server: true,
secret_key_base: System.fetch_env!("SECRET_KEY_BASE")
config :my_app, MyApp.Repo,
hostname: System.fetch_env!("DB_HOSTNAME"),
username: System.fetch_env!("DB_USERNAME"),
password: System.fetch_env!("DB_PASSWORD"),
database: System.fetch_env!("DB_NAME"),
port: System.fetch_env!("DB_PORT"),
pool_size: String.to_integer(System.fetch_env!("DB_POOL_SIZE")),
ssl: true,
ssl_opts: [
cacertfile: System.fetch_env!("DB_CERT")
]
config :my_app, MyApp.EventStore,
hostname: System.fetch_env!("EVENTSTORE_DB_HOSTNAME"),
username: System.fetch_env!("EVENTSTORE_DB_USERNAME"),
password: System.fetch_env!("EVENTSTORE_DB_PASSWORD"),
database: System.fetch_env!("EVENTSTORE_DB_NAME"),
port: System.fetch_env!("EVENTSTORE_DB_PORT"),
pool_size: String.to_integer(System.fetch_env!("EVENTSTORE_DB_POOL_SIZE")),
ssl: true,
ssl_opts: [
cacertfile: System.fetch_env!("EVENTSTORE_DB_CERT")
]
This is the Dockerfile that I’m using:
FROM beardedeagle/alpine-phoenix-builder:1.11.3 AS build
WORKDIR /app
RUN mix local.hex --force && \
mix local.rebar --force
ENV MIX_ENV=prod
COPY mix.exs mix.lock ./
COPY config config
RUN mix do deps.get, deps.compile
COPY lib lib
COPY rel rel
RUN mix do compile, release
FROM alpine:3.13 AS app
RUN apk add --no-cache openssl ncurses-libs
WORKDIR /app
EXPOSE 4000
RUN chown nobody:nobody /app
USER nobody:nobody
COPY --from=build --chown=nobody:nobody /app/_build/prod/rel/my_app ./
ENV HOME=/app
CMD ["bin/my_app", "start"]
I can confirm that the required environment variables are present inside the pod that gets created from the Kubernetes deployment so I don’t think there are any issues with that.
Also, running the commands from the release tasks module don’t result in any errors. The only issue is that running bin/my_app eval "MyApp.ReleaseTasks.migrate
outputs “Migrations already up” when that is not in fact the case.
Another thing I could point out is that I am using commanded/eventstore for this app and running the migrations for the event store actually works.
Any help is appreciated.