Astolfo
Use alpine for phx.gen.release --docker
When generating a release with phx.gen.release --docker a debian version is used by default to avoid “DNS issues” on Alpine.
It seems like the mentioned issues have been resolved in Alpine 3.18:
- DNS because of musl/Alpine base? · Issue #138 · nicolaka/netshoot · GitHub
- Debugging DNS Resolution | Kubernetes
Because Alpine images are much smaller, and as far as I’m aware have fewer vulnerabilities.
I suggest either switching to alpine by default or adding an option to generate Dockerfile that uses alpine as a base image (like phx.gen.release --docker --alpine).
If the community agrees, I can work on a pull request.
Thank you,
Anna
Most Liked
LostKobrakai
While DNS might have been a truely blocking issue I still wouldn’t call alpine a great option for a default. People will eventually add a NIF based dependency where runing musl has a high likelyhood of breaking things.
Personally I also don’t understand the obsession with image size given docker caching that stuff anyways.
mwilsoncoding
I originally agreed that it would be nice to have options in the generator to customize the variant. My work asks me to ship alpine images where possible, so it’s a frequent concern.
For example, the following could explicitly generate the current state/default:
mix phx.gen.release \
--docker \
--elixir-version='1.18.3' \
--otp-version='27.3' \
--variant=debian \
--variant-version='bullseye-20250317-slim'
--variant could specify the OS variant to base your build/run on and --variant-version its version.
Then again, it seemed easy enough to tweak the default Dockerfile to support all three OS options. But with this solution, I’m back to not needing new options in the generator.
Only 2 meaningful changes. First toward the top:
...
ARG VARIANT=debian
ARG VARIANT_VERSION=bullseye-20250317-slim
ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-${VARIANT}-${VARIANT_VERSION}"
ARG RUNNER_IMAGE="${VARIANT}:${VARIANT_VERSION}"
FROM ${BUILDER_IMAGE} AS builder
ARG VARIANT
# install build dependencies
RUN case "${VARIANT}" in \
"debian" | "ubuntu") \
apt-get update -y && apt-get install -y build-essential git \
&& apt-get clean && rm -f /var/lib/apt/lists/*_* \
;; \
"alpine") \
apk add --no-cache build-base git \
;; \
*) \
echo "Unsupported variant: ${VARIANT}" && exit 1 \
;; \
esac
...
Here, we:
- introduce the
VARIANTbuild arg - switch
DEBIAN_VERSIONtoVARIANT_VERSION - switch
debianto${VARIANT} RUNacasestatement to toggle OS package manager setup commands based on the value ofVARIANT
Then toward the end of the file:
...
FROM ${RUNNER_IMAGE}
ARG VARIANT
RUN case "${VARIANT}" in \
"debian" | "ubuntu") \
apt-get update -y && apt-get install -y libstdc++6 openssl libncurses5 locales ca-certificates \
&& apt-get clean && rm -f /var/lib/apt/lists/*_* \
;; \
"alpine") \
apk add --no-cache libstdc++ openssl ncurses-dev musl-locales musl-locales-lang ca-certificates \
;; \
*) \
echo "Unsupported variant: ${VARIANT}" && exit 1 \
;; \
esac
# Set the locale
ENV MUSL_LOCPATH="/usr/share/i18n/locales/musl"
RUN if [ "${VARIANT}" = "debian" ] || [ "${VARIANT}" = "ubuntu" ]; then \
unset MUSL_LOCPATH && sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen ; \
fi
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
...
Here, we:
- use the same
casestrategy to set up OS deps on the runner image - finish out alpine locale setup by assuming an alpine build and setting
MUSL_LOCPATH - if not alpine, unset
MUSL_LOCPATHand perform remaining locale setup command for ubuntu/debian
I’ve adapted the above solution from this post for setting up the locale in alpine. Tho this post directed me to musl-locales-lang over lang.
To get the various image types:
docker build \
-t my-ubuntu-app \
--build-arg VARIANT=ubuntu \
--build-arg VARIANT_VERSION=focal-20241011 \
.
docker build \
-t my-debian-app \
--build-arg VARIANT=debian \
--build-arg VARIANT_VERSION=buster-20240612 \
.
docker build \
-t my-alpine-app \
--build-arg VARIANT=alpine \
--build-arg VARIANT_VERSION=3.21.3 \
.
Available options for VARIANT and VARIANT_VERSION were found by browsing the available tags on Dockerhub.
Your mileage may vary, but this at least works for me on a freshly generated LiveView app using Elixir 1.18.3 on OTP 27.3.
Astolfo
There are many reasons to prefer smaller images:
- Faster build times
- Deployments in constrained environments
- Smaller surface area for vulnerabilities, for example debian:12-slim vs alpine:latest (base images). This problem with debian docker images and phoenix was also mentioned here
Are you sure there are that many popular libraries that don’t work with musl? Could you provide some examples?
Popular in Proposals: Ideas
Other popular 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
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex









