MyXQL says failed to connect ... non-existing domain - but there is no example.com :o

I’m trying to cram my phoenix project into a couple of containers. I have a mysql-server running in a container that exposes 3306 (and which I’m able to connect to from CLI). I’ve built a container for my app with this

# BUILD STAGE
FROM bitwalker/alpine-elixir-phoenix:latest AS phx-builder

# Set exposed ports
ENV MIX_ENV=prod

RUN mkdir /app
WORKDIR /app

# Cache elixir deps
ADD mix.exs mix.lock ./
RUN mix do deps.get, deps.compile

# Same with npm deps
ADD assets/package.json assets/
RUN cd assets && \
  npm install

ADD . .

# Run frontend build, compile, and digest assets
RUN cd assets/ && \
  npm run deploy && \
  cd - && \
  mix do deps.get, deps.compile, phx.digest, release

# APPLICATION STAGE
FROM bitwalker/alpine-elixir:latest

COPY --from=phx-builder /app/_build .

RUN chmod +x ./prod/rel/fish/bin/fish
RUN mkdir ./prod/rel/fish/tmp
RUN chmod +x ./prod/rel/fish/bin/fish

EXPOSE 5000
ENV MIX_ENV=prod 
ENV APP_PORT=4000 
ENV COOL_TEXT="Elixir Rocks" 
ENV SECRET_KEY_BASE="Aru1gpxiZDZHqt6biIsZoblCM8/yUPLy3kG9BhgcvcKUDUv5SkPhR4q/HKhZkcV7" 
ENV POOL_SIZE=10 

CMD ["./prod/rel/fish/bin/fish", "start"]

I can do

$ docker build -f Dockerfile.build -t fish .

but when I do

$ docker run --publish 4000:4000 --env COOL_TEXT='ELIXIR ROCKS!!!!' --env SECRET_KEY_BASE=fikumdick --env APP_PORT=4000 --env PORT_SIZE=10 --env HOST=localhost fish:latest

I get this output

15:31:11.834 [info] Running FishWeb.Endpoint with cowboy 2.7.0 at :::4000 (http)
15:31:11.835 [info] Access FishWeb.Endpoint at http://example.com
15:31:13.194 [error] MyXQL.Connection (#PID<0.3290.0>) failed to connect: ** (DBConnection.ConnectionError) non-existing domain

(and I haven’t the faintest idea where ‘it’ digs up that example.com - I have zero mentioning of that in any file)

My config/config.exs looks like this:

# config/config.exs
use Mix.Config

config :fish,
  ecto_repos: [Fish.Repo]

# Configures the endpoint
config :fish, FishWeb.Endpoint,
  url: [host: {:system, "HOST"}, port: {:system, "PORT"}],
  load_from_system_env: true,
  secret_key_base: "nOPS8kJTmAZtcgOpGVo7fMrAbFCCUVySKShVewMdaudersQgSLszNnTqb36fm71I",
  render_errors: [view: FishWeb.ErrorView, accepts: ~w(html json), layout: false],
  pubsub_server: Fish.PubSub,
  live_view: [signing_salt: "i1ucCSg6"]

config :fish, :pow,
  user: Fish.Users.User,
  repo: Fish.Repo,
  extensions: [PowResetPassword],
  controller_callbacks: Pow.Extension.Phoenix.ControllerCallbacks,
  web_module: FishWeb,
  mailer_backend: FishWeb.Pow.Mailer

config :fish, :pow_assent,
  providers: [
    github: [
      client_id: "REPLACE_WITH_CLIENT_ID",
      client_secret: "REPLACE_WITH_CLIENT_SECRET",
      strategy: Assent.Strategy.Github
    ]
    # example: [
    #   client_id: "REPLACE_WITH_CLIENT_ID",
    #   site: "https://server.example.com",
    #   authorization_params: [scope: "user:read user:write"],
    #   nonce: true,
    #   strategy: Assent.Strategy.OIDC
    # ]
  ]

# 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

and my releases.exs looks like this

#config/releases.exs 
import Config

secret_key_base = System.fetch_env!("SECRET_KEY_BASE")
cool_text = System.fetch_env!("COOL_TEXT")
application_port = System.fetch_env!("APP_PORT")
pool_size = System.fetch_env!("POOL_SIZE")

config :fish,
  cool_text: cool_text

config :fish, Fish.Repo,
  # ssl: true,
  migration_primary_key: [name: :id, type: :binary_id],
  username: "root",
  password: "",
  database: "fish_dev",
  hostname: "fish_db",
  # url: database_url,
  pool_size: String.to_integer(pool_size || "10")

config :fish, FishWeb.Endpoint,
  http: [:inet6, port: String.to_integer(application_port)],
  secret_key_base: secret_key_base

I believe the non-existing domain errors refers to the fish_db host, double-check that this host is reachable from within your app container.

Very good point (from Rails I’m used to calling on the container service name - which would be ‘db’ in this case, but I “just had to” rename the container - and then lured myself into calling on that – aarrgh

but can you explain where that “example.com” comes from?

15:31:11.835 [info] Access FishWeb.Endpoint at http://example.com

Secondly - changing the host to ‘db’ (which definitely needed to be changed :open_mouth:) did not remedy the error message :cry:

but can you explain where that “example.com” comes from?

AFAIR this particular messages is created when your Endpoint is started in your supervision tree and if memory serves, the :url configuration on the endpoint specifies that.

so - when my entire ./fish folder has 4 mentions of example.com - and every single one of them is a comment, and I’m frantically googling for how to IO.inspect the config structure to see what gets fed into the def start in application.ex where the FishWeb.Endpoint is being started - then what (provided I’m feeling pretty much out of luck on the googling thing) :cry:

Add this to your application start:

IO.inspect Application.get_all_env(:yourapp)

These may be also useful to know precisely what Repo and Endpoint are running with:

IO.inspect YourApp.Repo.config()
IO.inspect YourAppWeb.Endpoint.config(:url)

great :slight_smile:

but I’m afraid that made everything go from bad to worse - my understanding included :face_with_thermometer:

$ iex -S mix phx.server
Erlang/OTP 22 [erts-10.4.4] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Compiling 1 file (.ex)
[]
[
  telemetry_prefix: [:fish, :repo],
  otp_app: :fish,
  timeout: 15000,
  pool_size: 10
]
** (Mix) Could not start application fish: exited in: Fish.Application.start(:normal, [])
    ** (EXIT) an exception was raised:
        ** (ArgumentError) argument error
            (stdlib 3.9.2) :ets.lookup(FishWeb.Endpoint, :url)
            (fish 0.1.0) lib/phoenix/endpoint.ex:474: FishWeb.Endpoint.config/2
            (fish 0.1.0) lib/fish/application.ex:11: Fish.Application.start/2
            (kernel 6.4.1) application_master.erl:277: :application_master.start_it_old/4

with my application.ex looking like this:

defmodule Fish.Application do
  # See https://hexdocs.pm/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application

  def start(_type, _args) do
    IO.inspect(Application.get_all_env(:yourapp))
    IO.inspect(Fish.Repo.config())
    IO.inspect(FishWeb.Endpoint.config(:url))

    children = [
      # Start the Ecto repository
      Fish.Repo,
      # Start the Telemetry supervisor
      FishWeb.Telemetry,
      # Start the PubSub system
      {Phoenix.PubSub, name: Fish.PubSub},
      # Start the Endpoint (http/https)
      FishWeb.Endpoint
      # Start a worker by calling: Fish.Worker.start_link(arg)
      # {Fish.Worker, arg}
    ]

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: Fish.Supervisor]
    Supervisor.start_link(children, opts)
  end

  # Tell Phoenix to update the endpoint configuration
  # whenever the application is updated.
  def config_change(changed, _new, removed) do
    FishWeb.Endpoint.config_change(changed, removed)
    :ok
  end
end

Apologies, we cannot check endpoint config because it hasnt been started yet! I believe putting the IO.inspects after Supervisor.start_link will do the trick (remember that return value of Supervisor.start_link must be returned from the start/2 function)

ohh - I should have catched that one myself - sorry!

But it keeps barfing on the lookup of that :url

$ iex -S mix phx.server
Erlang/OTP 22 [erts-10.4.4] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Compiling 1 file (.ex)
00:07:25.511 [error] MyXQL.Connection (#PID<0.376.0>) failed to connect: ** (DBConnection.ConnectionError) no such file or directory "/tmp/mysql.sock"
00:07:25.511 [error] MyXQL.Connection (#PID<0.379.0>) failed to connect: ** (DBConnection.ConnectionError) no such file or directory "/tmp/mysql.sock"
00:07:25.511 [error] MyXQL.Connection (#PID<0.382.0>) failed to connect: ** (DBConnection.ConnectionError) no such file or directory "/tmp/mysql.sock"
00:07:25.511 [error] MyXQL.Connection (#PID<0.375.0>) failed to connect: ** (DBConnection.ConnectionError) no such file or directory "/tmp/mysql.sock"
00:07:25.511 [error] MyXQL.Connection (#PID<0.380.0>) failed to connect: ** (DBConnection.ConnectionError) no such file or directory "/tmp/mysql.sock"
00:07:25.511 [error] MyXQL.Connection (#PID<0.374.0>) failed to connect: ** (DBConnection.ConnectionError) no such file or directory "/tmp/mysql.sock"
00:07:25.511 [error] MyXQL.Connection (#PID<0.383.0>) failed to connect: ** (DBConnection.ConnectionError) no such file or directory "/tmp/mysql.sock"
00:07:25.511 [error] MyXQL.Connection (#PID<0.377.0>) failed to connect: ** (DBConnection.ConnectionError) no such file or directory "/tmp/mysql.sock"
00:07:25.511 [error] MyXQL.Connection (#PID<0.378.0>) failed to connect: ** (DBConnection.ConnectionError) no such file or directory "/tmp/mysql.sock"
00:07:25.511 [error] MyXQL.Connection (#PID<0.381.0>) failed to connect: ** (DBConnection.ConnectionError) no such file or directory "/tmp/mysql.sock"
[]
[
  telemetry_prefix: [:fish, :repo],
  otp_app: :fish,
  timeout: 15000,
  pool_size: 10
]
00:07:25.524 [info] Application fish exited: exited in: Fish.Application.start(:normal, [])
    ** (EXIT) an exception was raised:
        ** (ArgumentError) argument error
            (stdlib 3.9.2) :ets.lookup(FishWeb.Endpoint, :url)
            (fish 0.1.0) lib/phoenix/endpoint.ex:474: FishWeb.Endpoint.config/2
            (fish 0.1.0) lib/fish/application.ex:28: Fish.Application.start/2
            (kernel 6.4.1) application_master.erl:277: :application_master.start_it_old/4
** (Mix) Could not start application fish: exited in: Fish.Application.start(:normal, [])
    ** (EXIT) an exception was raised:
        ** (ArgumentError) argument error
            (stdlib 3.9.2) :ets.lookup(FishWeb.Endpoint, :url)
            (fish 0.1.0) lib/phoenix/endpoint.ex:474: FishWeb.Endpoint.config/2
            (fish 0.1.0) lib/fish/application.ex:28: Fish.Application.start/2
            (kernel 6.4.1) application_master.erl:277: :application_master.start_it_old/4

now with application.ex like this

...

  def start(_type, _args) do
    children = [
      # Start the Ecto repository
      Fish.Repo,
      # Start the Telemetry supervisor
      FishWeb.Telemetry,
      # Start the PubSub system
      {Phoenix.PubSub, name: Fish.PubSub},
      # Start the Endpoint (http/https)
      FishWeb.Endpoint
      # Start a worker by calling: Fish.Worker.start_link(arg)
      # {Fish.Worker, arg}
    ]

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: Fish.Supervisor]
    ret = Supervisor.start_link(children, opts)
    IO.inspect(Application.get_all_env(:yourapp))
    IO.inspect(Fish.Repo.config())
    IO.inspect(FishWeb.Endpoint.config(:url))
    ret
  end
...

But how does your endpoint related config look like?

# config/config.exs
# Configures the endpoint
config :fish, FishWeb.Endpoint,
  url: [host: {:system, "HOST"}, port: {:system, "PORT"}],
  load_from_system_env: true,
  secret_key_base: "nOPS8kJTmAZtcgOpGVo7fMrAbFCCUVySKShVewMdaudersQgSLszNnTqb36fm71I",
  render_errors: [view: FishWeb.ErrorView, accepts: ~w(html json), layout: false],
  pubsub_server: Fish.PubSub,
  live_view: [signing_salt: "i1ucCSg6"]

and releases.exs looks like this:

import Config

secret_key_base = System.fetch_env!("SECRET_KEY_BASE")
cool_text = System.fetch_env!("COOL_TEXT")
application_port = System.fetch_env!("APP_PORT")
pool_size = System.fetch_env!("POOL_SIZE")
hostname = System.fetch_env!("DBHOST")

config :fish,
  cool_text: cool_text

# database_url =
#   System.get_env("DATABASE_URL") ||
#     raise """
#     environment variable DATABASE_URL is missing.
#     For example: ecto://USER:PASS@HOST/DATABASE
#     """

config :fish, Fish.Repo,
  # ssl: true,
  migration_primary_key: [name: :id, type: :binary_id],
  username: "root",
  password: "",
  database: "fish_dev",
  hostname: hostname,
  # url: database_url,
  pool_size: String.to_integer(pool_size || "10")

config :fish, FishWeb.Endpoint,
  http: [:inet6, port: String.to_integer(application_port)],
  secret_key_base: secret_key_base

and the output - when trying out the ./build.sh now says

Successfully tagged fish:latest
22:15:52.926 [error] MyXQL.Connection (#PID<0.3291.0>) failed to connect: ** (DBConnection.ConnectionError) non-existing domain
22:15:52.926 [error] MyXQL.Connection (#PID<0.3290.0>) failed to connect: ** (DBConnection.ConnectionError) non-existing domain
22:15:52.926 [error] MyXQL.Connection (#PID<0.3289.0>) failed to connect: ** (DBConnection.ConnectionError) non-existing domain
22:15:52.926 [error] MyXQL.Connection (#PID<0.3288.0>) failed to connect: ** (DBConnection.ConnectionError) non-existing domain
22:15:52.926 [error] MyXQL.Connection (#PID<0.3287.0>) failed to connect: ** (DBConnection.ConnectionError) non-existing domain
22:15:52.926 [error] MyXQL.Connection (#PID<0.3286.0>) failed to connect: ** (DBConnection.ConnectionError) non-existing domain
22:15:52.927 [error] MyXQL.Connection (#PID<0.3281.0>) failed to connect: ** (DBConnection.ConnectionError) non-existing domain
22:15:52.927 [error] MyXQL.Connection (#PID<0.3285.0>) failed to connect: ** (DBConnection.ConnectionError) non-existing domain
22:15:52.927 [error] MyXQL.Connection (#PID<0.3280.0>) failed to connect: ** (DBConnection.ConnectionError) non-existing domain
22:15:52.927 [error] MyXQL.Connection (#PID<0.3284.0>) failed to connect: ** (DBConnection.ConnectionError) non-existing domain
[]
[
  telemetry_prefix: [:fish, :repo],
  otp_app: :fish,
  timeout: 15000,
  migration_primary_key: [name: :id, type: :binary_id],
  username: "root",
  password: "",
  database: "fish_dev",
  hostname: "db",
  pool_size: 10
]
[path: "/", host: {:system, "HOST"}, port: {:system, "PORT"}]
22:15:54.029 [error] MyXQL.Connection (#PID<0.3280.0>) failed to connect: ** (DBConnection.ConnectionError) non-existing domain

and my docker-compose.yml is:

version: "3"
services:
  db:
    image: mysql:latest
    container_name: fish_db
    environment:
      - MYSQL_DATABASE='fish_dev'
      - MYSQL_PASSWORD=''
      - MYSQL_USER='root'
      - MYSQL_ROOT_PASSWORD='R00t!?R00t'
    ports:
      - "3306:3306"
    expose:
      - "3306"
    volumes:
      - ./priv/repo/db:/var/lib/mysql
    networks:
      - db-network
  # admin:
  #   image: fish:latest
  #   container_name: fish-admin
  #   build:
  #     context: .
  #     dockerfile: Dockerfile.run
  #   command: migrate
  #   networks:
  #     - db-network
  #   depends_on:
  #     - db
  server:
    image: fish:latest
    container_name: fish-app-server
    environment:
      - PORT=4000
      - HOST="localhost"
      - DBHOST="db"
      - COOL_TEXT='ELIXIR ROCKS!!!!'
      - SECRET_KEY_BASE=fikumdick
      - APP_PORT=4000
      - PORT_SIZE=10
    expose:
      - "4000"
    command: ./prod/rel/fish/bin/fish start
    networks:
      - db-network
    depends_on:
      - db
#      - admin
volumes:
  fish_db: {}
networks:
  db-network:
#    external: true

ups - wrong output - when using the docker-compose up - this is what I see

$ docker-compose up server
fish_db is up-to-date
Creating fish-app-server ... done
Attaching to fish-app-server
fish-app-server | []
fish-app-server | [
fish-app-server |   telemetry_prefix: [:fish, :repo],
fish-app-server |   otp_app: :fish,
fish-app-server |   timeout: 15000,
fish-app-server |   migration_primary_key: [name: :id, type: :binary_id],
fish-app-server |   username: "root",
fish-app-server |   password: "",
fish-app-server |   database: "fish_dev",
fish-app-server |   hostname: "\"db\"",
fish-app-server |   pool_size: 10
fish-app-server | ]
fish-app-server | [path: "/", host: {:system, "HOST"}, port: {:system, "PORT"}]
fish-app-server | 22:19:58.889 [error] MyXQL.Connection (#PID<0.3291.0>) failed to connect: ** (DBConnection.ConnectionError) non-existing domain
fish-app-server | 22:19:58.890 [error] MyXQL.Connection (#PID<0.3290.0>) failed to connect: ** (DBConnection.ConnectionError) non-existing domain

that did the trick - now I’m at least back on turf where I am used to wander :icon_biggrin:

removing the “” from the docker-compose.yml line

- DBHOST="db"

instead having

- DBHOST=db

let me have this:

$ docker-compose up server
fish_db is up-to-date
Recreating fish-app-server ... done
Attaching to fish-app-server
fish-app-server | []
fish-app-server | [
fish-app-server |   telemetry_prefix: [:fish, :repo],
fish-app-server |   otp_app: :fish,
fish-app-server |   timeout: 15000,
fish-app-server |   migration_primary_key: [name: :id, type: :binary_id],
fish-app-server |   username: "root",
fish-app-server |   password: "",
fish-app-server |   database: "fish_dev",
fish-app-server |   hostname: "db",
fish-app-server |   pool_size: 10
fish-app-server | ]
fish-app-server | [path: "/", host: {:system, "HOST"}, port: {:system, "PORT"}]
fish-app-server | 22:22:25.712 [error] MyXQL.Connection (#PID<0.3285.0>) failed to connect: ** (MyXQL.Error) (1130) (ER_HOST_NOT_PRIVILEGED) Host '172.21.0.3' is not allowed to connect to this MySQL server

and that problem I know how to fix!

:smile:

:flat-on-my-belly-in-gratitude-and-sobbing-for-forgiveness-waisting-your-bandwidth:

thx both of you!

So was the main problem a yaml quoting issue?

yes

  • and I should have been on to that from the start!

Composing Docker compose yml’s will allow you to reference a somewhat covert naming scheme where hosts are named by their service - in this case: db

If you put that in “” I reckon that Docker will not try to extrapolate (or whatever it does) but take the string at face value -

So yes - I should have typed db where I typed "db" - and saved Wojtech and NoobZ precious time!

my bad

1 Like

I erred on two accounts

  1. I referenced file_db (which is the container image name in my configuration) where I should have referenced the service name - because hosts are setup by default with hostname = service name - see the docker reference link below

  2. I quoted db in the docker-compose.yml file where I should have left the quotes out (in effect ‘promoting’ db to a local variable of sorts

# ./docker-compose.yml
version: "3"
services:
  db:
    image: mysql:latest
    container_name: fish_db
    environment:
      - MYSQL_DATABASE='fish_prod'
      - MYSQL_PASSWORD='another secret'
      - MYSQL_USER='root'
      - MYSQL_ROOT_PASSWORD='secret'
    ports:
      - "3306:3306"
    expose:
      - "3306"
    volumes:
      - ./priv/repo/db:/var/lib/mysql
    networks:
      - db-network
  server:
    image: fish:latest
    container_name: fish-app-server
    environment:
      - PORT=4000
      - HOST="127.0.0.1"
      - DBHOST=db
      - DBNAME=fish_prod
      - SECRET_KEY_BASE=fikumdick
    expose:
      - "4000"
    ports:
      - "4000:4000"
    command: ./prod/rel/fish/bin/fish start
    networks:
      - db-network
    depends_on:
      - db
volumes:
  fish_db: {}
networks:
  db-network:
2 Likes