The Docker-Compose File (run)
The following file docker-compose.yml is used to run a docker-container with an image
created in Dockerfile.
The dockerfile builds the phoenix-release of iBoard blog.
The docker-compose file packs a stack with two services.
- web (The Phoenix application)
- db (A Postgres database)
docker-compose.yml
services:
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: ${PGUSER:-blog}
POSTGRES_PASSWORD: ${PGPASSWORD:?Set PGPASSWORD in .env}
POSTGRES_DB: ${PGDATABASE:-blog_prod}
volumes:
- ./data/postgres:/var/lib/postgresql/data
expose:
- "5432"
networks:
- backend
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${PGUSER:-blog}"]
interval: 10s
timeout: 5s
retries: 5
web:
image: iboard/blog:latest
env_file:
- path: ./.env
required: false
environment:
PHX_SERVER: "true"
# Endpoint
ENDPOINT_HOST: ${ENDPOINT_HOST:?Set ENDPOINT_HOST in .env}
ENDPOINT_SCHEME: ${ENDPOINT_SCHEME:-https}
ENDPOINT_PORT: ${ENDPOINT_PORT:-4000}
ENDPOINT_IP: ${ENDPOINT_IP:-0.0.0.0}
# Database — connects to the db service on the internal network
DATABASE_URL: "ecto://${PGUSER:-blog}:${PGPASSWORD}@db/${PGDATABASE:-blog_prod}"
POOL_SIZE: ${POOL_SIZE:-10}
# Security
SECRET_KEY_BASE: ${SECRET_KEY_BASE:?Set SECRET_KEY_BASE in .env}
# Mailer
MAILER_ADAPTER: ${MAILER_ADAPTER:-sendgrid}
SENDGRID_API_KEY: ${SENDGRID_API_KEY:-}
# Logging
LOG_LEVEL: ${LOG_LEVEL:-info}
# Clustering (optional)
DNS_CLUSTER_QUERY: ${DNS_CLUSTER_QUERY:-}
ports:
# Host port EXPOSE_PORT → container port ENDPOINT_PORT.
# Put an nginx reverse proxy in front to terminate TLS on 443.
- "${EXPOSE_PORT:-4000}:${ENDPOINT_PORT:-4000}"
volumes:
- ./data/uploads:/app/uploads
depends_on:
db:
condition: service_healthy
networks:
- backend
restart: unless-stopped
networks:
backend:
driver: bridge
Dockerfile
The following dockerfile builds an image from a slim Debian, packed with Erlang and Elixir.
It uses mix to build a release and a docker image.
# Builder Stage
FROM hexpm/elixir:1.19.5-erlang-28.4-debian-bookworm-20260223-slim AS builder
ENV MIX_ENV=prod
WORKDIR /build
# Install build dependencies
RUN apt-get update -y && apt-get install -y build-essential git \
&& apt-get clean && rm -f /var/lib/apt/lists/*_*
# Install hex and rebar
RUN mix local.hex --force && mix local.rebar --force
# Install mix dependencies
COPY mix.exs mix.lock ./
COPY config config
COPY README.md README.md
COPY CHANGELOG.md CHANGELOG.md
COPY TODO.md TODO.md
RUN mix deps.get --only $MIX_ENV
RUN mix deps.compile
# Copy application code
COPY priv priv
COPY lib lib
COPY assets assets
# run mix doesn't compile - FIXME: find another way to deploy docs
# RUN mix docs
COPY doc priv/static/docs
# Deploy assets
# Provide dummy environment variables for config/runtime.exs evaluation during build
ENV DATABASE_URL=ecto://postgres:postgres@localhost/w_app_core_prod
#ENV SECRET_KEY_BASE=dummy_secret_key_base_for_build_only_must_be_at_least_64_bytes_long_so_we_add_some_more_chars_here
# Compile the release
RUN mix compile
RUN mix assets.deploy
RUN mix release
# Runner Stage
FROM debian:bookworm-slim AS runner
ENV MIX_ENV=prod
# Install runtime dependencies including wkhtmltopdf
# wkhtmltopdf fontconfig libjpeg62-turbo libxrender1 xfonts-75dpi xfonts-base \
# pdftk \
RUN apt-get update -y && \
apt-get install -y libstdc++6 openssl libncurses5 locales \
&& apt-get clean && rm -f /var/lib/apt/lists/*_*
# Set the locale
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8
WORKDIR /app
# Copy the built release from the builder stage
COPY --from=builder /build/_build/prod/rel/w_app_core ./
COPY doc priv/static/docs
# Expose default port
EXPOSE 4000
CMD ["sh", "-c", "/app/bin/w_app_core eval WAppCore.Release.migrate && /app/bin/w_app_core start"]
0