Files
firezone/elixir/Dockerfile
Jamil 61534f92b0 refactor(elixir): remove telemetry id generation (#5084) (#5095)
Feel free to correct me if I'm wrong but it seems the telemetry id is
not longer used in Firezone 1.x
Removing this uuid generation would allow me to put the folder
`/var/firezone` as readonly instead of mounting a

[volume](367a46a5c8/firezone/values.yaml (L157))
to allow firezone to write inside. The folder `/var/firezone` seems to
be used only for this purpose

Maybe I should also remove

[this](49a965a686/elixir/Dockerfile (L293))
?

PS: I cannot find the contrib branch, but don't hesite to create it and
change the target branch of this PR

Co-authored-by: Antoine <antoinelabarussias@gmail.com>
2024-05-22 12:59:36 -07:00

321 lines
9.7 KiB
Docker

ARG ALPINE_VERSION="3.19.1"
ARG ERLANG_VERSION="26.2.2"
ARG ERLANG_DOWNLOAD_SHA256="d537ff4ac5d8c1cb507aedaf7198fc1f155ea8aa65a8d83edb35c2802763cc28"
ARG ELIXIR_VERSION="1.16.2"
ARG ELIXIR_DOWNLOAD_SHA256="f53d06f3e4041c50e65b750e5d56fec9cc7c6a44510786937c6a5bb0666a7207"
FROM alpine:${ALPINE_VERSION} as base
# Important! Update this no-op ENV variable when this Dockerfile
# is updated with the current date. It will force refresh of all
# of the base images and things like `apk add` won't be using
# old cached versions when the Dockerfile is built.
ENV REFRESHED_AT=2023-10-05 \
LANG=C.UTF-8 \
HOME=/app/ \
TERM=xterm
# Add tagged repos as well as the edge repo so that we can selectively install edge packages
ARG ALPINE_VERSION
RUN set -xe \
&& ALPINE_MINOR_VERSION=$(echo ${ALPINE_VERSION} | cut -d'.' -f1,2) \
&& echo "@main http://dl-cdn.alpinelinux.org/alpine/v${ALPINE_MINOR_VERSION}/main" >> /etc/apk/repositories \
&& echo "@community http://dl-cdn.alpinelinux.org/alpine/v${ALPINE_MINOR_VERSION}/community" >> /etc/apk/repositories \
&& echo "@edge http://dl-cdn.alpinelinux.org/alpine/edge/main" >> /etc/apk/repositories
RUN set -xe \
# Upgrade Alpine and base packages
&& apk --no-cache --update-cache --available upgrade \
# Install bash, Erlang/OTP and Elixir runtime dependencies
&& apk add --no-cache --update-cache \
bash \
libstdc++ \
ca-certificates \
ncurses \
openssl \
pcre \
unixodbc \
zlib \
# Update ca certificates
&& update-ca-certificates --fresh
FROM base AS build_erlang
# Install bash and Erlang/OTP deps
RUN set -xe \
&& apk add --no-cache --update-cache --virtual .fetch-deps \
curl \
libgcc \
lksctp-tools \
zlib-dev
# Install Erlang/OTP build deps
RUN set -xe \
&& apk add --no-cache --virtual .build-deps \
dpkg-dev \
dpkg \
gcc \
g++ \
libc-dev \
linux-headers \
make \
autoconf \
ncurses-dev \
openssl-dev \
unixodbc-dev \
lksctp-tools-dev \
tar
# Download OTP
ARG ERLANG_VERSION
ARG ERLANG_DOWNLOAD_SHA256
WORKDIR /tmp/erlang-build
RUN set -xe \
&& curl -fSL -o otp-src.tar.gz "https://github.com/erlang/otp/releases/download/OTP-${ERLANG_VERSION}/otp_src_${ERLANG_VERSION}.tar.gz" \
&& tar -xzf otp-src.tar.gz -C /tmp/erlang-build --strip-components=1 \
# && sha256sum otp-src.tar.gz && exit 1 \
&& echo "${ERLANG_DOWNLOAD_SHA256} otp-src.tar.gz" | sha256sum -c -
# Configure & Build
RUN set -xe \
&& export ERL_TOP=/tmp/erlang-build \
&& export CPPFLAGS="-D_BSD_SOURCE $CPPFLAGS" \
&& export gnuArch="$(dpkg-architecture --query DEB_HOST_GNU_TYPE)" \
&& ./configure \
--build="$gnuArch" \
--prefix=/usr/local \
--sysconfdir=/etc \
--mandir=/usr/share/man \
--infodir=/usr/share/info \
--without-javac \
--without-jinterface \
--without-wx \
--without-debugger \
--without-observer \
--without-cosEvent \
--without-cosEventDomain \
--without-cosFileTransfer \
--without-cosNotification \
--without-cosProperty \
--without-cosTime \
--without-cosTransactions \
--without-et \
--without-gs \
--without-ic \
--without-megaco \
--without-orber \
--without-percept \
--without-odbc \
--without-typer \
--enable-threads \
--enable-shared-zlib \
--enable-dynamic-ssl-lib \
--enable-ssl=dynamic-ssl-lib \
$(if [[ "${TARGET}" != *"amd64"* ]]; then echo "--disable-jit"; fi) \
&& $( \
if [[ "${TARGETARCH}" == *"amd64"* ]]; \
then export CFLAGS="-g -O2 -fstack-clash-protection -fcf-protection=full"; \
else export CFLAGS="-g -O2 -fstack-clash-protection"; fi \
) \
&& make -j$(getconf _NPROCESSORS_ONLN)
# Install to temporary location, strip the install, install runtime deps and copy to the final location
RUN set -xe \
&& make DESTDIR=/tmp install \
&& cd /tmp && rm -rf /tmp/erlang-build \
&& find /tmp/usr/local -regex '/tmp/usr/local/lib/erlang/\(lib/\|erts-\).*/\(man\|doc\|obj\|c_src\|emacs\|info\|examples\)' | xargs rm -rf \
&& find /tmp/usr/local -name src | xargs -r find | grep -v '\.hrl$' | xargs rm -v || true \
&& find /tmp/usr/local -name src | xargs -r find | xargs rmdir -vp || true \
# Strip install to reduce size
&& scanelf --nobanner -E ET_EXEC -BF '%F' --recursive /tmp/usr/local | xargs -r strip --strip-all \
&& scanelf --nobanner -E ET_DYN -BF '%F' --recursive /tmp/usr/local | xargs -r strip --strip-unneeded \
&& runDeps="$( \
scanelf --needed --nobanner --format '%n#p' --recursive /tmp/usr/local \
| tr ',' '\n' \
| sort -u \
| awk 'system("[ -e /tmp/usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
)" \
&& ln -s /tmp/usr/local/lib/erlang /usr/local/lib/erlang \
&& /tmp/usr/local/bin/erl -eval "beam_lib:strip_release('/tmp/usr/local/lib/erlang/lib')" -s init stop > /dev/null \
&& (/usr/bin/strip /tmp/usr/local/lib/erlang/erts-*/bin/* || true) \
&& apk add --no-cache --virtual .erlang-runtime-deps $runDeps lksctp-tools ca-certificates
# Cleanup after Erlang install
RUN set -xe \
&& apk del .fetch-deps .build-deps \
&& rm -rf /var/cache/apk/*
WORKDIR ${HOME}
CMD ["erl"]
FROM base AS build_elixir
# Install Elixir build deps
RUN set -xe \
&& apk add --no-cache --virtual .build-deps \
make \
curl \
tar \
git
# Download Elixir
ARG ELIXIR_VERSION
ARG ELIXIR_DOWNLOAD_SHA256
WORKDIR /tmp/elixir-build
RUN set -xe \
&& curl -fSL -o elixir-src.tar.gz "https://github.com/elixir-lang/elixir/archive/refs/tags/v${ELIXIR_VERSION}.tar.gz" \
&& mkdir -p /tmp/usr/local/src/elixir \
&& tar -xzC /tmp/usr/local/src/elixir --strip-components=1 -f elixir-src.tar.gz \
# && sha256sum elixir-src.tar.gz && exit 1 \
&& echo "${ELIXIR_DOWNLOAD_SHA256} elixir-src.tar.gz" | sha256sum -c - \
&& rm elixir-src.tar.gz
COPY --from=build_erlang /tmp/usr/local /usr/local
# Compile Elixir
RUN set -xe \
&& cd /tmp/usr/local/src/elixir \
&& make DESTDIR=/tmp install clean \
&& find /tmp/usr/local/src/elixir/ -type f -not -regex "/tmp/usr/local/src/elixir/lib/[^\/]*/lib.*" -exec rm -rf {} + \
&& find /tmp/usr/local/src/elixir/ -type d -depth -empty -delete \
&& rm -rf /tmp/elixir-build \
&& apk del .build-deps
# Cleanup apk cache
RUN rm -rf /var/cache/apk/*
WORKDIR ${HOME}
CMD ["iex"]
FROM base as elixir
WORKDIR ${HOME}
# Copy Erlang/OTP and Elixir installations
COPY --from=build_erlang /tmp/usr/local /usr/local
COPY --from=build_elixir /tmp/usr/local /usr/local
# Install hex + rebar
RUN set -xe \
&& mix local.hex --force \
&& mix local.rebar --force
CMD ["bash"]
FROM elixir as compiler
WORKDIR /app
# Install build deps
RUN apk add --update --no-cache \
make \
git \
nodejs \
npm \
build-base
# Add pnpm
RUN npm i -g pnpm
# Copy only the files needed to fetch the dependencies,
# to leverage Docker layer cache for them
RUN echo "0.0.0" > VERSION
COPY mix.exs mix.lock ./
COPY apps/domain/mix.exs ./apps/domain/mix.exs
COPY apps/web/mix.exs ./apps/web/mix.exs
COPY apps/api/mix.exs ./apps/api/mix.exs
COPY config config
# Fetch and compile the dependencies
ARG MIX_ENV="prod"
RUN mix deps.get --only ${MIX_ENV}
RUN mix deps.compile --skip-umbrella-children
# Copy the files needed to fetch asset deps
COPY apps/web/assets/package.json ./apps/web/assets/
COPY apps/web/assets/pnpm-lock.yaml ./apps/web/assets/
# Install npm deps and assets pipeline
RUN cd apps/web \
&& mix assets.setup
# Tailwind needs assets and app directories to look for used classes,
# so we can't optimize further at this stage
COPY VERSION ./
COPY priv priv
COPY apps apps
# Install pipeline and compile assets for Web app
RUN cd apps/web \
&& mix assets.deploy
# Copy the rest of the application files and compile them
RUN mix compile
FROM elixir as builder
# Install build deps
RUN apk add --update --no-cache \
git
WORKDIR /app
# Copy the compiled dependencies from the previous step
# leveraging the possible layer cache
COPY --from=compiler /app /app
COPY rel rel
ARG APPLICATION_NAME
ARG MIX_ENV="prod"
RUN mix release ${APPLICATION_NAME}
# start a new build stage so that the final image will only contain
# the compiled release and other runtime necessities
FROM base AS runtime
RUN set -xe \
# Install Firezone runtime deps
&& apk add --no-cache --update-cache \
curl \
tini
# Create default user and home directory, set owner to default
RUN set -xe \
&& mkdir -p /app \
&& adduser -s /bin/sh -u 1001 -G root -h /app -S -D default \
&& chown -R 1001:0 /app
WORKDIR /app
ARG APPLICATION_NAME
ENV APPLICATION_NAME=$APPLICATION_NAME
# Only copy the final release from the build stage
ARG MIX_ENV="prod"
COPY --from=builder /app/_build/${MIX_ENV}/rel/${APPLICATION_NAME} ./
# Change user to "default" to limit runtime privileges
USER default
# This is critical when you run this container in containers where
# running process would get a PID 1.
#
# BEAM is usually not started by itself but via some shell script (eg. the one generated by
# Elixir 1.9 releases or Distillery) and this script is not designed to become an init script
# for a Docker container and it DOES NOT reap zombie processes.
#
# So whenever a child process runs and terminates inside the same container it would result in memory and
# PID leak to a point where host VM would get unresponsive.
#
# A good example why you would start a process within container is the `ping` command for liveness probes.
# It starts a VM to issue an RPC command to a live node and then terminates, but would never be reaped.
#
# Tini would become an entrypoin script and would take care of zombie reaping no matter how you start the VM.
ENTRYPOINT ["/sbin/tini", "--"]
CMD bin/server