mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
On the domain side this PR extends `Domain.Repo` with filtering, pagination, and ordering, along with some convention changes are removing the code that is not needed since we have the filtering now. This required to touch pretty much all contexts and code, but I went through all public functions and added missing tests to make sure nothing will be broken. On the web side I've introduced a `<.live_table />` which is as close as possible to being a drop-in replacement for the regular `<.table />` (but requires to structure the LiveView module differently due to assigns anyways). I've updated all the listing tables to use it.
326 lines
9.8 KiB
Docker
326 lines
9.8 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
|
|
|
|
# Add other directories firezone needs to run
|
|
RUN set -xe \
|
|
&& mkdir -p /var/firezone \
|
|
&& chown -R 1001:0 /var/firezone
|
|
|
|
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
|