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 := $(BIN_DIR)/$(APP_NAME)
|
||||
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:
|
||||
@echo "Targets:"
|
||||
@@ -12,6 +13,7 @@ help:
|
||||
@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 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-race - Run all Go tests with race detector and timeout"
|
||||
@echo " make fmt - Format Go code"
|
||||
@@ -32,7 +34,10 @@ config:
|
||||
build: clean
|
||||
npm --prefix ./web/ui run build
|
||||
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:
|
||||
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:
|
||||
- `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
|
||||
|
||||
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