Usually if you are doing a multi stage build it works best to just go ahead and build a release in the base image and then you just copy that into the runtime image. Then the runtime image can be way smaller.
I would suggest not going the multi-stage build route for local development. For releases it is definitely a good route to go down (and I also recently published a post on this recently here if you are interested: https://akoutmos.com/post/multipart-docker-and-elixir-1.9-releases/)
Given that your dependencies can/will change over time, maintaining a separate base image in my opinion will just lead to headaches across the team (people having out of date images, images needing to be updated every time there is a new dep/version, etc).
My current workflow (both for work and personal) is to have a docker-compose stack with my elixir service based on elixir:1.8.2 (or whatever version you are on), along with postgres and any other services i require. I then leverage named volumes (https://docs.docker.com/compose/compose-file/#short-syntax-3) so that every time I spin the container up, all the deps/build stuff is persisted from the last time the container ran.
This way everyone on the team has the same container versions, no need to introduce any additional CI/CD steps for deploying new images to the registry and what not. It is also fast and productive. I can usually have my whole stack up and running locally in under a minute.
Thanks, I will explore volumes for deps. Although my idea with multi stages was supposed to take care about deps and libs. It would compile them in base, but then still run mix deps.get and compile in the next stage when you start it. So if mix.exs hasn’t changed - nothing would be done. But if you added anything new, it would add and compile only that.
But regardless, now I’m just curious why copying deps from base image didn’t work.
Why even have a multistage build I guess is the question I have? Why not just base your container off of FROM registry.gitlab.com/username/project_name/base:latest? Seems like an extra step of indirection which doesn’t net you anything.
Personally I use them in Phoenix (for development at least) for Webpack. I have a stage in my Dockerfile that does nothing but install Node and build assets. Then in a 2nd stage that sets up Elixir / Phoenix / mix, etc. I copy in the compiled assets into a folder.
Then I run a dedicated webpack service in Docker Compose but only in development (using an override file).
Haven’t deployed anything yet but I imagine once I tackle that, I’ll end up moving the webpack stage to nginx and also set up a 2nd stage for Elixir releases to base as my final prod image.
That comment was aimed more at the OPs code sample where they used the registry image as a base, and then immediatly started the next stage:
FROM registry.gitlab.com/username/project_name/base:latest as base
FROM elixir:1.8-otp-22-alpine
For your case that sounds like a good solution as installing node+elixir in the same container can be annoying to do. When doing frontend work, I usually have 2 containers running, 1 for Elixir app and 1 for the JS app. Each container will then have read only access to the host filesystem (to the files that are relevant for each) and then kick off rebuilds as files change. At that point it is only a matter of setting up CORS correctly on the Phoenix app and my Vue SPA can communicate with my Phoenix API.
Ah cool. Things are much different now than that repo (using a single multi-stage build instead of 2x Dockerfiles). I was going to update it once I get deployment covered.
This caused problems with my VSCode + ElixirLS extention. It could not find the deps location and highlighted the whole mix.exs file red. I tried to write the deps and _build to the original default location, but that causes problems apparently.
Weird. I tried VSCode, ElixirLS and remote containers and everything was found with the custom paths using that exact Docker set up. Autocomplete worked, linting worked, etc… It was pretty sweet.
When I used VSCode I only ever ran insiders. I’m not sure if it’s available in the stable release, but honestly, insiders was quite stable. I used it for like 6 months for hardcore every day development and it never crashed once.