mikl

mikl

How to copy dependencies from outside Docker image build?

I have a multi-step Gitlab CI pipeline, where I’m trying to avoid downloading Hex dependencies multiple times, but I’m struggling with the step where the Docker image is built.

In previous steps, I set MIX_HOME to a _mix folder inside the build structure, to be able to cache it with Gitlab CI cache and to pass it and the _build and deps folders around for use by separate lint and test steps. That works fine, but when I try to re-use said folders for the step that builds a Docker image, it doesn’t work as expected. The relevant parts of my Dockerfile:

FROM hexpm/elixir:1.15.4-erlang-26.0.2-debian-bookworm-20230612-slim AS build

# install build dependencies
RUN apt update -y && apt install -y build-essential curl git

# prepare build dir
WORKDIR /app

# set build ENV
ENV MIX_ENV=prod
ENV MIX_HOME=/app/_mix

# copy Mix dependencies from previous step
COPY _build _mix deps mix.exs mix.lock /app/
COPY config config

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

RUN mix deps.compile

COPY priv priv
COPY assets assets
COPY lib lib
RUN mix compile

However, despite copying both _build, deps and the MIX_HOME folder, when Docker reaches the mix compile step here, it errors:

Unchecked dependencies for environment prod:
* telemetry_metrics (Hex package)
  the dependency is not available, run "mix deps.get"
* phoenix_live_view (Hex package)
  the dependency is not available, run "mix deps.get"
[and so on for every package]

Shouldn’t it be finding the packages, since I’ve copied over the deps folder?

I’ve also tried running RUN mix compile --no-deps-check instead, but that just throws different errors like module Ecto.Query is not loaded and could not be found.. So Elixir is truly unable to find said modules.

It seems that copying the aforementioned folders into the Docker environment should work, so what am I missing here?

Most Liked

w0rd-driven

w0rd-driven

It’s probably not worth mentioning now but your cache key being static would mean every build that uses marsvin_mix_install would try to share the same cache. That’s every commit on every branch.

I use the variable $CI_COMMIT_REF_NAME which creates a cache for each branch. A good visual primer is A visual guide to GitLab CI/CD caching to understand the various strategies. A single key may be fine if you don’t branch at all since I think later commits drop earlier jobs.

You can also do print debugging by adding RUN ls -al cache/directory to output contents in the logs. Its hacky as hell and there may be better approaches like setting up a runner locally. You could also do stuff like that in the .gitlab-ci.yml script or before script sections.

spaceCowboy

spaceCowboy

Just reviewing your .gitlab-ci.yml. In marsvin_build you have both needs: and dependencies: . This might work just fine, but Gitlab recommends not having both in the same layer: CI/CD YAML syntax reference | GitLab Docs, as one relies on current stage, and the other relies on previous build stage. IDK if that changes anything, but thanks for sharing your scripts.

mikl

mikl

Yeah, I have a previous step looking like this:

.marsvin:
  image: hexpm/elixir:1.15.4-erlang-26.0.2-debian-bookworm-20230612-slim
  variables:
    MIX_ENV: "test"
    # To have hex and rebar included in cache/artifacts, put MIX_HOME inside
    # the build root.
    MIX_HOME: "${CI_PROJECT_DIR}/packages/marsvin/_mix"

marsvin_mix_install:
  extends: .marsvin
  stage: init
  needs: []
  dependencies: []
  cache:
    key: "marsvin_mix_install"
    paths:
      - packages/marsvin/_mix
      - packages/marsvin/_build
      - packages/marsvin/deps
  before_script:
    - cd packages/marsvin
    - mix local.hex --force --if-missing
    - mix local.rebar --force --if-missing
  script:
    - mix deps.get
    - mix deps.clean --unused
    - mix compile --warnings-as-errors
  artifacts:
    paths:
      - packages/marsvin/_mix
      - packages/marsvin/_build
      - packages/marsvin/deps
    expire_in: 7 days

The exported artifacts are then used in the build step, like this:

marsvin_build:
  extends: .marsvin
  stage: build
  needs:
    - "marsvin_mix_install"
    - "marsvin_mix_test"
  dependencies: ["marsvin_mix_install"]
  image: ${BUILDKIT_IMAGE}
  variables:
    APP_VERSION: "${APP_VERSION}"
    IMAGE_URL_INTERNAL: "${DOCKER_REGISTRY_INTERNAL}/${DOCKER_NS_INT}/marsvin"
  script:
    - cd packages/marsvin
    - ${BUILDKIT_SCRIPT}
      --tag=${IMAGE_URL_INTERNAL}:${IMAGE_VERSION}
      --cache-repo=${IMAGE_URL_INTERNAL}:cache
      --context=.
      --file=Dockerfile

Yeah, I only added that to try to solve aforementioned problem, does not appear to make a difference anyway.

Where Next?

Popular in Questions Top

hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New

Other popular topics Top

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
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New

We're in Beta

About us Mission Statement