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
45 changes: 45 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Dependencies
node_modules

# Build output
build
.svelte-kit

# Git
.git
.gitignore

# IDE
.vscode
.idea
*.swp
*.swo

# Logs
logs
*.log
npm-debug.log*

# OS files
.DS_Store
Thumbs.db

# Docker
Dockerfile
docker-compose.example.yml
.dockerignore

# Documentation
README.md
LICENSE
*.md

# Development/Test
.env.local
.env.*.local
coverage
.nyc_output

# Config (mounted at runtime, not baked in)
# Keep config examples for build stage
!config/*.example.*
8 changes: 8 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Diadem Application
DIADEM_PORT=3900

# MariaDB Database (Diadem Internal)
MARIADB_ROOT_PASSWORD=changeme_root
MARIADB_DATABASE=diadem
MARIADB_USER=diadem
MARIADB_PASSWORD=changeme
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ Thumbs.db
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
.pnpm-store

# Docker
docker-compose.yml
49 changes: 49 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
FROM node:22-slim AS base
RUN corepack enable && corepack prepare pnpm@latest --activate
WORKDIR /app

FROM base AS deps

COPY package.json pnpm-lock.yaml ./
COPY patches ./patches/
RUN pnpm install --frozen-lockfile

FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN ./setup.sh && pnpm run build

FROM node:22-slim AS runtime
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
RUN groupadd --gid 1001 diadem && \
useradd --uid 1001 --gid diadem --shell /bin/bash --create-home diadem
COPY --from=builder --chown=diadem:diadem /app/build ./build
COPY --from=builder --chown=diadem:diadem /app/package.json ./
COPY --from=deps --chown=diadem:diadem /app/node_modules ./node_modules

# Files needed for drizzle-kit db:push at runtime
COPY --from=builder --chown=diadem:diadem /app/drizzle.config.ts ./
COPY --from=builder --chown=diadem:diadem /app/src/lib/server/db ./src/lib/server/db
COPY --from=builder --chown=diadem:diadem /app/src/lib/services ./src/lib/services

# Create config.toml mount point (actual config mounted at runtime)
RUN touch ./src/lib/server/config.toml && chown diadem:diadem ./src/lib/server/config.toml

RUN mkdir -p /app/config /app/logs && chown diadem:diadem /app/config /app/logs
COPY --chown=diadem:diadem docker-entrypoint.sh ./
RUN chmod +x docker-entrypoint.sh
USER diadem
ENV NODE_ENV=production
ENV HOST=0.0.0.0
ENV PORT=3900

EXPOSE 3900

HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD node -e "fetch('http://localhost:${PORT:-3900}').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"

ENTRYPOINT ["./docker-entrypoint.sh"]
111 changes: 111 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Diadem Docker Build & Release Makefile

# Registry and image configuration (override with environment variables)
DIADEM_DOCKER_REGISTRY ?= ghcr.io
DIADEM_DOCKER_REPOSITORY ?= ccev/diadem
DIADEM_DOCKER_IMAGE ?= $(DIADEM_DOCKER_REGISTRY)/$(DIADEM_DOCKER_REPOSITORY)

# Version tagging (defaults to git short hash)
GIT_HASH := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
GIT_DIRTY := $(shell git diff --quiet 2>/dev/null || echo "-dirty")
DIADEM_DOCKER_VERSION ?= $(GIT_HASH)$(GIT_DIRTY)

# Additional tags
DIADEM_DOCKER_LATEST_TAG ?= latest

# Docker build options
DIADEM_DOCKER_BUILD_ARGS ?=
DIADEM_DOCKER_PLATFORM ?= linux/amd64,linux/arm64
DIADEM_DOCKER_FILE ?= Dockerfile

# Helm chart
HELM_CHART_PATH := helm/diadem

.PHONY: help build release build-and-release tag clean lint helm-lint helm-package

help: ## Show this help message
@echo "Diadem Docker Build & Release"
@echo ""
@echo "Usage: make [target]"
@echo ""
@echo "Configuration (override with environment variables):"
@echo " DIADEM_DOCKER_REGISTRY = $(DIADEM_DOCKER_REGISTRY)"
@echo " DIADEM_DOCKER_REPOSITORY = $(DIADEM_DOCKER_REPOSITORY)"
@echo " DIADEM_DOCKER_IMAGE = $(DIADEM_DOCKER_IMAGE)"
@echo " DIADEM_DOCKER_VERSION = $(DIADEM_DOCKER_VERSION)"
@echo ""
@echo "Targets:"
@awk 'BEGIN {FS = ":.*##"; printf ""} /^[a-zA-Z_-]+:.*?##/ { printf " %-15s %s\n", $$1, $$2 }' $(MAKEFILE_LIST)

build: ## Build image for local platform only
docker build \
--tag $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_VERSION) \
--tag $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_LATEST_TAG) \
--file $(DIADEM_DOCKER_FILE) \
$(DIADEM_DOCKER_BUILD_ARGS) \
.

release: ## Push locally built image to registry
docker push $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_VERSION)
docker push $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_LATEST_TAG)

build-and-release: ## Build multi-platform image and push to registry
docker buildx build \
--platform $(DIADEM_DOCKER_PLATFORM) \
--tag $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_VERSION) \
--tag $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_LATEST_TAG) \
--file $(DIADEM_DOCKER_FILE) \
--push \
$(DIADEM_DOCKER_BUILD_ARGS) \
.

tag: ## Tag an existing image with a new tag (e.g., make tag NEW_TAG=v1.0.0)
@test -n "$(NEW_TAG)" || (echo "NEW_TAG is required" && exit 1)
docker buildx imagetools create \
--tag $(DIADEM_DOCKER_IMAGE):$(NEW_TAG) \
$(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_VERSION)

clean: ## Remove local images
-docker rmi $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_VERSION) 2>/dev/null
-docker rmi $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_LATEST_TAG) 2>/dev/null

lint: ## Lint Dockerfile with hadolint
@command -v hadolint >/dev/null 2>&1 && hadolint $(DIADEM_DOCKER_FILE) || \
docker run --rm -i hadolint/hadolint < $(DIADEM_DOCKER_FILE)

helm-lint: ## Lint Helm chart
helm lint $(HELM_CHART_PATH)

helm-package: ## Package Helm chart
helm package $(HELM_CHART_PATH)

helm-template: ## Render Helm chart templates
helm template diadem $(HELM_CHART_PATH)

# Docker Compose targets
.PHONY: up down logs

up: ## Start services with docker-compose
docker compose up -d

down: ## Stop services with docker-compose
docker compose down

logs: ## View docker-compose logs
docker compose logs -f

# Development helpers
.PHONY: setup-buildx info

setup-buildx: ## Set up Docker buildx for multi-platform builds
docker buildx create --name diadem-builder --use 2>/dev/null || docker buildx use diadem-builder
docker buildx inspect --bootstrap

info: ## Show build configuration
@echo "Registry: $(DIADEM_DOCKER_REGISTRY)"
@echo "Repository: $(DIADEM_DOCKER_REPOSITORY)"
@echo "Image: $(DIADEM_DOCKER_IMAGE)"
@echo "Version: $(DIADEM_DOCKER_VERSION)"
@echo "Git Hash: $(GIT_HASH)"
@echo "Platforms: $(DIADEM_DOCKER_PLATFORM)"
@echo "Dockerfile: $(DIADEM_DOCKER_FILE)"
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ set this up yourself. But I'm not stopping you:
2. `./setup.sh && pnpm install && pnpm run build`
3. `pm2 restart diadem`

### Quick-Start in Docker
These are the basic steps to get going in Docker, but are not production ready (single-node DB, no redundancy, etc)
1. `git clone https://github.com/ccev/diadem && cd `
2. `cp ./config/config.example.toml ./config/config.toml`
3. Modify the config file to your liking by editing ./config/config.toml. You'll need to point the db at hostname `diadem-db`
4. `cp docker-compose.example.yml docker-compose.yml`
5. Modify the docker-compose file to your liking, such as pointing to an external database
6. `docker compose up --build`
7. Diadem is now running on http://localhost:3900

### Asset caching
Diadem proxies and optimizes UICON repos. Clients will cache all uicons for 7 days.
But I suggest adding your own caching rules, i.e. with Cloudflare:
Expand Down
65 changes: 65 additions & 0 deletions docker-compose.example.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
services:
diadem:
build:
context: .
dockerfile: Dockerfile
image: diadem:latest
container_name: diadem
restart: unless-stopped
ports:
- "${DIADEM_PORT:-3900}:3900"
environment:
- NODE_ENV=production
- HOST=0.0.0.0
- PORT=3900
volumes:
# Required: Mount your config file (both paths needed for runtime and db:push)
- ./config/config.toml:/app/build/server/config.toml:ro
- ./config/config.toml:/app/src/lib/server/config.toml:ro
# Optional: Persistent logs
- diadem-logs:/app/logs
depends_on:
diadem-db:
condition: service_healthy
networks:
- diadem-network
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://localhost:3900').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s

diadem-db:
image: mariadb:11.4
container_name: diadem-db
restart: unless-stopped
environment:
MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD:-changeme_root}
MARIADB_DATABASE: ${MARIADB_DATABASE:-diadem}
MARIADB_USER: ${MARIADB_USER:-diadem}
MARIADB_PASSWORD: ${MARIADB_PASSWORD:-changeme}
volumes:
- diadem-db-data:/var/lib/mysql
networks:
- diadem-network
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci

volumes:
diadem-db-data:
name: diadem-db-data
diadem-logs:
name: diadem-logs

networks:
diadem-network:
name: diadem-network
driver: bridge
17 changes: 17 additions & 0 deletions docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/sh
set -e

# Only run db:push if the database appears to be uninitialized
# This prevents accidental destructive schema changes in production
if [ "${SKIP_DB_PUSH:-}" = "true" ]; then
echo "Skipping database push (SKIP_DB_PUSH=true)"
elif [ "${FORCE_DB_PUSH:-}" = "true" ]; then
echo "Running database push (forced)..."
npx drizzle-kit push --force
else
echo "Running database push..."
npx drizzle-kit push
fi

echo "Starting Diadem..."
exec node build/index.js
14 changes: 13 additions & 1 deletion setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,31 @@ ensure_linked_file() {
local cfg="$2" # e.g. config/custom.txt
local example="$3" # e.g. config/custom.example.txt

# if source already exists, do nothing
# if source already exists (and is not a broken symlink), do nothing
if [ -e "$src" ]; then
echo "$src exists, skipping"
return
fi

# remove broken symlinks if they exist
if [ -L "$src" ]; then
echo "$src is a broken symlink, removing"
rm "$src"
fi

echo "$src missing, setting it up"

# ensure directories exist
mkdir -p "$(dirname "$src")"
mkdir -p "$(dirname "$cfg")"

# create config file from example if needed
# also handle case where Docker created a directory instead of a file (happens when mount source is missing)
if [ -d "$cfg" ]; then
echo "$cfg is a directory (Docker artifact?), removing"
rm -rf "$cfg"
fi

if [ ! -e "$cfg" ]; then
if [ ! -e "$example" ]; then
echo "ERROR: example file $example does not exist"
Expand Down