From b629d633b441de1d799c7c0c9c5deece1f471f39 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 13 Jan 2026 16:41:39 +0000 Subject: [PATCH 1/6] Initial plan From fcbd26243e09effe70f35bdb755bff271926cc60 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 13 Jan 2026 16:47:45 +0000 Subject: [PATCH 2/6] Add GitHub Actions workflow for multi-arch image builds and update compose.yaml Co-authored-by: mekarpeles <978325+mekarpeles@users.noreply.github.com> --- .github/workflows/build-images.yml | 59 ++++++++++++++ DOCKER_IMAGES.md | 124 +++++++++++++++++++++++++++++ README.md | 2 +- compose.yaml | 9 +++ 4 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/build-images.yml create mode 100644 DOCKER_IMAGES.md diff --git a/.github/workflows/build-images.yml b/.github/workflows/build-images.yml new file mode 100644 index 0000000..76d033e --- /dev/null +++ b/.github/workflows/build-images.yml @@ -0,0 +1,59 @@ +name: Build and Push Multi-Architecture Images + +on: + push: + branches: [ main ] + paths: + - 'docker/**' + - 'compose.yaml' + - 'lenny/**' + - 'requirements.txt' + - '.github/workflows/build-images.yml' + workflow_dispatch: + +permissions: + contents: read + packages: write + +jobs: + build-api: + name: Build lenny-api image + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }}/lenny-api + tags: | + type=ref,event=branch + type=sha,prefix={{branch}}- + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: . + file: ./docker/api/Dockerfile + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/DOCKER_IMAGES.md b/DOCKER_IMAGES.md new file mode 100644 index 0000000..2d91330 --- /dev/null +++ b/DOCKER_IMAGES.md @@ -0,0 +1,124 @@ +# Docker Image Build Process + +This document explains how Lenny uses pre-built multi-architecture Docker images to speed up deployment. + +## Overview + +Lenny uses a hybrid approach for Docker images to balance speed and flexibility: + +- **Pre-built images**: API, Database (PostgreSQL), S3 Storage (MinIO), and Readium are pre-built +- **Local build**: The Reader service is built locally because it requires dynamic configuration + +## Pre-built Images + +The following services use pre-built multi-architecture (linux/amd64, linux/arm64) images: + +### 1. lenny-api +- **Image**: `ghcr.io/archivelabs/lenny/lenny-api:latest` +- **Build trigger**: Automated via GitHub Actions on pushes to `main` branch +- **Why pre-built**: Static configuration, no build-time environment variables needed +- **Fallback**: If the image is unavailable, Docker Compose will build it locally + +### 2. Database (PostgreSQL) +- **Image**: `postgres:16` (official Docker Hub image) +- **Why pre-built**: Official PostgreSQL image, no customization needed + +### 3. S3 Storage (MinIO) +- **Image**: `minio/minio:latest` (official Docker Hub image) +- **Why pre-built**: Official MinIO image, no customization needed + +### 4. Readium +- **Image**: `ghcr.io/readium/readium:0.6.3` (official Readium project image) +- **Why pre-built**: Official Readium image, no customization needed + +## Local Build Images + +### Reader (lenny-reader) +- **Build**: Always built locally via `docker/reader/Dockerfile` +- **Why local build**: Requires `NEXT_PUBLIC_MANIFEST_ALLOWED_DOMAINS` as a build argument + - This value changes when using custom domains or cloudflared tunnels + - Must be baked into the Next.js application at build time +- **Rebuild triggers**: + - Running `make tunnel` (adds cloudflared domain to allowed domains) + - Changing `NEXT_PUBLIC_MANIFEST_ALLOWED_DOMAINS` in `.env` + +## GitHub Actions Workflow + +The `.github/workflows/build-images.yml` workflow automatically builds and pushes the `lenny-api` image when: + +1. Code is pushed to the `main` branch +2. Changes are made to: + - `docker/**` (Dockerfile changes) + - `compose.yaml` (Docker Compose configuration) + - `lenny/**` (application code) + - `requirements.txt` (Python dependencies) +3. The workflow is manually triggered via GitHub Actions UI + +### Workflow Details + +- **Platforms**: Builds for both `linux/amd64` and `linux/arm64` +- **Registry**: Images are pushed to GitHub Container Registry (ghcr.io) +- **Tags**: + - `latest` - for the main branch + - `main-` - for specific commits +- **Caching**: Uses GitHub Actions cache for faster builds + +## Benefits + +1. **Faster initial setup**: Users can pull pre-built images instead of building from scratch +2. **Consistent images**: All users get the same tested images +3. **Multi-architecture support**: Works on both x86_64 and ARM64 (Apple Silicon, ARM servers) +4. **Reduced build time**: Only the reader service needs to be built locally + +## For Developers + +### Testing the Build Workflow + +You can test the GitHub Actions workflow locally using `act`: + +```bash +# Install act (https://github.com/nektos/act) +# Run the workflow locally +act push -W .github/workflows/build-images.yml +``` + +### Manual Build and Push + +If you need to manually build and push images (requires appropriate permissions): + +```bash +# Login to GitHub Container Registry +echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin + +# Build and push multi-arch image +docker buildx create --use +docker buildx build \ + --platform linux/amd64,linux/arm64 \ + --push \ + -t ghcr.io/archivelabs/lenny/lenny-api:latest \ + -f docker/api/Dockerfile \ + . +``` + +### Local Development + +During development, you can force local builds by: + +```bash +# Remove the pre-built image +docker rmi ghcr.io/archivelabs/lenny/lenny-api:latest + +# Build locally +docker compose build api + +# Or use the rebuild target +make rebuild +``` + +## Permissions + +The GitHub Actions workflow requires the following permissions: +- `contents: read` - to checkout the repository +- `packages: write` - to push images to GitHub Container Registry + +The `GITHUB_TOKEN` secret is automatically provided by GitHub Actions and has the necessary permissions. diff --git a/README.md b/README.md index 1cdd58b..bbd6422 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ Lenny is a free, open source, Library-in-a-Box for libraries to preserve and len --- ## Technologies -- **Docker** for deployment and containerization +- **Docker** for deployment and containerization (with pre-built multi-architecture images - see [DOCKER_IMAGES.md](DOCKER_IMAGES.md)) - **nginx** as a reverse proxy - **FastAPI** (Python) as the web & API framework - **Minio** API for storing digital assets diff --git a/compose.yaml b/compose.yaml index 9028462..9e62773 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,6 +1,10 @@ services: + # API Service: Pre-built multi-architecture image from GitHub Container Registry + # Falls back to local build if image is not available or during development api: + image: ghcr.io/archivelabs/lenny/lenny-api:latest + pull_policy: always build: context: . dockerfile: docker/api/Dockerfile @@ -23,6 +27,7 @@ services: networks: - lenny_network + # Database: Pre-built official PostgreSQL image from Docker Hub db: image: postgres:16 container_name: lenny_db @@ -43,6 +48,7 @@ services: networks: - lenny_network + # S3 Storage: Pre-built official MinIO image from Docker Hub s3: image: minio/minio:latest container_name: lenny_s3 @@ -63,6 +69,8 @@ services: networks: - lenny_network + # Reader: Built locally due to dynamic NEXT_PUBLIC_MANIFEST_ALLOWED_DOMAINS + # This needs to be rebuilt when using custom domains or cloudflared tunnels reader: container_name: lenny_reader build: @@ -84,6 +92,7 @@ services: networks: - lenny_network + # Readium: Pre-built multi-architecture image from Readium project readium: image: ghcr.io/readium/readium:0.6.3 container_name: lenny_readium From b9bd54578b5d3731215e1f29d16bc16489c7f86f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 13 Jan 2026 16:50:58 +0000 Subject: [PATCH 3/6] Remove explicit pull_policy to use default Docker Compose behavior Co-authored-by: mekarpeles <978325+mekarpeles@users.noreply.github.com> --- compose.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/compose.yaml b/compose.yaml index 9e62773..8ae59a4 100644 --- a/compose.yaml +++ b/compose.yaml @@ -4,7 +4,6 @@ services: # Falls back to local build if image is not available or during development api: image: ghcr.io/archivelabs/lenny/lenny-api:latest - pull_policy: always build: context: . dockerfile: docker/api/Dockerfile From 3cf88d2f50f89388b801a9eeece84530fa346984 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 13 Jan 2026 16:53:25 +0000 Subject: [PATCH 4/6] Add repository settings documentation for GitHub Container Registry Co-authored-by: mekarpeles <978325+mekarpeles@users.noreply.github.com> --- DOCKER_IMAGES.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/DOCKER_IMAGES.md b/DOCKER_IMAGES.md index 2d91330..d08e0e3 100644 --- a/DOCKER_IMAGES.md +++ b/DOCKER_IMAGES.md @@ -122,3 +122,19 @@ The GitHub Actions workflow requires the following permissions: - `packages: write` - to push images to GitHub Container Registry The `GITHUB_TOKEN` secret is automatically provided by GitHub Actions and has the necessary permissions. + +### Repository Settings + +To ensure the workflow can push images to GitHub Container Registry, verify that: + +1. **Workflow permissions** are set correctly in the repository settings: + - Go to Settings > Actions > General > Workflow permissions + - Ensure "Read and write permissions" is selected + - Or use the specific permissions defined in the workflow file + +2. **Package visibility**: After the first successful workflow run, you may want to make the package public: + - Go to the package page: `https://github.com/orgs/ArchiveLabs/packages/container/lenny%2Flenny-api` + - Click "Package settings" + - Change visibility to "Public" (optional, but recommended for easier access) + +3. **No additional secrets needed**: The workflow uses `GITHUB_TOKEN`, which is automatically available in GitHub Actions. From ae1445fda5dca350094492e6f412d3b68b20acc8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 13 Jan 2026 16:55:50 +0000 Subject: [PATCH 5/6] Add 'make pull' command and update documentation for users Co-authored-by: mekarpeles <978325+mekarpeles@users.noreply.github.com> --- DOCKER_IMAGES.md | 12 ++++++++++++ Makefile | 6 ++++++ README.md | 4 ++++ 3 files changed, 22 insertions(+) diff --git a/DOCKER_IMAGES.md b/DOCKER_IMAGES.md index d08e0e3..d567e8f 100644 --- a/DOCKER_IMAGES.md +++ b/DOCKER_IMAGES.md @@ -70,6 +70,18 @@ The `.github/workflows/build-images.yml` workflow automatically builds and pushe 3. **Multi-architecture support**: Works on both x86_64 and ARM64 (Apple Silicon, ARM servers) 4. **Reduced build time**: Only the reader service needs to be built locally +## For Users + +### Updating to Latest Images + +To pull the latest pre-built images: + +```bash +make pull +``` + +This will update the API, database, S3, and Readium images to their latest versions. + ## For Developers ### Testing the Build Workflow diff --git a/Makefile b/Makefile index 775ca27..c40bca0 100644 --- a/Makefile +++ b/Makefile @@ -52,6 +52,12 @@ resetdb: start: @bash docker/utils/lenny.sh --start +# Pull latest pre-built images from GitHub Container Registry +.PHONY: pull +pull: + @echo "[+] Pulling latest pre-built images..." + @docker compose pull api db s3 readium + .PHONY: restart restart: @bash docker/utils/lenny.sh --restart diff --git a/README.md b/README.md index bbd6422..1950c11 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,8 @@ To install and run Lenny as a production application: curl -fsSL https://raw.githubusercontent.com/ArchiveLabs/lenny/refs/heads/main/install.sh | sudo bash ``` +**Note**: Lenny now uses pre-built multi-architecture Docker images, making the initial setup significantly faster. The first time you run `make all`, Docker will pull optimized images instead of building everything from scratch. For more details, see [DOCKER_IMAGES.md](DOCKER_IMAGES.md). + --- ## Development Setup @@ -121,6 +123,8 @@ make all ``` - This will generate a `.env` file with reasonable defaults (if not present). +- Pre-built images for API, Database, S3, and Readium will be pulled automatically. +- Only the Reader service needs to be built locally (due to dynamic domain configuration). - Navigate to `localhost:8080` (or your `$LENNY_PORT`). - Enter the API container with: `docker exec -it lenny_api bash` From 0f1c5e8c02c809bb4063952ef5d4d8875258da10 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 13 Jan 2026 16:58:45 +0000 Subject: [PATCH 6/6] Address code review feedback: improve documentation and tag format Co-authored-by: mekarpeles <978325+mekarpeles@users.noreply.github.com> --- .github/workflows/build-images.yml | 2 +- DOCKER_IMAGES.md | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-images.yml b/.github/workflows/build-images.yml index 76d033e..76642c3 100644 --- a/.github/workflows/build-images.yml +++ b/.github/workflows/build-images.yml @@ -43,7 +43,7 @@ jobs: images: ghcr.io/${{ github.repository }}/lenny-api tags: | type=ref,event=branch - type=sha,prefix={{branch}}- + type=sha,prefix={{branch}}-sha- type=raw,value=latest,enable={{is_default_branch}} - name: Build and push diff --git a/DOCKER_IMAGES.md b/DOCKER_IMAGES.md index d567e8f..bed3e24 100644 --- a/DOCKER_IMAGES.md +++ b/DOCKER_IMAGES.md @@ -59,8 +59,10 @@ The `.github/workflows/build-images.yml` workflow automatically builds and pushe - **Platforms**: Builds for both `linux/amd64` and `linux/arm64` - **Registry**: Images are pushed to GitHub Container Registry (ghcr.io) - **Tags**: - - `latest` - for the main branch - - `main-` - for specific commits + - `latest` - always points to the most recent build from the main branch + - `main` - also points to the main branch (same as latest) + - `main-sha-` - specific commit on main branch (e.g., `main-sha-abc1234`) + - `-sha-` - specific commits on other branches (if workflow runs on them) - **Caching**: Uses GitHub Actions cache for faster builds ## Benefits @@ -145,7 +147,8 @@ To ensure the workflow can push images to GitHub Container Registry, verify that - Or use the specific permissions defined in the workflow file 2. **Package visibility**: After the first successful workflow run, you may want to make the package public: - - Go to the package page: `https://github.com/orgs/ArchiveLabs/packages/container/lenny%2Flenny-api` + - Go to the package page: `https://github.com/orgs//packages/container/%2Flenny-api` + - For this repository, that would be: `https://github.com/orgs/ArchiveLabs/packages/container/lenny%2Flenny-api` - Click "Package settings" - Change visibility to "Public" (optional, but recommended for easier access)