Merge pull request #159 from blacksigkill/it/dockerization
Enhance dockerization with modular docker file/compose
This commit is contained in:
commit
6ede597b6f
8 changed files with 349 additions and 12 deletions
32
.dockerignore
Normal file
32
.dockerignore
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
# Dependencies
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Build output
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Git
|
||||||
|
.git
|
||||||
|
.github
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Environment
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
*.md
|
||||||
|
license
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
Dockerfile*
|
||||||
|
docker-compose*.yml
|
||||||
|
.dockerignore
|
||||||
|
|
||||||
|
# Other
|
||||||
|
*.log
|
||||||
12
.env.example
Normal file
12
.env.example
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Monochrome Docker Configuration
|
||||||
|
# Copy to .env and edit: cp .env.example .env
|
||||||
|
|
||||||
|
# --- Monochrome ---
|
||||||
|
MONOCHROME_PORT=3000
|
||||||
|
MONOCHROME_DEV_PORT=5173
|
||||||
|
|
||||||
|
# --- PocketBase (only used with --profile pocketbase) ---
|
||||||
|
POCKETBASE_PORT=8090
|
||||||
|
PB_ADMIN_EMAIL=admin@example.com
|
||||||
|
PB_ADMIN_PASSWORD=changeme
|
||||||
|
TZ=UTC
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -3,3 +3,6 @@ dist
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.local
|
*.local
|
||||||
.vite
|
.vite
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
.env
|
||||||
|
|
|
||||||
187
DOCKER.md
Normal file
187
DOCKER.md
Normal file
|
|
@ -0,0 +1,187 @@
|
||||||
|
# Docker Deployment Guide
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Monochrome Only
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Visit `http://localhost:3000`
|
||||||
|
|
||||||
|
### With PocketBase
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
# Edit .env -- set PB_ADMIN_EMAIL and PB_ADMIN_PASSWORD
|
||||||
|
docker compose --profile pocketbase up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
- Monochrome: `http://localhost:3000`
|
||||||
|
- PocketBase admin: `http://localhost:8090/_/`
|
||||||
|
|
||||||
|
Configure PocketBase collections per [self-hosted-database.md](self-hosted-database.md).
|
||||||
|
|
||||||
|
### Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose --profile dev up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Visit `http://localhost:5173` (hot-reload enabled)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
### Profiles
|
||||||
|
|
||||||
|
Docker Compose [profiles](https://docs.docker.com/compose/how-tos/profiles/) control which services start. A service with no profile always runs. A service with a profile only runs when that profile is activated.
|
||||||
|
|
||||||
|
| Command | What starts |
|
||||||
|
| --------------------------------------------------------- | ------------------------------------ |
|
||||||
|
| `docker compose up -d` | Monochrome |
|
||||||
|
| `docker compose --profile pocketbase up -d` | Monochrome + PocketBase |
|
||||||
|
| `docker compose --profile dev up -d` | Monochrome + Dev server |
|
||||||
|
| `docker compose --profile dev --profile pocketbase up -d` | Monochrome + Dev server + PocketBase |
|
||||||
|
|
||||||
|
In `docker-compose.yml`, it looks like this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
monochrome: # no profile -- always starts
|
||||||
|
|
||||||
|
pocketbase:
|
||||||
|
profiles: ['pocketbase'] # opt-in
|
||||||
|
|
||||||
|
monochrome-dev:
|
||||||
|
profiles: ['dev'] # opt-in
|
||||||
|
```
|
||||||
|
|
||||||
|
### Override File
|
||||||
|
|
||||||
|
Docker Compose automatically merges `docker-compose.override.yml` into `docker-compose.yml` if it exists in the same directory. No flags needed.
|
||||||
|
|
||||||
|
This is useful for forks that need to add custom services or configuration (Traefik labels, extra containers, custom networks) without modifying the base `docker-compose.yml`.
|
||||||
|
|
||||||
|
The override file does not exist in the upstream repo, don't search it!
|
||||||
|
|
||||||
|
**Example** -- adding Traefik labels to PocketBase in your fork:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# docker-compose.override.yml
|
||||||
|
services:
|
||||||
|
pocketbase:
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.pocketbase.rule=Host(`pocketbase.example.com`)
|
||||||
|
- traefik.http.routers.pocketbase.entrypoints=websecure
|
||||||
|
- traefik.http.routers.pocketbase.tls.certresolver=letsencrypt
|
||||||
|
- traefik.http.services.pocketbase.loadbalancer.server.port=8090
|
||||||
|
networks:
|
||||||
|
- proxy-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxy-network:
|
||||||
|
external: true
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example** -- adding a custom service in your fork:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# docker-compose.override.yml
|
||||||
|
services:
|
||||||
|
my-custom-api:
|
||||||
|
image: my-api:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- '4000:4000'
|
||||||
|
networks:
|
||||||
|
- monochrome-network
|
||||||
|
```
|
||||||
|
|
||||||
|
Override files can extend existing services (add labels, env vars, networks) and define entirely new services. See the [Docker docs](https://docs.docker.com/compose/how-tos/multiple-compose-files/merge/) for the full merge behavior.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Portainer Deployment
|
||||||
|
|
||||||
|
Portainer can deploy directly from your GitHub fork with auto-updates on push.
|
||||||
|
|
||||||
|
### Setup
|
||||||
|
|
||||||
|
1. In Portainer, go to **Stacks > Add Stack > Repository**
|
||||||
|
2. Enter your fork URL and branch
|
||||||
|
3. Compose path: `docker-compose.yml`
|
||||||
|
4. If your fork has a `docker-compose.override.yml`, Portainer loads it automatically
|
||||||
|
5. Under **Environment variables**, add:
|
||||||
|
- `COMPOSE_PROFILES=pocketbase` (to enable PocketBase -- omit if not needed)
|
||||||
|
- `PB_ADMIN_EMAIL=your@email.com`
|
||||||
|
- `PB_ADMIN_PASSWORD=your_secure_password`
|
||||||
|
- Any other variables from `.env.example`
|
||||||
|
6. Enable **GitOps updates** to auto-redeploy on push
|
||||||
|
|
||||||
|
> **Tip:** `COMPOSE_PROFILES` is a built-in Docker Compose variable. Setting it to `pocketbase` is equivalent to passing `--profile pocketbase` on the command line.
|
||||||
|
|
||||||
|
> **Warning:** The `dev` profile is for **local development only**. It uses volume mounts to enable hot-reload, which requires the source code to be present on the host machine. Do **not** include `dev` in `COMPOSE_PROFILES` on Portainer deployments from GitHub — it will fail because there's no local source code to mount.
|
||||||
|
|
||||||
|
### Fork Workflow
|
||||||
|
|
||||||
|
To add custom services (Traefik, monitoring, etc.) to your fork:
|
||||||
|
|
||||||
|
1. Create `docker-compose.override.yml` in your fork
|
||||||
|
2. Remove the `docker-compose.override.yml` line from `.gitignore`
|
||||||
|
3. Commit both changes to your fork
|
||||||
|
4. Portainer will auto-load the override file alongside the base compose
|
||||||
|
|
||||||
|
When pulling updates from upstream (`git pull upstream main`), there are no conflicts -- the upstream repo does not have an override file.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Operations
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View logs
|
||||||
|
docker compose logs -f
|
||||||
|
docker compose logs -f pocketbase
|
||||||
|
|
||||||
|
# Rebuild after code changes
|
||||||
|
docker compose up -d --build
|
||||||
|
|
||||||
|
# Stop everything (include all profiles you started)
|
||||||
|
docker compose --profile pocketbase down
|
||||||
|
|
||||||
|
# Stop and remove volumes (data loss!)
|
||||||
|
docker compose --profile pocketbase down -v
|
||||||
|
|
||||||
|
# Backup PocketBase data
|
||||||
|
docker compose exec pocketbase tar czf - /pb_data > backup.tar.gz
|
||||||
|
|
||||||
|
# Restore PocketBase data
|
||||||
|
docker compose exec pocketbase tar xzf - -C / < backup.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Production (Dockerfile)
|
||||||
|
|
||||||
|
Node.js Alpine image (multi-arch: amd64 + arm64). Installs dependencies, runs `vite build`, then serves the built files with `vite preview` on port 4173.
|
||||||
|
|
||||||
|
### Development (Dockerfile.dev)
|
||||||
|
|
||||||
|
Node.js Alpine image with source code mounted as a volume for hot-reload.
|
||||||
|
|
||||||
|
### Files
|
||||||
|
|
||||||
|
| File | Purpose | In upstream repo |
|
||||||
|
| ----------------------------- | ----------------------------- | :--------------: |
|
||||||
|
| `docker-compose.yml` | All services with profiles | Yes |
|
||||||
|
| `docker-compose.override.yml` | Fork-specific customizations | No |
|
||||||
|
| `.env.example` | Environment variable template | Yes |
|
||||||
|
| `.env` | Your local configuration | No |
|
||||||
|
| `Dockerfile` | Production build | Yes |
|
||||||
|
| `Dockerfile.dev` | Development build | Yes |
|
||||||
|
| `.dockerignore` | Build context exclusions | Yes |
|
||||||
20
Dockerfile
20
Dockerfile
|
|
@ -1,23 +1,25 @@
|
||||||
# Use Bun canary on Alpine
|
# Node Alpine -- multi-arch (amd64 + arm64)
|
||||||
FROM oven/bun:canary-alpine
|
FROM node:lts-alpine
|
||||||
|
|
||||||
# Set working directory
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Copy package files first for caching
|
# wget is needed for Docker healthcheck
|
||||||
COPY package.json bun.lock ./
|
RUN apk add --no-cache wget
|
||||||
|
|
||||||
# Install all dependencies (including devDeps)
|
# Copy package files first for caching
|
||||||
RUN bun install
|
COPY package.json ./
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
# Copy the rest of the project
|
# Copy the rest of the project
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Build the project
|
# Build the project
|
||||||
RUN bun run build
|
RUN npm run build
|
||||||
|
|
||||||
# Expose Vite preview port
|
# Expose Vite preview port
|
||||||
EXPOSE 4173
|
EXPOSE 4173
|
||||||
|
|
||||||
# Run the built project
|
# Run the built project
|
||||||
CMD ["bun", "run", "preview", "--", "--host", "0.0.0.0"]
|
CMD ["npm", "run", "preview", "--", "--host", "0.0.0.0"]
|
||||||
|
|
|
||||||
16
Dockerfile.dev
Normal file
16
Dockerfile.dev
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Development Dockerfile for hot-reloading
|
||||||
|
# Node Alpine -- multi-arch (amd64 + arm64)
|
||||||
|
FROM node:lts-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy package files first for caching
|
||||||
|
COPY package.json ./
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
# Expose Vite dev server port
|
||||||
|
EXPOSE 5173
|
||||||
|
|
||||||
|
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
|
||||||
20
README.md
20
README.md
|
|
@ -107,12 +107,26 @@ For alternative instances, check [INSTANCES.md](INSTANCES.md).
|
||||||
|
|
||||||
NOTE: Accounts wont work on self-hosted instances.
|
NOTE: Accounts wont work on self-hosted instances.
|
||||||
|
|
||||||
### Prerequisites
|
### Option 1: Docker (Recommended)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/monochrome-music/monochrome.git
|
||||||
|
cd monochrome
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Visit `http://localhost:3000`
|
||||||
|
|
||||||
|
For PocketBase, development mode, and advanced setups, see [DOCKER.md](DOCKER.md).
|
||||||
|
|
||||||
|
### Option 2: Manual Installation
|
||||||
|
|
||||||
|
#### Prerequisites
|
||||||
|
|
||||||
- [Node.js](https://nodejs.org/) (Version 20+ or 22+ recommended)
|
- [Node.js](https://nodejs.org/) (Version 20+ or 22+ recommended)
|
||||||
- [Bun](https://bun.sh/) or [npm](https://www.npmjs.com/)
|
- [Bun](https://bun.sh/) or [npm](https://www.npmjs.com/)
|
||||||
|
|
||||||
### Local Development
|
#### Local Development
|
||||||
|
|
||||||
1. **Clone the repository:**
|
1. **Clone the repository:**
|
||||||
|
|
||||||
|
|
@ -140,7 +154,7 @@ NOTE: Accounts wont work on self-hosted instances.
|
||||||
4. **Open your browser:**
|
4. **Open your browser:**
|
||||||
Navigate to `http://localhost:5173/`
|
Navigate to `http://localhost:5173/`
|
||||||
|
|
||||||
### Building for Production
|
#### Building for Production
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bun run build
|
bun run build
|
||||||
|
|
|
||||||
71
docker-compose.yml
Normal file
71
docker-compose.yml
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
services:
|
||||||
|
# Production frontend -- always runs
|
||||||
|
monochrome:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: monochrome
|
||||||
|
ports:
|
||||||
|
- '${MONOCHROME_PORT:-3000}:4173'
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- monochrome-network
|
||||||
|
healthcheck:
|
||||||
|
test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost:4173/']
|
||||||
|
interval: 30s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 3
|
||||||
|
start_period: 5s
|
||||||
|
|
||||||
|
# PocketBase backend -- only starts with: docker compose --profile pocketbase up -d
|
||||||
|
pocketbase:
|
||||||
|
image: ghcr.io/muchobien/pocketbase:latest
|
||||||
|
container_name: monochrome-pocketbase
|
||||||
|
profiles:
|
||||||
|
- pocketbase
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
PB_ADMIN_EMAIL: ${PB_ADMIN_EMAIL:-admin@example.com}
|
||||||
|
PB_ADMIN_PASSWORD: ${PB_ADMIN_PASSWORD:-changeme}
|
||||||
|
TZ: ${TZ:-UTC}
|
||||||
|
ports:
|
||||||
|
- '${POCKETBASE_PORT:-8090}:8090'
|
||||||
|
volumes:
|
||||||
|
- pb_data:/pb_data
|
||||||
|
- pb_public:/pb_public
|
||||||
|
- pb_hooks:/pb_hooks
|
||||||
|
command: serve --http=0.0.0.0:8090
|
||||||
|
healthcheck:
|
||||||
|
test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost:8090/api/health']
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 30s
|
||||||
|
networks:
|
||||||
|
- monochrome-network
|
||||||
|
|
||||||
|
# Development server -- only starts with: docker compose --profile dev up -d
|
||||||
|
monochrome-dev:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.dev
|
||||||
|
container_name: monochrome-dev
|
||||||
|
profiles:
|
||||||
|
- dev
|
||||||
|
ports:
|
||||||
|
- '${MONOCHROME_DEV_PORT:-5173}:5173'
|
||||||
|
volumes:
|
||||||
|
- .:/app
|
||||||
|
- /app/node_modules
|
||||||
|
command: npm run dev -- --host 0.0.0.0
|
||||||
|
networks:
|
||||||
|
- monochrome-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
monochrome-network:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
pb_data:
|
||||||
|
pb_public:
|
||||||
|
pb_hooks:
|
||||||
Loading…
Reference in a new issue