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
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,7 @@ ENV_DB_URL=""

# --- The logs directory for Caddy to persists its logs.
CADDY_LOGS_PATH="./storage/logs/caddy"

# --- Docker (Local envs)
ENV_DOCKER_USER="gocanto"
ENV_DOCKER_USER_GROUP="ggroup"
4 changes: 4 additions & 0 deletions .env.gh.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ENV_HTTP_PORT=8080
ENV_DOCKER_USER=gocanto
ENV_DOCKER_USER_GROUP=ggroup
CADDY_LOGS_PATH=./storage/logs/caddy
7 changes: 7 additions & 0 deletions .env.prod.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# --- Caddy
CADDY_LOGS_DIR=./storage/logs/caddy

# --- Database Secrets
DB_SECRET_USERNAME=./database/infra/secrets/pg_username
DB_SECRET_PASSWORD=./database/infra/secrets/pg_password
DB_SECRET_DBNAME=./database/infra/secrets/pg_dbname
6 changes: 3 additions & 3 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ jobs:
run: echo "${{ secrets.ENV_FILE_CONTENT }}" > .env
shell: bash

- name: Build with Makefile
run: make build:prod
- name: Build Release Images
run: make build:ci

- name: Log in to GitHub Container Registry
- name: Log in to GitHub Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
Expand Down
28 changes: 17 additions & 11 deletions config/makefile/build.mk
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
.PHONY: build\:local build\:prod build\:release
.PHONY: build\:local build\:prod build\:release build\:deploy

BUILD_VERSION ?= latest
BUILD_PACKAGE_OWNER := oullin

build\:local:
docker compose --profile local up --build -d

build\:ci:
@printf "\n$(CYAN)Building production images for CI$(NC)\n"
# This 'build' command only builds the images; it does not run them.
@docker compose --profile prod build

# --- Deprecated
# We should always deploy builds from the CI and not build again in servers.
build\:prod:
@printf "\n$(CYAN)docker compose --profile prod up --build -d$(NC)\n"
# --- The following lines take the variables passed to 'make' and export them
# into the shell environment for only the docker-compose command.
# These variable names now EXACTLY match what the Go application expects.
@POSTGRES_USER_SECRET_PATH="$(POSTGRES_USER_SECRET_PATH)" \
POSTGRES_PASSWORD_SECRET_PATH="$(POSTGRES_PASSWORD_SECRET_PATH)" \
POSTGRES_DB_SECRET_PATH="$(POSTGRES_DB_SECRET_PATH)" \
ENV_DB_USER_NAME="$(ENV_DB_USER_NAME)" \
ENV_DB_USER_PASSWORD="$(ENV_DB_USER_PASSWORD)" \
ENV_DB_DATABASE_NAME="$(ENV_DB_DATABASE_NAME)" \
@DB_SECRET_USERNAME="$(DB_SECRET_USERNAME)" \
DB_SECRET_PASSWORD="$(DB_SECRET_PASSWORD)" \
DB_SECRET_DBNAME="$(DB_SECRET_DBNAME)" \
docker compose --profile prod up --build -d

build\:deploy:
@DB_SECRET_USERNAME="$(DB_SECRET_USERNAME)" \
DB_SECRET_PASSWORD="$(DB_SECRET_PASSWORD)" \
DB_SECRET_DBNAME="$(DB_SECRET_DBNAME)" \
docker compose --profile prod up -d

build\:release:
@printf "\n$(YELLOW)Tagging images to be released.$(NC)\n"
docker tag api-api ghcr.io/$(BUILD_PACKAGE_OWNER)/oullin_api:$(BUILD_VERSION) && \
Expand Down
6 changes: 3 additions & 3 deletions database/infra/scripts/healthcheck.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
set -e

# Read the secrets into variables. This is more robust than direct command substitution.
DB_USER=$(cat /run/secrets/postgres_user)
DB_NAME=$(cat /run/secrets/postgres_db)
DB_USER=$(cat /run/secrets/pg_username)
DB_NAME=$(cat /run/secrets/pg_dbname)

# Explicitly check if the user variable is empty. If it is, fail immediately.
# This prevents the "role -d does not exist" error.
if [ -z "$DB_USER" ]; then
echo "Healthcheck Error: The postgres_user secret is empty or could not be read." >&2
echo "Healthcheck Error: The pg_username secret is empty or could not be read." >&2
exit 1
fi

Expand Down
File renamed without changes.
46 changes: 25 additions & 21 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Define the source of the secrets on the host machine.
secrets:
postgres_user:
file: ${POSTGRES_USER_SECRET_PATH:-./database/infra/secrets/postgres_user}
postgres_password:
file: ${POSTGRES_PASSWORD_SECRET_PATH:-./database/infra/secrets/postgres_password}
postgres_db:
file: ${POSTGRES_DB_SECRET_PATH:-./database/infra/secrets/postgres_db}
pg_username:
file: ${DB_SECRET_USERNAME:-./database/infra/secrets/pg_username}
pg_password:
file: ${DB_SECRET_PASSWORD:-./database/infra/secrets/pg_password}
pg_dbname:
file: ${DB_SECRET_DBNAME:-./database/infra/secrets/pg_dbname}

volumes:
caddy_data:
Expand All @@ -27,6 +27,7 @@ networks:

services:
caddy_prod:
image: api-caddy_prod
build:
context: ./caddy
dockerfile: Dockerfile
Expand Down Expand Up @@ -83,14 +84,15 @@ services:
networks:
- oullin_net
secrets:
- postgres_user
- postgres_password
- postgres_db
- pg_username
- pg_password
- pg_dbname
depends_on:
api-db:
condition: service_healthy

api:
image: api-api
env_file:
- .env
environment:
Expand All @@ -109,9 +111,9 @@ services:
container_name: oullin_api
restart: unless-stopped
secrets:
- postgres_user
- postgres_password
- postgres_db
- pg_username
- pg_password
- pg_dbname
depends_on:
api-db:
condition: service_healthy
Expand All @@ -130,9 +132,9 @@ services:
- ./database/infra/migrations:/migrations
- ./database/infra/scripts/run-migration.sh:/run-migration.sh
secrets:
- postgres_user
- postgres_password
- postgres_db
- pg_username
- pg_password
- pg_dbname
entrypoint: /run-migration.sh
command: ""
depends_on:
Expand All @@ -157,9 +159,9 @@ services:
# --- Use Docker Secrets instead of .env files for credentials.
# The given postgres image automatically reads from files specified by these _FILE variables.
environment:
POSTGRES_USER_FILE: /run/secrets/postgres_user
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
POSTGRES_DB_FILE: /run/secrets/postgres_db
POSTGRES_USER_FILE: /run/secrets/pg_username
POSTGRES_PASSWORD_FILE: /run/secrets/pg_password
POSTGRES_DB_FILE: /run/secrets/pg_dbname
PGDATA: /var/lib/postgresql/data/pgdata

# --- Securing port binding.
Expand All @@ -173,19 +175,21 @@ services:
# --- Define which secrets this service has access to.
# These secrets are mounted securely in memory at /run/secrets/
secrets:
- postgres_user
- postgres_password
- postgres_db
- pg_username
- pg_password
- pg_dbname
volumes:
# Use a Docker Named Volume for data persistence.
# This decouples my critical data from the host's file structure, making it
# more robust, portable, and managed entirely by Docker.
- oullin_db_data:/var/lib/postgresql/data

# Mount SSL certs and config files as read-only (:ro) for security.
- ./database/infra/ssl/server.crt:/etc/ssl/certs/server.crt:ro
- ./database/infra/ssl/server.key:/etc/ssl/private/server.key
- ./database/infra/config/postgresql.conf:/etc/postgresql/postgresql.conf:ro
- ./database/infra/scripts/healthcheck.sh:/healthcheck.sh:ro

command: postgres -c config_file=/etc/postgresql/postgresql.conf

logging:
Expand Down
Loading