From e0694b2374b00dffb19316c599e1ef9c877b7ef5 Mon Sep 17 00:00:00 2001 From: Veillax <126523099+Veillax@users.noreply.github.com> Date: Tue, 27 Oct 2026 18:36:06 -0600 Subject: [PATCH] Add Dockerfile, TrueNAS SCALE compose file and image publishing on release --- .gitea/workflows/release.yml | 23 +++++++++++++++++++++++ Dockerfile | 20 ++++++++++++++++++++ README.md | 23 ++++++++++++++++++----- deploy/build.sh | 4 +++- deploy/docker-compose.yml | 15 +++++++++++++++ 5 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 Dockerfile create mode 100644 deploy/docker-compose.yml diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 71c481b..fe27eca 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -37,3 +37,26 @@ jobs: env: TOKEN: ${{ secrets.RELEASE_TOKEN || secrets.GITHUB_TOKEN }} run: sh deploy/publish-release.sh "${GITHUB_REF_NAME}" + + # Skipped when the repository variable PUBLISH_DOCKER is "false", or fails alone + # if this runner has no Docker: the release above is already published by then. + # Optional secret REGISTRY_TOKEN (and variable REGISTRY_USER): an access token + # with package write permission, for servers where the job token can't push. + - name: Build and push the container image + if: ${{ vars.PUBLISH_DOCKER != 'false' }} + env: + REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN || secrets.GITHUB_TOKEN }} + REGISTRY_USER: ${{ vars.REGISTRY_USER || github.actor }} + run: | + host=${GITHUB_SERVER_URL#*://} + owner=$(echo "$GITHUB_REPOSITORY_OWNER" | tr 'A-Z' 'a-z') + image="$host/$owner/beach" + echo "$REGISTRY_TOKEN" | docker login "$host" -u "$REGISTRY_USER" --password-stdin + # a container-driver builder can build several architectures in one go + docker buildx create --name release --driver docker-container --use >/dev/null 2>&1 || docker buildx use release + tags="-t $image:$GITHUB_REF_NAME" + case "$GITHUB_REF_NAME" in + *-*) ;; # pre-releases (v1.0.0-rc1) don't move :latest + *) tags="$tags -t $image:latest" ;; + esac + docker buildx build --platform linux/amd64 $tags --push . diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..814632f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +# syntax=docker/dockerfile:1 +# Packages the binary deploy/build.sh already built (dist/bin/linux_/beach), so no +# emulation is needed. Build it with: sh deploy/build.sh && docker buildx build . +# +# Beach runs as root in the container: to start and stop containers it must read the +# Docker socket, and the socket's group id differs from host to host. smartmontools is +# there for the optional "smartctl" source (it also needs the devices passed in). +FROM alpine:3.22 +ARG TARGETARCH +LABEL org.opencontainers.image.title="Beach" \ + org.opencontainers.image.description="One-page control panel for a homelab: containers, pools, disks and tunnels" \ + org.opencontainers.image.source="https://git.veillax.com/Veillax/beach" \ + org.opencontainers.image.licenses="MIT" +RUN apk add --no-cache ca-certificates smartmontools \ + && mkdir /data +COPY dist/bin/linux_${TARGETARCH}/beach /beach +VOLUME ["/data"] +EXPOSE 8095 +ENTRYPOINT ["/beach"] +CMD ["-listen", ":8095", "-data", "/data/beach.db"] diff --git a/README.md b/README.md index 7aed3e2..225b50b 100644 --- a/README.md +++ b/README.md @@ -31,15 +31,28 @@ There are two flags only: `-listen` and `-data`. There is no config file or envi ## Running in Docker -Mount the Docker socket (this gives the container control of Docker, which is what the start/stop buttons need) and, for host metrics, run it with the host's `/proc` visible: +Tagged releases publish an image to this server's container registry (`git.veillax.com/veillax/beach`). +To build one yourself: `sh deploy/build.sh && docker buildx build -t beach .`. + +Mount the Docker socket (this gives the container control of Docker, which is what the start/stop buttons need): ``` -docker run -d --name beach -p 127.0.0.1:8095:8095 -v beach:/data \ - -v /var/run/docker.sock:/var/run/docker.sock \ - beach -data /data/beach.db +docker run -d --name beach -p 127.0.0.1:8095:8095 -v beach:/data -v /var/run/docker.sock:/var/run/docker.sock git.veillax.com/veillax/beach:latest ``` -(There is no published image yet: build one from `go build` output in a `scratch`/`distroless` image.) +CPU, memory, load and uptime are the host's even inside a container; the filesystem list is the container's own, +so on TrueNAS rely on its API for pools and disks. + +## TrueNAS SCALE + +1. Apps, then Discover Apps, then Custom App, then Install via YAML. Paste [deploy/docker-compose.yml](deploy/docker-compose.yml) + and change the data path to a dataset (for example `/mnt//apps/beach`). +2. If the registry is private, add it under Apps, Configuration, Docker Registry Settings first. +3. Open `http://:8095`, create the administrator, then in **Settings** add TrueNAS (`https://` + and an API key from Credentials, API Keys; tick "self-signed certificate" if needed), Docker, and Hammerhead. + +smartctl in the container needs the disks passed in (`privileged: true`); TrueNAS's API already reports SMART data and +temperatures, so you can leave it off. ## Security notes diff --git a/deploy/build.sh b/deploy/build.sh index d13a767..8cf458b 100644 --- a/deploy/build.sh +++ b/deploy/build.sh @@ -4,6 +4,7 @@ # deploy/build.sh [version] version defaults to `git describe` # # Output: +# dist/bin/_/beach the raw binary (the Docker image uses the linux ones) # dist/beach___.tar.gz or .zip # dist/SHA256SUMS # @@ -17,7 +18,7 @@ VERSION=${1:-$(git describe --tags --always 2>/dev/null || echo dev)} TARGETS=${TARGETS:-"linux/amd64 windows/amd64"} rm -rf dist -mkdir -p dist/stage +mkdir -p dist/bin dist/stage for t in $TARGETS; do os=${t%/*} arch=${t#*/} @@ -29,6 +30,7 @@ for t in $TARGETS; do for c in $CMDS; do echo "building $c $VERSION for $os/$arch" CGO_ENABLED=0 GOOS=$os GOARCH=$arch go build -trimpath -ldflags "-s -w -X main.version=$VERSION" -o "$stage/$c$ext" "./cmd/$c" + mkdir -p "dist/bin/${os}_${arch}" && cp "$stage/$c$ext" "dist/bin/${os}_${arch}/" done for f in LICENSE README.md; do [ -f "$f" ] && cp "$f" "$stage/" diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml new file mode 100644 index 0000000..f719f15 --- /dev/null +++ b/deploy/docker-compose.yml @@ -0,0 +1,15 @@ +# Beach as a TrueNAS SCALE app (Apps -> Discover Apps -> Custom App -> Install via YAML), +# or on any Docker host. Change the image to match your registry and the release you want. +services: + beach: + image: git.veillax.com/veillax/beach:latest + restart: unless-stopped + ports: + - "8095:8095" + volumes: + # Beach's database. On TrueNAS use a dataset path, e.g. /mnt//apps/beach + - /mnt/tank/apps/beach:/data + # Lets Beach list, start and stop containers. This gives it control of Docker. + - /var/run/docker.sock:/var/run/docker.sock + # Only for the optional smartctl source; TrueNAS's API already reports SMART data. + # privileged: true