Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 78 additions & 56 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,80 +1,102 @@
# Use Elixir official image
# ============================================
# Stage 0: Common base (system dependencies)
# ============================================
FROM elixir:1.15.7-alpine AS base

# Install build dependencies
RUN apk add --no-cache \
build-base \
git \
postgresql-client \
inotify-tools \
curl \
sudo

# Create user with same UID/GID as host user
ARG USER_ID=1000
ARG GROUP_ID=1000
RUN addgroup -g ${GROUP_ID} -S elixir && \
adduser -u ${USER_ID} -S elixir -G elixir -s /bin/sh

# Set work directory
openssh-client \
postgresql-dev \
&& rm -rf /var/cache/apk/*

WORKDIR /app
RUN mix do local.hex --force, local.rebar --force

# Change ownership
RUN chown -R elixir:elixir /app
# ============================================
# Stage 1: Dependencies (better caching)
# ============================================
FROM base AS deps

# Switch to elixir user
USER elixir
# Copy only dependency files first
COPY mix.exs mix.lock ./
RUN --mount=type=ssh mix deps.get --only prod

# Install Hex and Rebar
RUN mix local.hex --force && \
mix local.rebar --force
# ============================================
# Stage 2: Development
# ============================================
FROM base AS dev

#############################################
# Dependencies stage - for caching
#############################################
FROM base AS deps
# Add only what is specific for development
RUN apk add --no-cache nodejs npm inotify-tools \
&& rm -rf /var/cache/apk/*

COPY mix.exs mix.lock ./
COPY config config
RUN --mount=type=ssh mix deps.get

# The rest will be set up via volume in Compose

# Copy mix files first for better caching
COPY --chown=elixir:elixir mix.exs mix.lock ./
# ============================================
# Stage 3: Build (production)
# ============================================
FROM base AS build

# Install dependencies
RUN mix deps.get
# Add only build-specific files
RUN apk add --no-cache nodejs npm \
&& rm -rf /var/cache/apk/*

#############################################
# Development stage
#############################################
FROM deps AS development
ARG mix_env=prod
WORKDIR /app

# 1. Dependencies first (better caching)
COPY mix.exs mix.lock ./
RUN --mount=type=ssh mix deps.get --only $mix_env

# Copy scripts first (they change less frequently)
COPY --chown=elixir:elixir scripts/ ./scripts/
# 2. Configurations
COPY config config

# Make ALL scripts executable - FIX AQUI
RUN find ./scripts -type f -name "*.sh" -exec chmod +x {} \;
# 3. Source code
COPY lib lib
COPY priv priv
COPY scripts scripts

# Copy rest of application code
COPY --chown=elixir:elixir . .
# 4. Assets
COPY assets assets
RUN if [ -f "assets/package.json" ]; then \
cd assets && npm ci --omit=dev && \
(npm run deploy || npm run build || true); \
fi

# Compile dependencies only (code will be compiled by script)
RUN mix deps.compile
# 5. Compile and make release
RUN MIX_ENV=$mix_env mix compile
RUN MIX_ENV=$mix_env mix release

# Default command will be overridden by docker-compose
CMD ["mix", "phx.server"]
# ============================================
# Stage 4: Runtime (production – minimal image)
# ============================================
FROM alpine:3.20 AS app

#############################################
# Production stage (for future use)
#############################################
FROM deps AS production
RUN apk add --no-cache \
openssl \
ncurses-libs \
libstdc++ \
ca-certificates \
&& rm -rf /var/cache/apk/*

ARG mix_env=prod
WORKDIR /app

ENV MIX_ENV=prod
RUN addgroup -g 1000 -S appuser && \
adduser -u 1000 -S appuser -G appuser && \
chown -R appuser:appuser /app

# Copy application code
COPY --chown=elixir:elixir . .
USER appuser:appuser

# Compile application
RUN mix deps.compile && \
mix compile
COPY --from=build --chown=appuser:appuser /app/_build/${mix_env}/rel/sendwise ./
COPY --from=build --chown=appuser:appuser /app/scripts/start.sh ./start.sh

# Create release
RUN mix release
ENV HOME=/app \
PATH=/app/bin:$PATH

CMD ["_build/prod/rel/foedus/bin/foedus", "start"]
CMD ["sh", "./start.sh"]
53 changes: 53 additions & 0 deletions compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
services:
foedus:
build:
context: .
target: dev
restart: unless-stopped
container_name: foedus
command: mix phx.server
stdin_open: true
tty: true
depends_on:
foedus_db:
condition: service_healthy
ports:
- 4000:4000
volumes:
- .:/app
- foedus_deps:/app/deps
- foedus_build:/app/_build
env_file:
- .env
environment:
- PHX_LIVE_RELOAD_POLLING=true
networks:
- foedus_net

foedus_db:
image: "postgres:17"
container_name: foedus_db
environment:
POSTGRES_USER: ${DATABASE_USER}
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
ports:
- "5432:5432"
env_file:
- .env
volumes:
- "foedus_db:/var/lib/postgresql/data"
networks:
- foedus_net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5

networks:
foedus_net:

volumes:
foedus_db:
foedus_deps:
foedus_build:
8 changes: 4 additions & 4 deletions config/dev.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import Config

# Configure your database
config :foedus, Foedus.Repo,
username: "postgres",
password: "postgres",
hostname: "db",
database: "foedus_dev",
username: System.get_env("DATABASE_USER") || "postgres",
password: System.get_env("DATABASE_PASSWORD") || "postgres",
hostname: System.get_env("DATABASE_HOST") || "my_doctor_db",
database: System.get_env("DATABASE_NAME") || "my_doctor_dev",
stacktrace: true,
show_sensitive_data_on_connection_error: true,
pool_size: 10
Expand Down
58 changes: 0 additions & 58 deletions docker-compose.yml

This file was deleted.

28 changes: 28 additions & 0 deletions lib/release.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
defmodule Foedus.Release do
@moduledoc """
Used for executing DB release tasks when run in production without Mix
installed.
"""
@app :sendwise

def migrate do
load_app()

for repo <- repos() do
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true))
end
end

def rollback(repo, version) do
load_app()
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version))
end

defp repos do
Application.fetch_env!(@app, :ecto_repos)
end

defp load_app do
Application.load(@app)
end
end
26 changes: 0 additions & 26 deletions scripts/dev-start.sh

This file was deleted.

9 changes: 9 additions & 0 deletions scripts/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash
set -e

if [ -f "bin/foedus" ]; then
bin/foedus eval "Foedus.Release.migrate" || true
bin/foedus start
else
exec "$@"
fi