Nefcairon

Nefcairon

Deployment of NX.Explorer to fly.io

Hello,

In my attempt to develop a phoenix web app I have created a fly.io account. fly.io requires a docker image and I get following error when I use docker build .:

Step 10/30 : RUN mix deps.get --only prod &&     mix deps.compile
 ---> Running in d9c1165e2bfa
* Getting explorer (https://github.com/elixir-nx/explorer.git - origin/main)
** (Mix) Error fetching/updating Git repository: the "git" executable is not available in your PATH. Please install Git on this machine or pass --no-deps-check if you want to run a previously built application on a system without Git.
The command '/bin/sh -c mix deps.get --only prod &&     mix deps.compile' returned a non-zero code: 1

This is happening because one dep in mix.exs is from github:
{:explorer, "~> 0.1.0-dev", github: "elixir-nx/explorer"

As I have never used docker, I ask for help. Do I have to change the dockerfile? I use the one from Getting Started · Fly Docs.

Marked As Solved

andrewb

andrewb

Hi @Nefcairon,

I was working through this problem yesterday as well.

In the end, I installed nodejs and npm packages on the BUILDER image, changed the order of the COPY commands and added npm install.

The NODE_ENV=production npx tailwindcss --postcss --minify -i css/app.css -o ../priv/static/assets/app.css && cd .. call is in your package.json file so it will be called when you call mix assets.deploy.

My final Dockerfile looks like this:

ARG BUILDER_IMAGE="hexpm/elixir:1.12.3-erlang-24.1.4-debian-bullseye-20210902-slim"
ARG RUNNER_IMAGE="debian:bullseye-20210902-slim"

FROM ${BUILDER_IMAGE} as builder

# install build dependencies
RUN apt-get update -y && apt-get install -y build-essential git nodejs npm \
    && apt-get clean && rm -f /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

# Compile the release
COPY lib lib

COPY priv priv

COPY assets assets

RUN cd assets && npm install

RUN mix assets.deploy

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

# Only copy the final release from the build stage
COPY --from=builder --chown=nobody:root /app/_build/prod/rel ./

USER nobody

# Create a symlink to the application directory by extracting the directory name. This is required
# since the release directory will be named after the application, and we don't know that name.
RUN set -eux; \
  ln -nfs /app/$(basename *)/bin/$(basename *) /app/entry

CMD /app/entry start

Also Liked

thomas.fortes

thomas.fortes

You need to update the image that you’re using, the tutorial on fly.io uses an old version of alpine that has an old rust version than the 1.51 that @cschmatzler mentioned.

Change the first line from FROM hexpm/elixir:1.12.1-erlang-24.0.1-alpine-3.13.3 AS build to FROM hexpm/elixir:1.12.3-erlang-24.1.4-alpine-3.14.2 AS build to use a more recent one.

Also, you don’t need to insert new lines to add each new package, apk add works like apt, dnf, pacman and every other linux package manager, you can do it all in one line.

RUN apk add --no-cache build-base npm git rust cargo

dimitarvp

dimitarvp

To make sure you have smaller image, do this for the Rustup step:

RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain stable --profile minimal --target x86_64-unknown-linux-gnu -y

The --profile minimal part is crucial and it shaved off ~500MB from our Docker image. With the default profile Rust is installed as if it’s on a development machine. The minimal profile is for servers / apps.

The --target x86_64-unknown-linux-gnu thing you can skip but I prefer to be explicit – 50/50, your call.

More info here: Profiles - The rustup book

riebeekn

riebeekn

You will need to customize the build file depending on your particular needs. For instance since you need to grab a hex dependency via git, you’ll need to add git as part of the docker build dependencies, i.e.

# install build dependencies
RUN apk add --no-cache build-base npm git

Hopefully that will get you further along, unfortunately there is probably no avoiding learning at least some docker, there are a number of examples of phoenix specific docker files floating around if you search on this forum or hit up the google machine.

Last Post!

talhaazeem-invozone

talhaazeem-invozone

I am getting error on the npm install, any idea?

------
 > [builder 13/18] RUN cd assets && npm install:
#22 0.629 npm ERR! must provide string spec
#22 0.637
#22 0.637 npm ERR! A complete log of this run can be found in:
#22 0.637 npm ERR!     /root/.npm/_logs/2022-09-05T15_26_34_548Z-debug.log
------
Error failed to fetch an image or build from source: error building: executor failed running [/bin/sh -c cd assets && npm install]: exit code: 1

Where Next?

Popular in Questions Top

JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

Other popular topics Top

Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New

We're in Beta

About us Mission Statement