From daa488634db80db03ff88b92e1ff2088e09c20cc Mon Sep 17 00:00:00 2001 From: Kevin Avignon <6740474+Kavignon@users.noreply.github.com> Date: Sun, 26 Jan 2025 12:22:39 -0500 Subject: [PATCH 1/3] Added dockerignore. --- .dockerignore | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..e829f31 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,13 @@ +# Ignore files and directories that aren't needed in the container +.git +_build +deps +node_modules +test +*.md +docker-compose.* +.env + +# Allow mix.exs and mix.lock explicitly +!mix.exs +!mix.lock From e045a81db58e5a63c93749ce6b76253098ae6554 Mon Sep 17 00:00:00 2001 From: Kevin Avignon <6740474+Kavignon@users.noreply.github.com> Date: Sun, 26 Jan 2025 12:27:44 -0500 Subject: [PATCH 2/3] Add multi-stage Docker build for Phoenix application. The docker container for production is being built in 3 stages. The Node build installs the dependencies set in app/assets , copies what's in the assets folder and runs esbuild to bundle + minify static files. The Elixir build stage installs Hex and Rebar, fetches + compiles dependencies for production, copies compiled assets from the Node build stage and runs The Distroless runtime stage copies the compiled production binaries in the Elixir stage into a minimal Distroless image (very lean Unix runtime to reduce attack opportunities), sets the working directory to /app and starts the Phoenix server. --- Dockerfile.prod | 36 ++++++++++++++++++++++++++++++++++++ assets/package.json | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 Dockerfile.prod diff --git a/Dockerfile.prod b/Dockerfile.prod new file mode 100644 index 0000000..c9ebc08 --- /dev/null +++ b/Dockerfile.prod @@ -0,0 +1,36 @@ +FROM node:20-slim AS node-build + +WORKDIR /app/assets + +# 1. Copy package.json and lock file, then install dependencies +COPY assets/package.json assets/package-lock.json ./ +RUN npm install + +# 2. Copy all other assets (including vendor/topbar.js) +COPY assets/ ./ + +# 3. Build static assets +RUN npx esbuild js/app.js --bundle --minify --sourcemap --outdir=../priv/static/assets + +# Stage 2: Elixir Build Stage +FROM elixir:1.18-otp-27-alpine AS build + +RUN apk add --no-cache build-base git npm bash curl +WORKDIR /app +RUN mix local.hex --force && mix local.rebar --force +COPY mix.exs mix.lock ./ +RUN mix deps.get --only prod +COPY . . +RUN mix deps.compile +# Copy built assets from Node.js stage +COPY --from=node-build /app/assets ../priv/static/assets +RUN mix phx.digest + +# Stage 3: Minimal Runtime Container +FROM gcr.io/distroless/base-debian11:latest + +WORKDIR /app +COPY --from=build /app/_build/prod/rel/slax ./ +USER nobody:nogroup +EXPOSE 4000 +CMD ["bin/slax", "start"] diff --git a/assets/package.json b/assets/package.json index 2365b63..b2bccb7 100644 --- a/assets/package.json +++ b/assets/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "main": "tailwind.config.js", "scripts": { - "deploy": "esbuild app.js --bundle --minify --sourcemap --outdir=../priv/static/assets", + "deploy": "esbuild js/app.js --bundle --minify --sourcemap --outdir=../priv/static/assets", "watch": "esbuild app.js --bundle --watch --sourcemap --outdir=../priv/static/assets" }, "keywords": [], From 4f21d029d4ee6b564699356d1eec7070a03c9b80 Mon Sep 17 00:00:00 2001 From: Kevin Avignon <6740474+Kavignon@users.noreply.github.com> Date: Sun, 26 Jan 2025 14:10:24 -0500 Subject: [PATCH 3/3] Updating binaries for esbuild. --- Dockerfile.prod | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Dockerfile.prod b/Dockerfile.prod index c9ebc08..8f21aff 100644 --- a/Dockerfile.prod +++ b/Dockerfile.prod @@ -4,13 +4,15 @@ WORKDIR /app/assets # 1. Copy package.json and lock file, then install dependencies COPY assets/package.json assets/package-lock.json ./ -RUN npm install + +# Install dependencies including esbuild for the correct platform +RUN npm install --force && npm install esbuild-linux-64 --force # 2. Copy all other assets (including vendor/topbar.js) COPY assets/ ./ -# 3. Build static assets -RUN npx esbuild js/app.js --bundle --minify --sourcemap --outdir=../priv/static/assets +# 3. Build static assets using the correct binary +RUN npx esbuild-linux-64 js/app.js --bundle --minify --sourcemap --outdir=../priv/static/assets # Stage 2: Elixir Build Stage FROM elixir:1.18-otp-27-alpine AS build