diff --git a/.dockerignore b/.dockerignore index e014fab..bbbf89a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,10 +1,13 @@ -.git -.codegraph -.superpowers -.worktrees -.tmp -.playwright-mcp -.env +* +!LICENSE +!cmd +!db +!docker +!go.mod +!go.sum +!internal +!protocol +!web **/node_modules **/dist **/*_test.go diff --git a/Dockerfile b/Dockerfile index 36cc560..0b46884 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,19 +2,15 @@ FROM --platform=$BUILDPLATFORM golang:1.27-alpine AS build ARG TARGETOS TARGETARCH ARG VERSION=dev WORKDIR /src -COPY go.mod go.sum ./ -COPY cmd ./cmd -COPY db ./db -COPY internal ./internal -COPY protocol ./protocol +COPY --parents go.mod go.sum cmd db internal protocol ./ RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -trimpath -tags grpcnotrace \ -ldflags "-s -w -X github.com/dihemoe/alisten/internal/bootstrap.version=$VERSION" \ - -o /out/alisten ./cmd/alisten + -o /out/usr/local/bin/alisten ./cmd/alisten \ + && install -Dm644 /etc/ssl/certs/ca-certificates.crt /out/etc/ssl/certs/ca-certificates.crt +COPY LICENSE /out/usr/share/doc/alisten/ FROM gcr.io/distroless/static-debian13:nonroot AS alisten -COPY LICENSE /usr/share/doc/alisten/ -COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt -COPY --from=build /out/alisten /usr/local/bin/alisten +COPY --from=build /out / USER 65532:65532 EXPOSE 8080 9090 HEALTHCHECK --start-period=30s --start-interval=1s --interval=10s --timeout=3s --retries=3 \ diff --git a/docker/build-ffmpeg.sh b/docker/build-ffmpeg.sh new file mode 100644 index 0000000..edf808d --- /dev/null +++ b/docker/build-ffmpeg.sh @@ -0,0 +1,35 @@ +#!/bin/sh +set -eu + +case "$TARGETARCH" in + amd64) arch=x86_64 triple=x86_64-linux-gnu cross_gcc=gcc-x86-64-linux-gnu ;; + arm64) arch=aarch64 triple=aarch64-linux-gnu cross_gcc=gcc-aarch64-linux-gnu ;; +esac + +dpkg --add-architecture "$TARGETARCH" +apt-get update +DEBIAN_FRONTEND=noninteractive apt-get install --yes --no-install-recommends \ + ca-certificates gcc libc6-dev make nasm wget "$cross_gcc" \ + "libc6-dev:$TARGETARCH" "libmp3lame-dev:$TARGETARCH" "zlib1g-dev:$TARGETARCH" + +wget -q --tries=3 --timeout=30 -O /tmp/ffmpeg.tar.gz \ + "https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n$FFMPEG_VERSION.tar.gz" +mkdir /tmp/ffmpeg +tar -xzf /tmp/ffmpeg.tar.gz -C /tmp/ffmpeg --strip-components=1 +cd /tmp/ffmpeg + +audio_decoders=$(sed -n '/\/\* audio codecs \*\//,/\/\* subtitles \*\//s/.*ff_\([a-z0-9_]*\)_decoder;.*/\1/p' \ + libavcodec/allcodecs.c | paste -sd,) +audio_decoders_listed_as_video=comfortnoise,dvaudio,eightsvx_exp,eightsvx_fib,rka,s302m,speex + +./configure \ + --enable-cross-compile --arch="$arch" --target-os=linux --cross-prefix="$triple-" \ + --disable-everything --disable-autodetect --disable-doc --disable-debug --disable-network \ + --disable-ffplay --disable-avdevice --disable-swscale \ + --extra-ldexeflags=-static \ + --enable-zlib --enable-libmp3lame --enable-encoder=libmp3lame \ + --enable-protocol=file --enable-demuxers --enable-parsers --enable-bsfs \ + --enable-muxers --enable-filter=aresample \ + --enable-decoder="$audio_decoders,$audio_decoders_listed_as_video" +make -j"$(nproc)" +install -D -t /out/usr/local/bin ffmpeg ffprobe diff --git a/docker/fetch-tools.sh b/docker/fetch-tools.sh new file mode 100644 index 0000000..895cf6d --- /dev/null +++ b/docker/fetch-tools.sh @@ -0,0 +1,17 @@ +#!/bin/sh +set -eu + +case "$TARGETARCH" in + amd64) ytdlp=yt-dlp_linux deno=x86_64 ;; + arm64) ytdlp=yt-dlp_linux_aarch64 deno=aarch64 ;; +esac + +wget -q --tries=3 --timeout=30 -O /tmp/yt-dlp.zip \ + "https://github.com/yt-dlp/yt-dlp/releases/download/$YTDLP_VERSION/$ytdlp.zip" +wget -q --tries=3 --timeout=30 -O /tmp/deno.zip \ + "https://github.com/denoland/deno/releases/download/$DENO_VERSION/deno-$deno-unknown-linux-gnu.zip" + +mkdir -p /out/opt/yt-dlp /out/usr/local/bin +unzip -q /tmp/yt-dlp.zip -d /out/opt/yt-dlp +unzip -q /tmp/deno.zip -d /out/usr/local/bin +ln -s "/opt/yt-dlp/$ytdlp" /out/usr/local/bin/yt-dlp diff --git a/web/Dockerfile b/web/Dockerfile index b2364ce..b7bf4fb 100644 --- a/web/Dockerfile +++ b/web/Dockerfile @@ -5,16 +5,24 @@ COPY web/package.json web/package-lock.json ./ RUN npm ci COPY web/ . RUN npm run build \ - && find dist -type f \( -name '*.html' -o -name '*.js' -o -name '*.css' -o -name '*.svg' -o -name '*.json' -o -name '*.webmanifest' \) -exec gzip -9 -k {} + \ - && sed "s|@VERSION@|${VERSION}|" nginx/default.conf > /tmp/default.conf + && find dist -type f ! -name '*.png' -exec gzip -9 -k {} + \ + && install -d -m 775 /out/etc/nginx /out/etc/nginx/conf.d \ + && mkdir -p /out/usr/share/nginx \ + && sed "s|@VERSION@|${VERSION}|" nginx/default.conf > /out/etc/nginx/conf.d/default.conf \ + && cp nginx/nginx.conf /out/etc/nginx/nginx.conf \ + && cp -R nginx/templates /out/etc/nginx/alisten-templates \ + && mv dist /out/usr/share/nginx/html +COPY LICENSE /out/usr/share/doc/alisten/ FROM nginxinc/nginx-unprivileged:1.30-alpine ENV NGINX_ENTRYPOINT_QUIET_LOGS=1 -COPY web/nginx/nginx.conf /etc/nginx/nginx.conf -COPY --from=build /tmp/default.conf /etc/nginx/conf.d/default.conf -COPY --from=build /src/dist /usr/share/nginx/html -COPY web/nginx/templates /etc/nginx/alisten-templates -COPY LICENSE /usr/share/doc/alisten/ +COPY --from=build --parents \ + /out/./etc/nginx/nginx.conf \ + /out/./etc/nginx/conf.d/default.conf \ + /out/./etc/nginx/alisten-templates \ + /out/./usr/share/nginx/html \ + /out/./usr/share/doc/alisten/LICENSE \ + / EXPOSE 8080 9090 HEALTHCHECK --start-period=30s --start-interval=1s --interval=10s --timeout=3s --retries=3 \ CMD wget -q -O /dev/null http://127.0.0.1:9090/healthz || exit 1 diff --git a/worker.Dockerfile b/worker.Dockerfile index 5aaf454..fc4a467 100644 --- a/worker.Dockerfile +++ b/worker.Dockerfile @@ -2,37 +2,38 @@ FROM --platform=$BUILDPLATFORM golang:1.27-alpine AS build ARG TARGETOS TARGETARCH ARG VERSION=dev WORKDIR /src -COPY go.mod go.sum ./ -COPY cmd ./cmd -COPY db ./db -COPY internal ./internal -COPY protocol ./protocol +COPY --parents go.mod go.sum cmd db internal protocol ./ RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -trimpath -tags grpcnotrace \ -ldflags "-s -w -X github.com/dihemoe/alisten/internal/bootstrap.version=$VERSION" \ - -o /out/alisten ./cmd/alisten + -o /out/usr/local/bin/alisten ./cmd/alisten +COPY LICENSE /out/usr/share/doc/alisten/ + +FROM --platform=$BUILDPLATFORM debian:trixie-slim AS ffmpeg +ARG TARGETARCH +ARG FFMPEG_VERSION=7.1.5 +COPY docker/build-ffmpeg.sh /tmp/ +RUN sh /tmp/build-ffmpeg.sh FROM --platform=$BUILDPLATFORM golang:1.27-alpine AS tools ARG TARGETARCH ARG YTDLP_VERSION=2026.10.21 ARG DENO_VERSION=v2.9.8 -RUN case "$TARGETARCH" in amd64) ytdlp=yt-dlp_linux deno=x86_64 ;; arm64) ytdlp=yt-dlp_linux_aarch64 deno=aarch64 ;; esac \ - && wget -q --tries=3 --timeout=30 -O /tmp/yt-dlp.zip "https://github.com/yt-dlp/yt-dlp/releases/download/$YTDLP_VERSION/$ytdlp.zip" \ - && wget -q --tries=3 --timeout=30 -O /tmp/deno.zip "https://github.com/denoland/deno/releases/download/$DENO_VERSION/deno-$deno-unknown-linux-gnu.zip" \ - && mkdir -p /out/opt/yt-dlp /out/usr/local/bin \ - && unzip -q /tmp/yt-dlp.zip -d /out/opt/yt-dlp \ - && unzip -q /tmp/deno.zip -d /out/usr/local/bin \ - && ln -s "/opt/yt-dlp/$ytdlp" /out/usr/local/bin/yt-dlp +COPY --from=ffmpeg /out /out +COPY docker/fetch-tools.sh /tmp/ +RUN sh /tmp/fetch-tools.sh FROM debian:trixie-slim AS alisten-worker +COPY --from=tools /out / RUN apt-get update \ - && DEBIAN_FRONTEND=noninteractive apt-get install --yes --no-install-recommends ca-certificates ffmpeg \ + && DEBIAN_FRONTEND=noninteractive apt-get install --yes --no-install-recommends ca-certificates \ && rm -rf /var/lib/apt/lists/* \ && groupadd --system --gid 65532 alisten \ - && useradd --system --uid 65532 --gid alisten --home-dir /var/cache/alisten --no-create-home --shell /usr/sbin/nologin alisten \ - && install -d -o alisten -g alisten /var/cache/alisten -COPY LICENSE /usr/share/doc/alisten/ -COPY --from=tools /out / -COPY --from=build /out/alisten /usr/local/bin/alisten + && useradd --system --uid 65532 --gid alisten --home-dir /var/cache/alisten --no-create-home \ + --shell /usr/sbin/nologin alisten \ + && install -d -o alisten -g alisten /var/cache/alisten \ + && ffmpeg -hide_banner -encoders | grep -q libmp3lame \ + && ffprobe -hide_banner -version >/dev/null +COPY --from=build /out / ENV XDG_CACHE_HOME=/var/cache/alisten USER 65532:65532 EXPOSE 9090