diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 868a3c0..eba112a 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -10,7 +10,11 @@ on: jobs: build: - uses: daemonless/dbuild/.github/workflows/daemonless-build.yaml@main + # Trial of dbuild#feat/linux-images: back to @main (and no dbuild_ref) + # once that is merged. + uses: daemonless/dbuild/.github/workflows/daemonless-build.yaml@feat/linux-images with: image_name: pkg-cache + dbuild_ref: feat/linux-images + linux: true secrets: inherit diff --git a/Containerfile.linux b/Containerfile.linux new file mode 100644 index 0000000..c185e66 --- /dev/null +++ b/Containerfile.linux @@ -0,0 +1,28 @@ +# pkg-cache on Linux, built only by dbuild's shared GitHub workflow +# (build-linux job): Alpine's nginx with the same config template and +# scripts as the FreeBSD image (root/), supervised by s6. Keep APP_VER with +# Containerfile.j2's: the manifest adds this image to a tag only when the +# versions agree. +FROM alpine:3.24 +ARG APP_VER=1.6 +LABEL org.opencontainers.image.title="Daemonless pkg cache" \ + org.opencontainers.image.description="Managed pkg caching appliance: speeds up FreeBSD, apt, dnf, apk and pacman package fetches across your hosts and builds." \ + org.opencontainers.image.source="https://github.com/daemonless/pkg-cache" \ + org.opencontainers.image.url="https://daemonless.io/images/pkg-cache/" \ + org.opencontainers.image.licenses="BSD-2-Clause" \ + org.opencontainers.image.vendor="daemonless" \ + org.opencontainers.image.authors="daemonless" \ + io.daemonless.category="Infrastructure" \ + io.daemonless.port="80" \ + io.daemonless.volumes="/config,/cache" +RUN apk add --no-cache nginx s6 ca-certificates tzdata && \ + addgroup -g 1000 bsd && adduser -D -H -u 1000 -G bsd -s /sbin/nologin bsd && \ + mkdir -p /app /config /cache /usr/local/etc/nginx && echo "${APP_VER}" > /app/version && \ + chown -R bsd:bsd /var/lib/nginx +COPY root/ / +COPY root-linux/ / +RUN chmod +x /init /etc/cont-init.d/* /etc/services.d/*/run \ + /daemonless/libexec/* /daemonless/init.d/* +EXPOSE 80 +VOLUME ["/config", "/cache"] +ENTRYPOINT ["/init"] diff --git a/root-linux/etc/cont-init.d/10-users b/root-linux/etc/cont-init.d/10-users new file mode 100755 index 0000000..e14ddc4 --- /dev/null +++ b/root-linux/etc/cont-init.d/10-users @@ -0,0 +1,7 @@ +#!/bin/sh +# PUID/PGID for the bsd user nginx's workers run as, as on FreeBSD. +# 20-pkg-cache-init fixes ownership of /config and /cache. +PUID="${PUID:-1000}"; PGID="${PGID:-1000}" +if [ "$(id -g bsd)" != "$PGID" ]; then delgroup bsd 2>/dev/null || true; addgroup -g "$PGID" bsd; fi +if [ "$(id -u bsd)" != "$PUID" ]; then deluser bsd 2>/dev/null || true; adduser -D -H -u "$PUID" -G bsd -s /sbin/nologin bsd; fi +echo "[usermod] User bsd configured (uid=$(id -u bsd), gid=$(id -g bsd))" diff --git a/root-linux/etc/services.d/nginx/run b/root-linux/etc/services.d/nginx/run new file mode 100755 index 0000000..2be36f7 --- /dev/null +++ b/root-linux/etc/services.d/nginx/run @@ -0,0 +1,3 @@ +#!/bin/sh +# Master runs as root to bind :80; workers drop to bsd (user bsd; in the config). +exec nginx -c /run/pkg-cache/nginx.conf -g "daemon off;" diff --git a/root-linux/etc/services.d/pkg-cache-access-log/run b/root-linux/etc/services.d/pkg-cache-access-log/run new file mode 100755 index 0000000..294552e --- /dev/null +++ b/root-linux/etc/services.d/pkg-cache-access-log/run @@ -0,0 +1,2 @@ +#!/bin/sh +exec /daemonless/libexec/pkg-cache-access-log diff --git a/root-linux/etc/services.d/pkg-cache-error-log/run b/root-linux/etc/services.d/pkg-cache-error-log/run new file mode 100755 index 0000000..fcb4312 --- /dev/null +++ b/root-linux/etc/services.d/pkg-cache-error-log/run @@ -0,0 +1,2 @@ +#!/bin/sh +exec /daemonless/libexec/pkg-cache-error-log diff --git a/root-linux/etc/services.d/pkg-cache-logrotate/run b/root-linux/etc/services.d/pkg-cache-logrotate/run new file mode 100755 index 0000000..c18de3d --- /dev/null +++ b/root-linux/etc/services.d/pkg-cache-logrotate/run @@ -0,0 +1,2 @@ +#!/bin/sh +exec /daemonless/libexec/pkg-cache-logrotate diff --git a/root-linux/etc/services.d/pkg-cache-stats/run b/root-linux/etc/services.d/pkg-cache-stats/run new file mode 100755 index 0000000..dcf4d1d --- /dev/null +++ b/root-linux/etc/services.d/pkg-cache-stats/run @@ -0,0 +1,2 @@ +#!/bin/sh +exec /daemonless/libexec/pkg-cache-stats diff --git a/root-linux/init b/root-linux/init new file mode 100755 index 0000000..16ddd6f --- /dev/null +++ b/root-linux/init @@ -0,0 +1,10 @@ +#!/bin/sh +# Minimal init: PUID/PGID, then the same one-shot scripts as the FreeBSD +# image (/daemonless/init.d), then s6 supervises the services. +set -e +for f in /etc/cont-init.d/* /daemonless/init.d/*; do + echo "[init] Running: $f" + "$f" +done +echo "[init] Initialization complete" +exec s6-svscan /etc/services.d diff --git a/root/daemonless/init.d/20-pkg-cache-init b/root/daemonless/init.d/20-pkg-cache-init index 11bbb81..1a77250 100644 --- a/root/daemonless/init.d/20-pkg-cache-init +++ b/root/daemonless/init.d/20-pkg-cache-init @@ -1,7 +1,6 @@ #!/bin/sh # Render and start a managed daemonless pkg-cache appliance config. mkdir -p /config/log /config/stats /cache /run/pkg-cache -cp /defaults/nginx.conf /run/pkg-cache/nginx.conf SIZE="${PKG_CACHE_SIZE:-50g}" UPSTREAM="${PKG_UPSTREAM:-pkg.FreeBSD.org}" @@ -30,9 +29,11 @@ if [ -z "${RESOLVER}" ] || has_newline "${RESOLVER}" || ! printf "%s" "${RESOLVE invalid_env PKG_RESOLVER "${RESOLVER}" fi -sed -i "" "s/max_size=[^ ;]*/max_size=${SIZE}/" /run/pkg-cache/nginx.conf -sed -i "" "s/PKG_UPSTREAM_HOST/${UPSTREAM}/g" /run/pkg-cache/nginx.conf -sed -i "" "s/PKG_RESOLVER/${RESOLVER}/" /run/pkg-cache/nginx.conf +# Not sed -i: FreeBSD's and Linux's take different arguments. +sed -e "s/max_size=[^ ;]*/max_size=${SIZE}/" \ + -e "s/PKG_UPSTREAM_HOST/${UPSTREAM}/g" \ + -e "s/PKG_RESOLVER/${RESOLVER}/" \ + /defaults/nginx.conf > /run/pkg-cache/nginx.conf /daemonless/libexec/pkg-cache-repos /run/pkg-cache/repos.conf /run/pkg-cache/repos.json || exit 1 diff --git a/root/daemonless/libexec/pkg-cache-logrotate b/root/daemonless/libexec/pkg-cache-logrotate index c3c2bc9..1a8b6ea 100644 --- a/root/daemonless/libexec/pkg-cache-logrotate +++ b/root/daemonless/libexec/pkg-cache-logrotate @@ -26,7 +26,8 @@ while true; do for f in access.log error.log; do p="$LOGDIR/$f" [ -f "$p" ] || continue - sz=$(stat -f%z "$p" 2>/dev/null || echo 0) + # ls, not stat: stat's flags differ between FreeBSD and Linux. + sz=$(ls -ln "$p" 2>/dev/null | awk '{print $5}'); sz=${sz:-0} if [ "$sz" -gt "$MAX" ]; then mv -f "$p" "$p.rotating" rotated=1 diff --git a/root/daemonless/libexec/pkg-cache-stats b/root/daemonless/libexec/pkg-cache-stats index ceb025c..dd5d9f7 100644 --- a/root/daemonless/libexec/pkg-cache-stats +++ b/root/daemonless/libexec/pkg-cache-stats @@ -37,7 +37,8 @@ while true; do fi tick=$((tick + 1)) - size=$(stat -f %z "$LOG" 2>/dev/null || echo 0) + # ls, not stat: stat's flags differ between FreeBSD and Linux. + size=$(ls -ln "$LOG" 2>/dev/null | awk '{print $5}'); size=${size:-0} [ "$size" -lt "$offset" ] && offset=0 # log was rotated if [ "$size" -gt "$offset" ]; then tail -c +$((offset + 1)) "$LOG" | head -c $((size - offset)) > "$STATS/new.log"