I am very new to Elixir. I have built an app which runs locally, which works fine. But now i need to build a container for it with Docker.
However, every attempt to do a release seems to try and connection to RabbitMQ (which is running locally, as a Docker Container).
I don't want, cant have it try and connect to Rabbit each time this container is built, as it will need to be built by a CI / CD pipeline and will never have access to any Rabbit. I have set it up with an ENV, but this needs to be set within my YAML when deploying to my k8s cluster.
So this is the Dockerfile:
# Container Base Image
FROM elixir:1.13.1-alpine as release_build
# Set Working Folder
WORKDIR app
#ENV RABBIT_CONNECTION=""
# Copy Source Code Into Container
COPY ./src/app ./
# Install Hex Package Manager
RUN mix local.hex --force
# Install Rebar
RUN mix local.rebar --force
# Get All Deps
RUN mix deps.get
RUN mix deps.compile
# Compile Application
RUN mix compile
So has you can see i have a ENV set with the Rabbit Connection URL (commented out currently). In this state i get,
The following arguments were given to AMQP.Connection.open/1:
If i set it, but only to an empty string, i get,
no match of right hand side value: {:error, {{:unable_to_parse_uri, :no_scheme}, []}}
I also tried with the valid URL of my locally running container, but has it was using localhost and on a different Docker network, that just returned an econnrefused error.
This is how I am connecting to Rabbit in my app,
rabbit_url = Application.fetch_env!(:rabbit, :url)
# Open Connection To Rabbit
{:ok, connection} = AMQP.Connection.open(rabbit_url)
{:ok, channel} = AMQP.Channel.open(connection)
This is the rabbit config file section,
config :rabbit, url: System.get_env("RABBIT_CONNECTION")
I made a little local Bash script to boot this,
RABBIT_CONNECTION='amqp://admin:password@localhost:5672' iex -S mix
This script works fine with the application to boot and connection to my locally running container for RabbitMQ
So I know there must be a way of getting the code to do a release without an connections, either to Rabbit or a Database or something similar like that.
Any help is most welcome
Thanks,
I have tried to create a project such as yours.
mix new broker_client
In the mix.exs application function is configured to run the start function of my module.
def application do
[
extra_applications: [:logger],
mod: {BrokerClient, []}
]
end
Additionally, in config/runtime.exs, I am configuring amqp with the connection and one or more channels as documented here.
import Config
config :amqp,
connections: [
myconn: [url: System.get_env("BROKER_URL")]
],
channels: [
mychan: [connection: :myconn]
]
In lib/broker_client.ex I have the start function implemented which creates a simple Task as showing in this answer.
defmodule BrokerClient do
def sample() do
{:ok, chan} = AMQP.Application.get_channel(:mychan)
:ok = AMQP.Basic.publish(chan, "", "", "Hello")
Process.sleep(1000 * 10)
end
def start(_type, _args) do
IO.puts("starting...")
Task.start(fn -> sample() end)
end
end
I can build this fine without having rabbitmq running locally or setting the variable broker.
FROM elixir as builder
WORKDIR /app
RUN mix local.hex --force && mix local.rebar --force
COPY mix.exs mix.lock ./
RUN mix deps.get --only prod
COPY ./ .
RUN MIX_ENV=prod mix release
FROM debian:stable-slim
ENV LANG="C.UTF-8" LC_AL="C.UTF-8" PATH="/app/bin:$PATH"
COPY --from=builder /app/_build/prod/rel/broker_client /app
CMD [ "broker_client", "start"]
Now I can run this with docker-compose as example.
version: '3.9'
services:
client:
build: ./
environment:
BROKER_URL: 'amqp://guest:guest@rabbitmq'
# sleep 10 seconds to give the broker time to start
command: [ "sh", "-c", "sleep 10 && broker_client start" ]
depends_on:
- rabbitmq
rabbitmq:
image: rabbitmq
Its probably also useful to look at the offical docs for Application.