Optimize Docker image and reduce size

- Replace build-essential with specific packages (gcc, g++, make)
- Remove curl from both builder and runtime stages
- Remove Docker healthcheck (Kubernetes handles this)
- Consolidate file copying to reduce layers
- Remove redundant mkdir and chown commands
- Add comprehensive .dockerignore file

These changes reduce image size and build time significantly.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Graham McIntire 2025-07-26 16:07:37 -05:00
parent 4f5f26287a
commit 27ee859d3b
No known key found for this signature in database
2 changed files with 65 additions and 58 deletions

View file

@ -1,45 +1,57 @@
# This file excludes paths from the Docker build context.
#
# By default, Docker's build context includes all files (and folders) in the
# current directory. Even if a file isn't copied into the container it is still sent to
# the Docker daemon.
#
# There are multiple reasons to exclude files from the build context:
#
# 1. Prevent nested folders from being copied into the container (ex: exclude
# /assets/node_modules when copying /assets)
# 2. Reduce the size of the build context and improve build time (ex. /build, /deps, /doc)
# 3. Avoid sending files containing sensitive information
#
# More information on using .dockerignore is available here:
# https://docs.docker.com/engine/reference/builder/#dockerignore-file
# Version control
.git/
.github/
.gitignore
.dockerignore
# Dependencies
deps/
_build/
.elixir_ls/
# Ignore git, but keep git HEAD and refs to access current commit hash if needed:
#
# $ cat .git/HEAD | awk '{print ".git/"$2}' | xargs cat
# d0b8727759e1e0e7aa3d41707d12376e373d5ecc
.git
!.git/HEAD
!.git/refs
# Development files
.DS_Store
*.iml
.idea/
.vscode/
*.swp
*.swo
*~
# Common development/test artifacts
/cover/
/doc/
/test/
/tmp/
.elixir_ls
# Test files
test/
coveralls.json
cover/
# Mix artifacts
/_build/
/deps/
# Documentation
docs/
README.md
CLAUDE.md
*.md
# Temporary files
*.log
tmp/
temp/
# Build artifacts
erl_crash.dump
*.ez
# Generated on crash by the VM
erl_crash.dump
# Phoenix specific
priv/static/assets/
priv/static/cache_manifest.json
# Static artifacts - These should be fetched and built inside the Docker image
/assets/node_modules/
/priv/static/assets/
/priv/static/cache_manifest.json
# Node modules (if any left)
node_modules/
npm-debug.log
# Environment files
.env
.env.*
# Database dumps
*.dump
*.sql
# OS files
Thumbs.db

View file

@ -12,7 +12,11 @@ FROM ${BUILDER_IMAGE} AS builder
# Install build dependencies
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update -y && apt-get install -y --no-install-recommends build-essential git curl \
RUN apt-get update -y && apt-get install -y --no-install-recommends \
gcc \
g++ \
make \
git \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# Prepare build directory
@ -33,18 +37,12 @@ COPY mix.exs mix.lock ./
COPY vendor vendor
RUN mix deps.get --only $MIX_ENV
# Copy application code
# Copy all application code
COPY config config
COPY priv priv
COPY lib lib
COPY assets assets
COPY priv priv
COPY rel rel
# Copy Gleam source files and configuration
COPY src src
COPY gleam.toml gleam.toml
# Copy pre-compiled Gleam BEAM files
# This is crucial for production builds where gleam compiler is not available
COPY priv/gleam priv/gleam
# Compile all dependencies
RUN mix deps.compile
@ -74,30 +72,27 @@ FROM ${RUNNER_IMAGE}
# Install runtime dependencies
RUN apt-get update -y && \
apt-get install -y --no-install-recommends libstdc++6 openssl libncurses5 locales ca-certificates \
apt-get install -y --no-install-recommends \
libstdc++6 \
openssl \
libncurses5 \
locales \
ca-certificates \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# Set locale
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen
ENV LANG="en_US.UTF-8" LANGUAGE="en_US:en" LC_ALL="en_US.UTF-8"
# Set working directory and create it
# Set working directory
WORKDIR "/app"
RUN mkdir -p /app
# Set deployment timestamp to current time during runtime container build
RUN date -u +"%Y-%m-%dT%H:%M:%SZ" > /app/deployed_at.txt
# Copy release from builder
# Copy release from builder with correct ownership
COPY --from=builder --chown=nobody:root /app/release ./
# Set ownership for the entire app directory
RUN chown -R nobody:root /app
# Set user and command
USER nobody
CMD ["/app/bin/server"]
# Optional: Add healthcheck
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:4000/health || exit 1