Add Docker support with Dockerfile, entrypoint script, and CI workflows
- Introduced a Dockerfile for building the application with Go and Node.js dependencies. - Added a docker-entrypoint.sh script to manage container execution. - Created a .dockerignore file to exclude unnecessary files from the Docker context. - Updated Makefile to include a new target for building the Docker image. - Added CI workflows for testing, formatting, and releasing artifacts in Gitea.
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
.git
|
||||||
|
.gitea
|
||||||
|
agent-transcripts
|
||||||
|
bin
|
||||||
|
data
|
||||||
|
node_modules
|
||||||
|
web/ui/node_modules
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "**"
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: Go Tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: make test
|
||||||
|
|
||||||
|
- name: Run race tests
|
||||||
|
run: make test-race
|
||||||
|
|
||||||
|
build:
|
||||||
|
name: Build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: "20"
|
||||||
|
cache: npm
|
||||||
|
cache-dependency-path: web/ui/package-lock.json
|
||||||
|
|
||||||
|
- name: Install UI deps
|
||||||
|
run: npm --prefix ./web/ui ci
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: make build
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
name: Format
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "**"
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
gofmt:
|
||||||
|
name: gofmt
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Verify formatting
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
files="$(gofmt -l .)"
|
||||||
|
if [[ -n "${files}" ]]; then
|
||||||
|
echo "These files need formatting:"
|
||||||
|
echo "${files}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
name: Release Artifacts
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "*"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build ${{ matrix.goos }}/${{ matrix.goarch }} (${{ matrix.variant }})
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- goos: linux
|
||||||
|
goarch: amd64
|
||||||
|
variant: default
|
||||||
|
static: false
|
||||||
|
- goos: linux
|
||||||
|
goarch: amd64
|
||||||
|
variant: alpine-static
|
||||||
|
static: true
|
||||||
|
- goos: linux
|
||||||
|
goarch: arm64
|
||||||
|
variant: default
|
||||||
|
static: false
|
||||||
|
- goos: linux
|
||||||
|
goarch: arm64
|
||||||
|
variant: alpine-static
|
||||||
|
static: true
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: "20"
|
||||||
|
cache: npm
|
||||||
|
cache-dependency-path: web/ui/package-lock.json
|
||||||
|
|
||||||
|
- name: Install UI deps
|
||||||
|
run: npm --prefix ./web/ui ci
|
||||||
|
|
||||||
|
- name: Build UI assets
|
||||||
|
run: npm --prefix ./web/ui run build
|
||||||
|
|
||||||
|
- name: Build binary
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir -p dist
|
||||||
|
if [[ "${{ matrix.static }}" == "true" ]]; then
|
||||||
|
CGO_ENABLED=0 GOOS="${{ matrix.goos }}" GOARCH="${{ matrix.goarch }}" \
|
||||||
|
go build -trimpath -tags "netgo osusergo" \
|
||||||
|
-ldflags "-s -w" \
|
||||||
|
-o "dist/scratchbox-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.variant }}" \
|
||||||
|
./cmd/scratchbox
|
||||||
|
else
|
||||||
|
CGO_ENABLED=0 GOOS="${{ matrix.goos }}" GOARCH="${{ matrix.goarch }}" \
|
||||||
|
go build -trimpath \
|
||||||
|
-ldflags "-s -w" \
|
||||||
|
-o "dist/scratchbox-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.variant }}" \
|
||||||
|
./cmd/scratchbox
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Verify static linux binary
|
||||||
|
if: ${{ matrix.static }}
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
file "dist/scratchbox-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.variant }}" | grep -q "statically linked"
|
||||||
|
|
||||||
|
- name: Package artifact
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir -p artifacts
|
||||||
|
cp README.md artifacts/
|
||||||
|
cp "dist/scratchbox-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.variant }}" artifacts/
|
||||||
|
tar -C artifacts -czf "scratchbox-${{ github.ref_name }}-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.variant }}.tar.gz" .
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: scratchbox-${{ github.ref_name }}-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.variant }}
|
||||||
|
path: scratchbox-${{ github.ref_name }}-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.variant }}.tar.gz
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
FROM golang:1.25-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
# Build-time dependencies for UI and Go compilation.
|
||||||
|
RUN apk add --no-cache nodejs npm
|
||||||
|
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
COPY web/ui/package.json web/ui/package-lock.json ./web/ui/
|
||||||
|
RUN npm --prefix ./web/ui ci
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN npm --prefix ./web/ui run build
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
|
||||||
|
go build -trimpath -tags "netgo osusergo" -ldflags "-s -w" \
|
||||||
|
-o /out/scratchbox ./cmd/scratchbox
|
||||||
|
|
||||||
|
FROM alpine:3.22
|
||||||
|
|
||||||
|
RUN addgroup -S scratchbox && adduser -S -G scratchbox scratchbox
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY --from=builder /out/scratchbox /usr/local/bin/scratchbox
|
||||||
|
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
|
||||||
|
|
||||||
|
RUN chmod +x /usr/local/bin/docker-entrypoint.sh && \
|
||||||
|
mkdir -p /data /config && chown -R scratchbox:scratchbox /data /config
|
||||||
|
|
||||||
|
USER scratchbox
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
VOLUME ["/data", "/config"]
|
||||||
|
|
||||||
|
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
||||||
@@ -3,8 +3,9 @@ CMD_DIR := ./cmd/scratchbox
|
|||||||
BIN_DIR := ./bin
|
BIN_DIR := ./bin
|
||||||
BIN := $(BIN_DIR)/$(APP_NAME)
|
BIN := $(BIN_DIR)/$(APP_NAME)
|
||||||
CONFIG ?= config.yaml
|
CONFIG ?= config.yaml
|
||||||
|
DOCKER_IMAGE ?= scratchbox:dev
|
||||||
|
|
||||||
.PHONY: help run dev config build test test-race fmt clean
|
.PHONY: help run dev config build docker test test-race fmt clean
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo "Targets:"
|
@echo "Targets:"
|
||||||
@@ -12,6 +13,7 @@ help:
|
|||||||
@echo " make dev - Build and run server (CONFIG=$(CONFIG))"
|
@echo " make dev - Build and run server (CONFIG=$(CONFIG))"
|
||||||
@echo " make config - Write default config to $(CONFIG) and generate sibling config.key if missing"
|
@echo " make config - Write default config to $(CONFIG) and generate sibling config.key if missing"
|
||||||
@echo " make build - Build Svelte UI and binary to $(BIN)"
|
@echo " make build - Build Svelte UI and binary to $(BIN)"
|
||||||
|
@echo " make docker - Build Docker image (DOCKER_IMAGE=$(DOCKER_IMAGE))"
|
||||||
@echo " make test - Run all Go tests with timeout and shuffle"
|
@echo " make test - Run all Go tests with timeout and shuffle"
|
||||||
@echo " make test-race - Run all Go tests with race detector and timeout"
|
@echo " make test-race - Run all Go tests with race detector and timeout"
|
||||||
@echo " make fmt - Format Go code"
|
@echo " make fmt - Format Go code"
|
||||||
@@ -32,7 +34,10 @@ config:
|
|||||||
build: clean
|
build: clean
|
||||||
npm --prefix ./web/ui run build
|
npm --prefix ./web/ui run build
|
||||||
mkdir -p $(BIN_DIR)
|
mkdir -p $(BIN_DIR)
|
||||||
go build -o $(BIN) $(CMD_DIR)
|
CGO_ENABLED=0 go build -o $(BIN) $(CMD_DIR)
|
||||||
|
|
||||||
|
docker:
|
||||||
|
docker build -t $(DOCKER_IMAGE) .
|
||||||
|
|
||||||
test:
|
test:
|
||||||
go test -timeout 30s -shuffle=on ./...
|
go test -timeout 30s -shuffle=on ./...
|
||||||
|
|||||||
@@ -23,6 +23,60 @@ Without `--config`, built-in defaults are used.
|
|||||||
If you modify the web UI source (`web/ui`), rebuild frontend assets with:
|
If you modify the web UI source (`web/ui`), rebuild frontend assets with:
|
||||||
- `make build`
|
- `make build`
|
||||||
|
|
||||||
|
## Docker
|
||||||
|
|
||||||
|
Build the container image:
|
||||||
|
|
||||||
|
- `make docker`
|
||||||
|
- Default image tag: `scratchbox:dev`
|
||||||
|
|
||||||
|
Optionally set a custom image name/tag:
|
||||||
|
|
||||||
|
- `make docker DOCKER_IMAGE=scratchbox:latest`
|
||||||
|
|
||||||
|
Run with persistent data and config directories:
|
||||||
|
|
||||||
|
- `mkdir -p ./docker-data ./docker-config`
|
||||||
|
- `docker run --rm -p 8080:8080 -v "$(pwd)/docker-data:/data" -v "$(pwd)/docker-config:/config" scratchbox:dev`
|
||||||
|
|
||||||
|
Inside the container, the default command is:
|
||||||
|
|
||||||
|
- `scratchbox server --config /config/config.yaml`
|
||||||
|
|
||||||
|
Create config files with the image (writes to mounted `./docker-config`):
|
||||||
|
|
||||||
|
- `docker run --rm -v "$(pwd)/docker-config:/config" scratchbox:dev generate-config > ./docker-config/config.yaml`
|
||||||
|
- `docker run --rm -v "$(pwd)/docker-config:/config" scratchbox:dev generate-key > ./docker-config/config.key`
|
||||||
|
|
||||||
|
## Release Artifacts
|
||||||
|
|
||||||
|
Tagged releases provide `.tar.gz` archives with prebuilt Linux binaries.
|
||||||
|
|
||||||
|
Variant guide:
|
||||||
|
|
||||||
|
| Variant | Recommended for | Notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `default` | Most Linux distributions (Ubuntu, Debian, Fedora, Arch, etc.) | Smaller, dynamically linked Linux build |
|
||||||
|
| `alpine-static` | Alpine Linux / musl-based environments | Statically linked for better compatibility |
|
||||||
|
|
||||||
|
To unpack an artifact:
|
||||||
|
|
||||||
|
- `tar -xzf scratchbox-<tag>-linux-amd64-default.tar.gz`
|
||||||
|
|
||||||
|
To unpack into a specific directory:
|
||||||
|
|
||||||
|
- `mkdir -p ./scratchbox-release`
|
||||||
|
- `tar -xzf scratchbox-<tag>-linux-amd64-default.tar.gz -C ./scratchbox-release`
|
||||||
|
|
||||||
|
To run from an unpacked artifact:
|
||||||
|
|
||||||
|
- `./scratchbox-<os>-<arch>-<variant> server --config config.yaml`
|
||||||
|
|
||||||
|
If you do not have a config file yet, generate one first:
|
||||||
|
|
||||||
|
- `go run ./cmd/scratchbox generate-config > config.yaml`
|
||||||
|
- `go run ./cmd/scratchbox generate-key > config.key`
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
All configuration is YAML.
|
All configuration is YAML.
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
# Default to running the server with mounted config.
|
||||||
|
if [ "$#" -eq 0 ]; then
|
||||||
|
set -- server --config /config/config.yaml
|
||||||
|
elif [ "${1#-}" != "$1" ]; then
|
||||||
|
# Allow passing server flags directly, e.g. `docker run ... --config ...`.
|
||||||
|
set -- server "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec scratchbox "$@"
|
||||||
Reference in New Issue
Block a user