Phoenix Docker build fails on npm ci

Setting up a phoneix project in a container , works fine on the cli

Dockerfile

FROM hexpm/elixir:1.11.2-erlang-23.1.3-debian-buster-20201012 AS base

# install build dependencies
RUN apt-get -qq update && \
    apt-get -qq -y install build-essential npm git python --fix-missing --no-install-recommends


# prepare build dir
WORKDIR /app

ARG MIX_ENV
ARG RELEASE_LEVEL

ENV LANG=C.UTF-8 LC_ALL=C.UTF-8

# Update timezone
ENV TZ=Asia/Singapore

# install hex + rebar
RUN mix local.hex --force && \
    mix local.rebar --force

# set build ENV

ENV MIX_ENV=$MIX_ENV

# install mix dependencies
COPY mix.exs mix.lock ./
COPY config config
RUN mix deps.get --only $MIX_ENV
RUN mix deps.compile

# build assets
COPY assets/package.json assets/package-lock.json ./assets/
RUN npm --prefix ./assets ci --progress=false --no-audit --loglevel=error

COPY priv priv
COPY assets assets
RUN npm run --prefix ./assets deploy
RUN mix phx.digest


# compile and build release
COPY lib lib
# uncomment COPY if rel/ exists
# COPY rel rel
RUN mix do compile, release


FROM debian:buster-slim AS app

RUN apk add --no-cache openssl ncurses-libs

WORKDIR /app

ARG MIX_ENV
ARG RELEASE_LEVEL

ENV LANG=C.UTF-8 LC_ALL=C.UTF-8

# Update timezone
ENV TZ=Asia/Singapore

# Exposes port to the host machine
EXPOSE 8080

# Install stable dependencies that don't change often
RUN apt-get update && \
  apt-get install -y --no-install-recommends \
  apt-utils \
  openssl \
  curl \
  wget && \
  rm -rf /var/lib/apt/lists/*


RUN chown nobody:nobody /app

USER nobody:nobody

COPY --from=build --chown=nobody:nobody /app/_build/${MIX_ENV}/rel/ghost_rider ./

ENV HOME=/app

CMD ["bin/ghost_rider", "start"]

fails with following error

Step 15/35 : RUN npm --prefix ./assets ci --progress=false --no-audit --loglevel=error
 ---> Running in 2b08ff3a7d3a
npm ERR! (intermediate value)(intermediate value)(intermediate value).then is not a function

npm ERR! A complete log of this run can be found in:
npm ERR!     /root/.npm/_logs/2020-12-02T02_23_33_826Z-debug.log
ERROR: Service 'ghost-rider' failed to build : The command '/bin/sh -c npm --prefix ./assets ci --progress=false --no-audit --loglevel=error' returned a non-zero code: 1

it works fine on the project via cli

npm --prefix ./assets ci --progress=false --no-audit --loglevel=error
.....
......
........
added 948 packages in 12.791s

deps

[
      {:phoenix, "~> 1.5.7"},
      {:phoenix_ecto, "~> 4.1"},
      {:ecto_sql, "~> 3.4"},
      {:ecto_psql_extras, "~> 0.2"},
      {:postgrex, ">= 0.0.0"},
      {:phoenix_html, "~> 2.11"},
      {:phoenix_live_reload, "~> 1.2", only: :dev},
      {:phoenix_live_dashboard, "~> 0.3 or ~> 0.2.9"},
      {:telemetry_metrics, "~> 0.4"},
      {:telemetry_poller, "~> 0.4"},
      {:gettext, "~> 0.11"},
      {:jason, "~> 1.0"},
      {:plug_cowboy, "~> 2.0"},
      {:finch, "~> 0.5.2"},
      {:recaptcha, "~> 3.0"},
      {:ink, "~> 1.0"},
      {:credo, "~> 1.5", only: [:dev, :test], runtime: false},
      {:sentry, "8.0.3"},
      {:hackney, "~> 1.8"}
    ]
# https://elixirforum.com/t/could-use-some-feedback-on-this-multistage-dockerfile-1st-elixir-phoenix-deployment/30862/10?

########################
### Dependency stage ###
########################
FROM hexpm/elixir:1.11.2-erlang-23.1.3-debian-buster-20201012 AS deps

# install build dependencies
RUN apt-get -qq update && \
    apt-get -qq -y install build-essential npm git python --fix-missing --no-install-recommends


# prepare build dir
WORKDIR /app

ARG MIX_ENV
ARG RELEASE_LEVEL

ENV LANG=C.UTF-8 LC_ALL=C.UTF-8

# Update timezone
ENV TZ=Asia/Singapore

# install hex + rebar
RUN mix local.hex --force && \
    mix local.rebar --force

# set build ENV
ENV MIX_ENV=${MIX_ENV}
ENV RELEASE_LEVEL=${RELEASE_LEVEL}

COPY mix.exs mix.lock ./
COPY config config

# install mix dependencies
RUN mix deps.get --only ${MIX_ENV}
RUN mix deps.compile



########################
# Build Phoenix assets #
########################
# Using stretch for now because it includes Python
# Otherwise you get errors, could use a smaller image though
FROM node:14.15.1-stretch AS assets
WORKDIR /app/assets

COPY --from=deps /app/deps /app/deps/
COPY assets/package.json assets/package-lock.json ./
RUN npm ci --progress=false --no-audit --loglevel=error

COPY priv ./
COPY assets/ ./

RUN npm run deploy

#########################
# Create Phoenix digest #
#########################
FROM deps AS digest
COPY --from=assets /app/priv ./priv
RUN mix phx.digest

#######################
#### Create release ###
#######################
FROM digest AS release
ARG MIX_ENV
ENV MIX_ENV=${MIX_ENV}
COPY lib ./lib
RUN mix do compile, release

#################################################
# Create the actual image that will be deployed #
#################################################
FROM debian:buster-slim AS deploy

# Install stable dependencies that don't change often
RUN apt-get update && \
  apt-get install -y --no-install-recommends \
  apt-utils \
  openssl \
  curl \
  wget && \
  rm -rf /var/lib/apt/lists/*


# Set WORKDIR after setting user to nobody so it automatically gets the right permissions
# When the app starts it will need to be able to create a tmp directory in /app
WORKDIR /app

ARG MIX_ENV
ARG RELEASE_LEVEL

ENV MIX_ENV=${MIX_ENV}
ENV RELEASE_LEVEL=${RELEASE_LEVEL}

ENV LANG=C.UTF-8 LC_ALL=C.UTF-8

# Update timezone
ENV TZ=Asia/Singapore

COPY --from=release /app/_build/${MIX_ENV}/rel/ghost_rider ./

ENV HOME=/app

# Exposes port to the host machine
EXPOSE 8080

CMD ["bin/ghost_rider", "start"]

got the build to work following

Could use some feedback on this multistage dockerfile (1st elixir/phoenix deployment)?

but seems that doesn’t take priv into account and have missing files for tailwind. any examples docker file that uses tailwind with phoenix ?

Haven’t tried your docker image so maybe I’m wrong.

I often find myself using too new nodejs and npm. Nodejs 10 is usually fine, but Nodejs 12 is often no good.

Thanks for sharing your input

got it to work finally with some changes :grin:

# https://elixirforum.com/t/could-use-some-feedback-on-this-multistage-dockerfile-1st-elixir-phoenix-deployment/30862/10?

########################
### Dependency stage ###
########################
FROM hexpm/elixir:1.11.2-erlang-23.1.3-debian-buster-20201012 AS deps

# install build dependencies
RUN apt-get -qq update && \
    apt-get -qq -y install build-essential npm git python --fix-missing --no-install-recommends


# prepare build dir
WORKDIR /app

ARG MIX_ENV
ARG RELEASE_LEVEL

ENV LANG=C.UTF-8 LC_ALL=C.UTF-8

# Update timezone
ENV TZ=Asia/Singapore

# install hex + rebar
RUN mix local.hex --force && \
    mix local.rebar --force

# set build ENV
ENV MIX_ENV=${MIX_ENV}
ENV RELEASE_LEVEL=${RELEASE_LEVEL}

COPY mix.exs mix.lock ./
COPY config config

# install mix dependencies
RUN mix deps.get --only ${MIX_ENV}
RUN mix deps.compile



########################
# Build Phoenix assets #
########################
# Using stretch for now because it includes Python
# Otherwise you get errors, could use a smaller image though
FROM node:14.15.1-stretch AS assets
WORKDIR /app/assets

COPY --from=deps /app/deps /app/deps/
COPY assets/package.json assets/package-lock.json ./
RUN npm ci --progress=false --no-audit --loglevel=error

COPY assets/ ./

RUN npm run deploy

#########################
# Create Phoenix digest #
#########################
FROM deps AS digest
COPY priv priv
RUN mix phx.digest

#######################
#### Create release ###
#######################
FROM digest AS release
ARG MIX_ENV
ENV MIX_ENV=${MIX_ENV}
COPY lib ./lib
RUN mix do compile, release

#################################################
# Create the actual image that will be deployed #
#################################################
FROM debian:buster-slim AS deploy

# Install stable dependencies that don't change often
RUN apt-get update && \
  apt-get install -y --no-install-recommends \
  apt-utils \
  openssl \
  curl \
  wget && \
  rm -rf /var/lib/apt/lists/*


# Set WORKDIR after setting user to nobody so it automatically gets the right permissions
# When the app starts it will need to be able to create a tmp directory in /app
WORKDIR /app

ARG MIX_ENV
ARG RELEASE_LEVEL

ENV MIX_ENV=${MIX_ENV}
ENV RELEASE_LEVEL=${RELEASE_LEVEL}

ENV LANG=C.UTF-8 LC_ALL=C.UTF-8

# Update timezone
ENV TZ=Asia/Singapore

COPY --from=release /app/_build/${MIX_ENV}/rel/ghost_rider ./

ENV HOME=/app

# Exposes port to the host machine
EXPOSE 8080

CMD ["bin/ghost_rider", "start"]

I will try to submit to the official hex docs for deployment as the recipe there is incomplete in my view and not so convenient for 1st time users of phoenix

1 Like