From 5c5942d99514b433e09d90624bbe58992eab6be2 Mon Sep 17 00:00:00 2001 From: outlook84 <96007761+outlook84@users.noreply.github.com> Date: Sun, 13 Jul 2025 14:37:20 +0800 Subject: [PATCH] build: lightweight busybox-based container build (#5285) --- .goreleaser.yml | 11 ----------- Dockerfile | 36 +++++++++++++++++++++++++----------- docker/alpine/healthcheck.sh | 9 +++++++++ docker/alpine/init.sh | 31 ++++++++++++++++++++++--------- 4 files changed, 56 insertions(+), 31 deletions(-) create mode 100644 docker/alpine/healthcheck.sh diff --git a/.goreleaser.yml b/.goreleaser.yml index e59ef7f9..57b7b44a 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -40,17 +40,6 @@ archives: - goos: windows formats: ["zip"] -upx: - - enabled: true - goos: - - linux - - darwin - goarch: - - amd64 - - arm64 - compress: "best" - lzma: true - dockers: # Alpine docker images - dockerfile: Dockerfile diff --git a/Dockerfile b/Dockerfile index 68dec799..8bd825da 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,23 +1,37 @@ -FROM alpine:3.22 +## Multistage build: First stage fetches dependencies +FROM alpine:3.22 AS fetcher +# install and copy ca-certificates, mailcap, and tini-static; download JSON.sh RUN apk update && \ - apk --no-cache add ca-certificates mailcap jq tini + apk --no-cache add ca-certificates mailcap tini-static && \ + wget -O /JSON.sh https://raw.githubusercontent.com/dominictarr/JSON.sh/0d5e5c77365f63809bf6e77ef44a1f34b0e05840/JSON.sh -# Make user and create necessary directories +## Second stage: Use lightweight BusyBox image for final runtime environment +FROM busybox:1.37.0-musl + +# Define non-root user UID and GID ENV UID=1000 ENV GID=1000 +# Create user group and user RUN addgroup -g $GID user && \ - adduser -D -u $UID -G user user && \ - mkdir -p /config /database /srv && \ - chown -R user:user /config /database /srv + adduser -D -u $UID -G user user -# Copy files and set permissions -COPY filebrowser /bin/filebrowser -COPY docker/common/ / -COPY docker/alpine/ / +# Copy binary, scripts, and configurations into image with proper ownership +COPY --chown=user:user filebrowser /bin/filebrowser +COPY --chown=user:user docker/common/ / +COPY --chown=user:user docker/alpine/ / +COPY --chown=user:user --from=fetcher /sbin/tini-static /bin/tini +COPY --from=fetcher /JSON.sh /JSON.sh +COPY --from=fetcher /etc/ca-certificates.conf /etc/ca-certificates.conf +COPY --from=fetcher /etc/ca-certificates /etc/ca-certificates +COPY --from=fetcher /etc/mime.types /etc/mime.types +COPY --from=fetcher /etc/ssl /etc/ssl -RUN chown -R user:user /bin/filebrowser /defaults healthcheck.sh init.sh +# Create data directories, set ownership, and ensure healthcheck script is executable +RUN mkdir -p /config /database /srv && \ + chown -R user:user /config /database /srv \ + && chmod +x /healthcheck.sh # Define healthcheck script HEALTHCHECK --start-period=2s --interval=5s --timeout=3s CMD /healthcheck.sh diff --git a/docker/alpine/healthcheck.sh b/docker/alpine/healthcheck.sh new file mode 100644 index 00000000..70e71bf6 --- /dev/null +++ b/docker/alpine/healthcheck.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +set -e + +PORT=${FB_PORT:-$(cat /tmp/FB_CONFIG | sh /JSON.sh | grep '\["port"\]' | awk '{print $2}')} +ADDRESS=${FB_ADDRESS:-$(cat /tmp/FB_CONFIG | sh /JSON.sh | grep '\["address"\]' | awk '{print $2}' | sed 's/"//g')} +ADDRESS=${ADDRESS:-localhost} + +wget -q --spider http://$ADDRESS:$PORT/health || exit 1 \ No newline at end of file diff --git a/docker/alpine/init.sh b/docker/alpine/init.sh index ccd04cd4..5ea2cf6e 100755 --- a/docker/alpine/init.sh +++ b/docker/alpine/init.sh @@ -7,19 +7,32 @@ if [ ! -f "/config/settings.json" ]; then cp -a /defaults/settings.json /config/settings.json fi -# Deal with the case where user does not provide a config argument -has_config_arg=0 +# Extract config file path from arguments +config_file="" +next_is_config=0 for arg in "$@"; do - case "$arg" in - --config|--config=*|-c|-c=*) - has_config_arg=1 + if [ "$next_is_config" -eq 1 ]; then + config_file="$arg" break - ;; + fi + case "$arg" in + -c|--config) + next_is_config=1 + ;; + -c=*|--config=*) + config_file="${arg#*=}" + break + ;; esac done -if [ "$has_config_arg" -eq 0 ]; then - set -- --config=/config/settings.json "$@" -fi +# If no config argument is provided, set the default and add it to the args +if [ -z "$config_file" ]; then + config_file="/config/settings.json" + set -- --config=/config/settings.json "$@" +fi + +# Create a symlink to the config file for compatibility with the healthcheck script +ln -s "$config_file" /tmp/FB_CONFIG exec filebrowser "$@" \ No newline at end of file