otijhuis
Hi,
I’m currently building an app prototype in Phoenix 1.5 and I want to run it in a local kubernetes cluster (k3d multi node cluster with prometheus/grafana/loki) to try some different scenarios. Considering this is the first time I’m deploying a phoenix app I’d love some feedback.
I have enabled docker buildkit. This makes the builds a lot faster considering docker then does a lot of things in parallel. It also makes it possible to use the cache mount (with the experimental syntax enabled).
I also followed the Phoenix releases guide. I can pass in the SECRET_KEY_BASE when I run the image. I also set the option for the release to only create unix executables.
It’s basically a fresh Phoenix 1.5 install I tested this on. The final image is just 22.9MB. It seems to run perfectly fine.
Is there anything else I have to pay attention to? Other packages I might need at runtime?
# syntax=docker/dockerfile:experimental
FROM hexpm/elixir:1.10.2-erlang-22.3.2-alpine-3.11.3 AS deps
WORKDIR /app
COPY lib ./lib
COPY config ./config
COPY mix.exs .
COPY mix.lock .
ENV MIX_ENV prod
RUN mix do \
local.rebar --force,\
local.hex --force,\
deps.get --only prod
# Build Phoenix assets
# Using stretch for now because it includes Python
# Otherwise you get errors, could use a smaller image though
FROM node:13.13.0-stretch AS assets
WORKDIR /app
COPY assets/package*.json ./assets/
COPY --from=deps /app/deps ./deps
RUN --mount=type=cache,target=/root/.npm,sharing=locked \
npm --prefer-offline --no-audit --progress=false \
--loglevel=error --prefix ./assets ci
COPY assets/ ./assets
RUN npm run --prefix ./assets deploy
# Phoenix digest
FROM deps AS digest
COPY --from=assets /app/priv ./priv
RUN mix phx.digest
# Create release
FROM digest AS release
ENV MIX_ENV prod
RUN mix do compile, release
# Release
FROM alpine:3.11.3 as deploy
WORKDIR /app
RUN apk add --no-cache openssl ncurses-libs
COPY --from=release /app/_build ./_build
ENV SECRET_KEY_BASE=
EXPOSE 4000
ENTRYPOINT ["/app/_build/prod/rel/your_app/bin/your_app"]
CMD ["start"]
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex











Showing Posts 1 to 10- Show Best Posts
- Show All Posts (oldest first)
- Show All Posts (newest first)
tristan
You are using the
RUNmount cache option for npm but not formixorapk. You can improve those the same as npm by using local caches of their packages.Erlang and not Elixir but I discuss hex package caching and Alpine caching here: Docker | Adopting Erlang
qhwa
Wow, that’s impressive. You have a lot of good ideas already tried in the dockerfile, e.g.
npm ci,buildkitetc.There are some subtle things I think can make it better:
In this stage,
libis not necessary formix deps.get. This will save you a lot of time if you just modify codes in your side without touching any dependencies / configurations.In my builds, I copy them to some directory unrelated to the app, for example
/app. This can simplify your entrypoint path and make the Dockerfile more reusable.I would put this secret variable in a runtime configuration, e.g. aconfig/release.exs, without exposing it at build-time. For K8S, it’s usually stored in a cluster secret as origin.Sorry, please forget it, I made a mistake, it’s a
runtimevariable here.cnck1387
One minor improvement you could do is:
Replace:
With:
That should reduce your total layers by 1 and very slightly improve build speeds (probably won’t be noticeable but it’s still a small win).
otijhuis
@tristan thanks! Totally forgot about doing that for those as well. Unfortunately have had way too much node/angular experience lately. You definitely learn how to optimize though.
otijhuis
@qhwa ah nice, thx. I’ll check about moving the lib copy to another stage.
You can definitely do a lot with buildkit. For an angular build pipeline we use a multistage build as well. If you do tests / linter / compile checks in different stages that don’t depend on each other they will run in parallel. You just have to make sure another stage copies some output from those stages (even if those are empty files), otherwise buildkit just says “ah, you’re not using any output, I’ll skip the stages completely”.
@cnck1387 true. Thought about checking if those were the only 2 mix files but forgot. The difference will probably be tiny indeed.
tmjoen
Lots of great stuff here, thanks!
I’d be grateful if you could post the “finished” version here later
JovaniPink
When you are done .. you could think of sharing with the community Adding Solid Docker Compose Recipes.
otijhuis
@tmjoen / @JovaniPink sure thing! I found some other helpful info as well and will be trying to implement the changes this weekend. I’ll definitely post the final result.
otijhuis
Here’s the version I ended up with. I tried to document all the steps.
As a reference:
Intel NUC Skull Canyon (quadcore core i7 mobile processor)
Phoenix 1.5 project with liveview enabled, no ecto.
Tailwind CSS and prometheus telemetry reporter added.
Initial build time: 1m17sec
Rebuild after a code change with all layers cached: 5sec (tested by changing one of the metrics in telemetry.ex)
Final image size: 19.7Mb (19.1 without openssl)
edit: @JovaniPink you’re free to use this example any way you like. I won’t be using docker compose myself. I prefer to use a local kubernetes cluster to get more kubernetes experience (trying k3d at the moment). But I’ll try to make notes about the things I run into and share them later on.
cnck1387
You may want to
chmod +xthe entrypoint script so it’s guaranteed to be executable in case you end up in a situation where the file system building the image loses it.