Phoenix app - Unable to deploy due to app/bin/migrate error and dbconnection failed with non existing domain

Hi !
I’m struggling with the setup of an Elixir Phoenix new app with a postgresql database (created with fly launch), with Docker/Docker compose and a Gitlab CI.

I succeeded to deploy with fly deploy once, and now, i have a “UnhandledIoError” when the command /app/bin/migrate is running.
I read about it so i launched the mix.phx.release --ecto before fly launch at the beginning of the project.

When i try to push a new commit and run the Gitlab CI, i encounter an error of database connection.

The error in Gitlab CI job

The error when i run fly deploy

Below are the different config files :

fly.toml

app = “test”
kill_signal = “SIGTERM”
kill_timeout = 5
processes =

[deploy]
release_command = “/app/bin/migrate”

[env]
PHX_HOST = “test.fly.dev
PORT = “4000”

[experimental]
allowed_public_ports =
auto_rollback = true

[[services]]
http_checks =
internal_port = 4000
processes = [“app”]
protocol = “tcp”
script_checks =
[services.concurrency]
hard_limit = 25
soft_limit = 20
type = “connections”

[[services.ports]]
force_https = true
handlers = [“http”]
port = 80

[[services.ports]]
handlers = [“tls”, “http”]
port = 443

[[services.tcp_checks]]
grace_period = “60s”
interval = “15s”
restart_limit = 0
timeout = “2s”

Dockerfile used for lint and test CI stages

FROM debian:buster

RUN apt-get update && apt-get install -y
locales
curl
make
p7zip
wget
musl
build-essential
ca-certificates
gcc
libtool-bin
libsm6
inotify-tools
zip
&& apt-get purge -y --auto-remove $buildDeps
&& rm -rf /var/lib/apt/lists/*

RUN sed -i -e ‘s/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/’ /etc/locale.gen &&
dpkg-reconfigure --frontend=noninteractive locales &&
update-locale LANG=en_US.UTF-8

ENV LANG en_US.UTF-8

RUN wget https://packages.erlang-solutions.com/erlang-solutions_2.0_all.deb
&& dpkg -i erlang-solutions_2.0_all.deb
&& apt-get update && apt-get install -y
esl-erlang
elixir
&& apt-get purge -y --auto-remove $buildDeps
&& rm -rf /var/lib/apt/lists/*
&& elixir -v

RUN mix local.hex --force
&& mix local.rebar --force

WORKDIR /app

Dockerfile used for Fly deployment

ARG ELIXIR_VERSION=1.13.2
ARG OTP_VERSION=24.3.2
ARG DEBIAN_VERSION=bullseye-20210902-slim

ARG BUILDER_IMAGE=“hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}”
ARG RUNNER_IMAGE=“debian:${DEBIAN_VERSION}”

FROM ${BUILDER_IMAGE} as builder

install build dependencies

RUN apt-get update && apt-get install -y
locales
curl
make
p7zip
wget
musl
build-essential
ca-certificates
gcc
libtool-bin
libsm6
inotify-tools
zip
&& apt-get purge -y --auto-remove $buildDeps
&& apt-get clean
&& rm -rf /var/lib/apt/lists/*

prepare build dir

WORKDIR /app

install hex + rebar

RUN mix local.hex --force &&
mix local.rebar --force

set build ENV

ENV MIX_ENV=“prod”

install mix dependencies

COPY mix.exs mix.lock ./
RUN mix deps.get --only $MIX_ENV
RUN mkdir config

copy compile-time config files before we compile dependencies

to ensure any relevant config change will trigger the dependencies

to be re-compiled.

COPY config/config.exs config/${MIX_ENV}.exs config/
RUN mix deps.compile

COPY priv priv

COPY assets assets

COPY lib lib

compile assets

RUN mix assets.deploy

Compile the release

RUN mix compile

Changes to config/runtime.exs don’t require recompiling the code

COPY config/runtime.exs config/

COPY rel rel
RUN mix release

start a new build stage so that the final image will only contain

the compiled release and other runtime necessities

FROM ${RUNNER_IMAGE}

RUN apt-get update -y && apt-get install -y libstdc++6 openssl libncurses5 locales
&& apt-get clean && rm -f /var/lib/apt/lists/_

Set the locale

RUN sed -i ‘/en_US.UTF-8/s/^# //g’ /etc/locale.gen && locale-gen

ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

WORKDIR “/app”
RUN chown nobody /app

set runner ENV

ENV MIX_ENV=“prod”

Only copy the final release from the build stage

COPY --from=builder --chown=nobody:root /app/_build/${MIX_ENV}/rel/test ./

USER nobody

CMD [“/app/bin/server”]

Appended by flyctl

ENV ECTO_IPV6 true
ENV ERL_AFLAGS “-proto_dist inet6_tcp”

Config/config.exs

import Config

config :test,
ecto_repos: [Test.Repo]

Configures the endpoint

config :test, TestWeb.Endpoint,
url: [host: “localhost”],
secret_key_base: “####”,
render_errors: [view: TestWeb.ErrorView, accepts: ~w(html json), layout: false],
pubsub_server: Test.PubSub,
live_view: [signing_salt: “cxOT1sfW”]

config :test, Test.Mailer, adapter: Swoosh.Adapters.Local

Swoosh API client is needed for adapters other than SMTP.

config :swoosh, :api_client, false

Configure esbuild (the version is required)

config :esbuild,
version: “0.12.18”,
default: [
args: ~w(js/app.js --bundle --target=es2016 --outdir=…/priv/static/assets),
cd: Path.expand(“…/assets”, DIR),
env: %{“NODE_PATH” => Path.expand(“…/deps”, DIR)}
]

Configures Elixir’s Logger

config :logger, :console,
format: “$time $metadata[$level] $message\n”,
metadata: [:request_id]

Use Jason for JSON parsing in Phoenix

config :phoenix, :json_library, Jason

Import environment specific config. This must remain at the bottom

of this file so it overrides the configuration defined above.

import_config “#{config_env()}.exs”

Config/dev.exs

import Config

Configure your database

config :test, Test.Repo,
username: “postgres”,
password: “postgres”,
database: “test_dev”,
hostname: “db”,
show_sensitive_data_on_connection_error: true,
pool_size: 10

config :test, TestWeb.Endpoint,

Binding to loopback ipv4 address prevents access from other machines.

Change to ip: {0, 0, 0, 0} to allow access from other machines.

http: [port: 4000],
debug_errors: true,
code_reloader: true,
check_origin: false,
watchers: [
# Start the esbuild watcher by calling Esbuild.install_and_run(:default, args)
esbuild: {Esbuild, :install_and_run, [:default, ~w(–sourcemap=inline --watch)]}
]

Watch static and templates for browser reloading.

config :test, TestWeb.Endpoint,
live_reload: [
patterns: [
~r"priv/static/.(js|css|png|jpeg|jpg|gif|svg)$",
~r"priv/gettext/.
(po)$“,
~r"lib/test_web/(live|views)/.(ex)$",
~r"lib/test_web/templates/.
(eex)$”
]
]

Do not include metadata nor timestamps in development logs

config :logger, :console, format: “[$level] $message\n”

Set a higher stacktrace during development. Avoid configuring such

in production as building large stacktraces may be expensive.

config :phoenix, :stacktrace_depth, 20

Initialize plugs at runtime for faster development compilation

config :phoenix, :plug_init_mode, :runtime

Config/runtime.exs

import Config

The block below contains prod specific runtime configuration.

if config_env() == :prod do
database_url =
System.get_env(“DATABASE_URL”) ||
raise “”"
environment variable DATABASE_URL is missing.
For example: ecto://USER:PASS@HOST/DATABASE
“”"

config :test Test.Repo,
ssl: false,
socket_options: [:inet6],
url: database_url,
pool_size: String.to_integer(System.get_env(“POOL_SIZE”) || “10”)

secret_key_base =
System.get_env(“SECRET_KEY_BASE”) ||
raise “”"
environment variable SECRET_KEY_BASE is missing.
You can generate one by calling: mix phx.gen.secret
“”"

app_name =
System.get_env(“FLY_APP_NAME”) ||
raise “FLY_APP_NAME not available”

config :test, TestWeb.Endpoint,
server: true,
url: [host: “#{app_name}.fly.dev”, port: 443],
http: [
# Enable IPv6 and bind on all interfaces.
# Set it to {0, 0, 0, 0, 0, 0, 0, 1} for local network only access.
# See the documentation on Plug.Cowboy — Plug.Cowboy v2.5.2
# for details about using IPv6 vs IPv4 and loopback vs public addresses.
ip: {0, 0, 0, 0, 0, 0, 0, 0},
port: String.to_integer(System.get_env(“PORT”) || “4000”),
transport_options: [socket_opts: [:inet6]]
],
secret_key_base: secret_key_base

end

I’m totally new to devops so it’s not easy to understand how this all workflow work, and why it’s not working yet.

And I read a lot of threads and docs but i don’t understand where i have to set the fly postgres database variables in the config files for production :thinking:

What am i doing wrong ? Someone has an idea ?
Thanks by advance :grinning:

Hi @sevb!

The error message says that the /bin/app/migrate file does not exist in your Docker container.

While the collapsible file regions are a nice feature, it doesn’t seem to work with pre-formatted tags and it makes it very difficult to read.

It’s ok, I added the database env variables in my docker-compose file and the deployment succeed :smiley:

1 Like