* Create a s6-overlay-extracted stage to copy from This was largely inspired by: @socheatsok78 Our downloaded files are checked where that version doesn't do any verification of the downloads. * Update ffmpeg to the first build with checksums.sha256 * Create a ffmpeg-extracted stage to copy from * Don't preserve ownership from the builder I was sick of the extra work with ffmpeg builds. So, I managed to get sums generated for those builds and now we don't need to manually fill out SHA256 hashes anymore. Now to bump ffmpeg, we can just change the date.
360 lines
10 KiB
Docker
360 lines
10 KiB
Docker
ARG FFMPEG_DATE="2025-01-10-19-43"
|
|
ARG FFMPEG_VERSION="N-118280-g5cd49e1bfd"
|
|
|
|
ARG S6_VERSION="3.2.0.2"
|
|
|
|
ARG SHA256_S6_AMD64="59289456ab1761e277bd456a95e737c06b03ede99158beb24f12b165a904f478"
|
|
ARG SHA256_S6_ARM64="8b22a2eaca4bf0b27a43d36e65c89d2701738f628d1abd0cea5569619f66f785"
|
|
ARG SHA256_S6_NOARCH="6dbcde158a3e78b9bb141d7bcb5ccb421e563523babbe2c64470e76f4fd02dae"
|
|
|
|
ARG ALPINE_VERSION="latest"
|
|
ARG FFMPEG_PREFIX_FILE="ffmpeg-${FFMPEG_VERSION%%-*}"
|
|
ARG FFMPEG_SUFFIX_FILE=".tar.xz"
|
|
|
|
FROM alpine:${ALPINE_VERSION} AS ffmpeg-download
|
|
ARG FFMPEG_DATE
|
|
ARG FFMPEG_VERSION
|
|
ARG FFMPEG_PREFIX_FILE
|
|
ARG FFMPEG_SUFFIX_FILE
|
|
ARG SHA256_FFMPEG_AMD64
|
|
ARG SHA256_FFMPEG_ARM64
|
|
ARG CHECKSUM_ALGORITHM="sha256"
|
|
ARG FFMPEG_CHECKSUM_AMD64="${SHA256_FFMPEG_AMD64}"
|
|
ARG FFMPEG_CHECKSUM_ARM64="${SHA256_FFMPEG_ARM64}"
|
|
|
|
ARG FFMPEG_FILE_SUMS="checksums.${CHECKSUM_ALGORITHM}"
|
|
ARG FFMPEG_URL="https://github.com/yt-dlp/FFmpeg-Builds/releases/download/autobuild-${FFMPEG_DATE}"
|
|
|
|
ARG DESTDIR="/downloaded"
|
|
ARG TARGETARCH
|
|
ADD "${FFMPEG_URL}/${FFMPEG_FILE_SUMS}" "${DESTDIR}/"
|
|
RUN set -eu ; \
|
|
apk --no-cache --no-progress add cmd:aria2c cmd:awk ; \
|
|
\
|
|
aria2c_options() { \
|
|
algorithm="${CHECKSUM_ALGORITHM%[0-9]??}" ; \
|
|
bytes="${CHECKSUM_ALGORITHM#${algorithm}}" ; \
|
|
hash="$( awk -v fn="${1##*/}" '$0 ~ fn"$" { print $1; exit; }' "${DESTDIR}/${FFMPEG_FILE_SUMS}" )" ; \
|
|
\
|
|
printf -- '\t%s\n' \
|
|
'allow-overwrite=true' \
|
|
'always-resume=false' \
|
|
'check-integrity=true' \
|
|
"checksum=${algorithm}-${bytes}=${hash}" \
|
|
'max-connection-per-server=2' \
|
|
; \
|
|
printf -- '\n' ; \
|
|
} ; \
|
|
\
|
|
decide_arch() { \
|
|
case "${TARGETARCH}" in \
|
|
(amd64) printf -- 'linux64' ;; \
|
|
(arm64) printf -- 'linuxarm64' ;; \
|
|
esac ; \
|
|
} ; \
|
|
\
|
|
FFMPEG_ARCH="$(decide_arch)" ; \
|
|
for url in $(awk ' \
|
|
$2 ~ /^[*]?'"${FFMPEG_PREFIX_FILE}"'/ && /-'"${FFMPEG_ARCH}"'-/ { $1=""; print; } \
|
|
' "${DESTDIR}/${FFMPEG_FILE_SUMS}") ; \
|
|
do \
|
|
url="${FFMPEG_URL}/${url# }" ; \
|
|
printf -- '%s\n' "${url}" ; \
|
|
aria2c_options "${url}" ; \
|
|
printf -- '\n' ; \
|
|
done > /tmp/downloads ; \
|
|
unset -v url ; \
|
|
\
|
|
aria2c --no-conf=true \
|
|
--dir /downloaded \
|
|
--lowest-speed-limit='16K' \
|
|
--show-console-readout=false \
|
|
--summary-interval=0 \
|
|
--input-file /tmp/downloads ; \
|
|
\
|
|
apk --no-cache --no-progress add cmd:awk "cmd:${CHECKSUM_ALGORITHM}sum" ; \
|
|
\
|
|
decide_expected() { \
|
|
case "${TARGETARCH}" in \
|
|
(amd64) printf -- '%s' "${FFMPEG_CHECKSUM_AMD64}" ;; \
|
|
(arm64) printf -- '%s' "${FFMPEG_CHECKSUM_ARM64}" ;; \
|
|
esac ; \
|
|
} ; \
|
|
\
|
|
FFMPEG_HASH="$(decide_expected)" ; \
|
|
\
|
|
cd "${DESTDIR}" ; \
|
|
if [ -n "${FFMPEG_HASH}" ] ; \
|
|
then \
|
|
printf -- '%s *%s\n' "${FFMPEG_HASH}" "${FFMPEG_PREFIX_FILE}"*-"${FFMPEG_ARCH}"-*"${FFMPEG_SUFFIX_FILE}" >> /tmp/SUMS ; \
|
|
"${CHECKSUM_ALGORITHM}sum" --check --strict /tmp/SUMS || exit ; \
|
|
fi ; \
|
|
"${CHECKSUM_ALGORITHM}sum" --check --strict --ignore-missing "${DESTDIR}/${FFMPEG_FILE_SUMS}" ; \
|
|
\
|
|
mkdir -v -p "/verified/${TARGETARCH}" ; \
|
|
ln -v "${FFMPEG_PREFIX_FILE}"*-"${FFMPEG_ARCH}"-*"${FFMPEG_SUFFIX_FILE}" "/verified/${TARGETARCH}/" ; \
|
|
rm -rf "${DESTDIR}" ;
|
|
|
|
FROM alpine:${ALPINE_VERSION} AS ffmpeg-extracted
|
|
COPY --link --from=ffmpeg-download /verified /verified
|
|
|
|
ARG FFMPEG_PREFIX_FILE
|
|
ARG FFMPEG_SUFFIX_FILE
|
|
ARG TARGETARCH
|
|
RUN set -eu ; \
|
|
apk --no-cache --no-progress add cmd:tar cmd:xz ; \
|
|
\
|
|
mkdir -v /extracted ; \
|
|
cd /extracted ; \
|
|
set -x ; \
|
|
tar -xp \
|
|
--strip-components=2 \
|
|
--no-anchored \
|
|
--no-same-owner \
|
|
-f "/verified/${TARGETARCH}"/"${FFMPEG_PREFIX_FILE}"*"${FFMPEG_SUFFIX_FILE}" \
|
|
'ffmpeg' 'ffprobe' ; \
|
|
\
|
|
ls -AlR /extracted ;
|
|
|
|
FROM scratch AS s6-overlay-download
|
|
ARG S6_VERSION
|
|
ARG SHA256_S6_AMD64
|
|
ARG SHA256_S6_ARM64
|
|
ARG SHA256_S6_NOARCH
|
|
|
|
ARG DESTDIR="/downloaded"
|
|
ARG CHECKSUM_ALGORITHM="sha256"
|
|
|
|
ARG S6_CHECKSUM_AMD64="${CHECKSUM_ALGORITHM}:${SHA256_S6_AMD64}"
|
|
ARG S6_CHECKSUM_ARM64="${CHECKSUM_ALGORITHM}:${SHA256_S6_ARM64}"
|
|
ARG S6_CHECKSUM_NOARCH="${CHECKSUM_ALGORITHM}:${SHA256_S6_NOARCH}"
|
|
|
|
ARG S6_OVERLAY_URL="https://github.com/just-containers/s6-overlay/releases/download/v${S6_VERSION}"
|
|
ARG S6_PREFIX_FILE="s6-overlay-"
|
|
ARG S6_SUFFIX_FILE=".tar.xz"
|
|
|
|
ARG S6_FILE_AMD64="${S6_PREFIX_FILE}x86_64${S6_SUFFIX_FILE}"
|
|
ARG S6_FILE_ARM64="${S6_PREFIX_FILE}aarch64${S6_SUFFIX_FILE}"
|
|
ARG S6_FILE_NOARCH="${S6_PREFIX_FILE}noarch${S6_SUFFIX_FILE}"
|
|
|
|
ADD "${S6_OVERLAY_URL}/${S6_FILE_AMD64}.${CHECKSUM_ALGORITHM}" "${DESTDIR}/"
|
|
ADD "${S6_OVERLAY_URL}/${S6_FILE_ARM64}.${CHECKSUM_ALGORITHM}" "${DESTDIR}/"
|
|
ADD "${S6_OVERLAY_URL}/${S6_FILE_NOARCH}.${CHECKSUM_ALGORITHM}" "${DESTDIR}/"
|
|
|
|
ADD --checksum="${S6_CHECKSUM_AMD64}" "${S6_OVERLAY_URL}/${S6_FILE_AMD64}" "${DESTDIR}/"
|
|
ADD --checksum="${S6_CHECKSUM_ARM64}" "${S6_OVERLAY_URL}/${S6_FILE_ARM64}" "${DESTDIR}/"
|
|
ADD --checksum="${S6_CHECKSUM_NOARCH}" "${S6_OVERLAY_URL}/${S6_FILE_NOARCH}" "${DESTDIR}/"
|
|
|
|
FROM alpine:${ALPINE_VERSION} AS s6-overlay-extracted
|
|
COPY --link --from=s6-overlay-download /downloaded /downloaded
|
|
|
|
ARG TARGETARCH
|
|
|
|
RUN set -eu ; \
|
|
\
|
|
decide_arch() { \
|
|
local arg1 ; \
|
|
arg1="${1:-$(uname -m)}" ; \
|
|
\
|
|
case "${arg1}" in \
|
|
(amd64) printf -- 'x86_64' ;; \
|
|
(arm64) printf -- 'aarch64' ;; \
|
|
(armv7l) printf -- 'arm' ;; \
|
|
(*) printf -- '%s' "${arg1}" ;; \
|
|
esac ; \
|
|
unset -v arg1 ; \
|
|
} ; \
|
|
\
|
|
mkdir -v /verified ; \
|
|
cd /downloaded ; \
|
|
for f in *.sha256 ; \
|
|
do \
|
|
sha256sum -c < "${f}" || exit ; \
|
|
ln -v "${f%.sha256}" /verified/ || exit ; \
|
|
done ; \
|
|
unset -v f ; \
|
|
\
|
|
S6_ARCH="$(decide_arch "${TARGETARCH}")" ; \
|
|
set -x ; \
|
|
mkdir -v /s6-overlay-rootfs ; \
|
|
cd /s6-overlay-rootfs ; \
|
|
for f in /verified/*.tar* ; \
|
|
do \
|
|
case "${f}" in \
|
|
(*-noarch.tar*|*-"${S6_ARCH}".tar*) \
|
|
tar -xpf "${f}" || exit ;; \
|
|
esac ; \
|
|
done ; \
|
|
set +x ; \
|
|
unset -v f ;
|
|
|
|
FROM debian:bookworm-slim AS tubesync
|
|
|
|
ARG TARGETARCH
|
|
ARG TARGETPLATFORM
|
|
|
|
ARG S6_VERSION
|
|
|
|
ARG FFMPEG_DATE
|
|
ARG FFMPEG_VERSION
|
|
|
|
ENV S6_VERSION="${S6_VERSION}" \
|
|
FFMPEG_DATE="${FFMPEG_DATE}" \
|
|
FFMPEG_VERSION="${FFMPEG_VERSION}"
|
|
|
|
ENV DEBIAN_FRONTEND="noninteractive" \
|
|
HOME="/root" \
|
|
LANGUAGE="en_US.UTF-8" \
|
|
LANG="en_US.UTF-8" \
|
|
LC_ALL="en_US.UTF-8" \
|
|
TERM="xterm" \
|
|
S6_CMD_WAIT_FOR_SERVICES_MAXTIME="0"
|
|
|
|
# Install third party software
|
|
COPY --link --from=s6-overlay-extracted /s6-overlay-rootfs /
|
|
COPY --link --from=ffmpeg-extracted /extracted /usr/local/bin/
|
|
|
|
# Reminder: the SHELL handles all variables
|
|
RUN set -x && \
|
|
apt-get update && \
|
|
apt-get -y --no-install-recommends install locales && \
|
|
printf -- "en_US.UTF-8 UTF-8\n" > /etc/locale.gen && \
|
|
locale-gen en_US.UTF-8 && \
|
|
# Install required distro packages
|
|
apt-get -y --no-install-recommends install curl ca-certificates file binutils xz-utils && \
|
|
# Installed s6 (using COPY earlier)
|
|
file -L /command/s6-overlay-suexec && \
|
|
# Installed ffmpeg (using COPY earlier)
|
|
/usr/local/bin/ffmpeg -version && \
|
|
file /usr/local/bin/ff* && \
|
|
# Clean up
|
|
apt-get -y autoremove --purge file binutils xz-utils && \
|
|
rm -rf /var/lib/apt/lists/* && \
|
|
rm -rf /var/cache/apt/* && \
|
|
rm -rf /tmp/*
|
|
|
|
# Install dependencies we keep
|
|
RUN set -x && \
|
|
apt-get update && \
|
|
# Install required distro packages
|
|
apt-get -y --no-install-recommends install \
|
|
libjpeg62-turbo \
|
|
libmariadb3 \
|
|
libpq5 \
|
|
libwebp7 \
|
|
nginx-light \
|
|
pipenv \
|
|
pkgconf \
|
|
python3 \
|
|
python3-wheel \
|
|
redis-server \
|
|
curl \
|
|
less \
|
|
&& apt-get -y autoclean && \
|
|
rm -rf /var/lib/apt/lists/* && \
|
|
rm -rf /var/cache/apt/* && \
|
|
rm -rf /tmp/*
|
|
|
|
# Copy over pip.conf to use piwheels
|
|
COPY pip.conf /etc/pip.conf
|
|
|
|
# Add Pipfile
|
|
COPY Pipfile /app/Pipfile
|
|
|
|
# Do not include compiled byte-code
|
|
ENV PIP_NO_COMPILE=1 \
|
|
PIP_NO_CACHE_DIR=1 \
|
|
PIP_ROOT_USER_ACTION='ignore'
|
|
|
|
# Switch workdir to the the app
|
|
WORKDIR /app
|
|
|
|
# Set up the app
|
|
#BuildKit#RUN --mount=type=bind,source=Pipfile,target=/app/Pipfile \
|
|
RUN \
|
|
set -x && \
|
|
apt-get update && \
|
|
# Install required build packages
|
|
apt-get -y --no-install-recommends install \
|
|
default-libmysqlclient-dev \
|
|
g++ \
|
|
gcc \
|
|
libjpeg-dev \
|
|
libpq-dev \
|
|
libwebp-dev \
|
|
make \
|
|
postgresql-common \
|
|
python3-dev \
|
|
python3-pip \
|
|
zlib1g-dev \
|
|
&& \
|
|
# Create a 'app' user which the application will run as
|
|
groupadd app && \
|
|
useradd -M -d /app -s /bin/false -g app app && \
|
|
# Install non-distro packages
|
|
cp -at /tmp/ "${HOME}" && \
|
|
PIPENV_VERBOSITY=64 HOME="/tmp/${HOME#/}" pipenv install --system --skip-lock && \
|
|
# Clean up
|
|
rm /app/Pipfile && \
|
|
pipenv --clear && \
|
|
apt-get -y autoremove --purge \
|
|
default-libmysqlclient-dev \
|
|
g++ \
|
|
gcc \
|
|
libjpeg-dev \
|
|
libpq-dev \
|
|
libwebp-dev \
|
|
make \
|
|
postgresql-common \
|
|
python3-dev \
|
|
python3-pip \
|
|
zlib1g-dev \
|
|
&& \
|
|
apt-get -y autoremove && \
|
|
apt-get -y autoclean && \
|
|
rm -rf /var/lib/apt/lists/* && \
|
|
rm -rf /var/cache/apt/* && \
|
|
rm -rf /tmp/*
|
|
|
|
|
|
# Copy app
|
|
COPY tubesync /app
|
|
COPY tubesync/tubesync/local_settings.py.container /app/tubesync/local_settings.py
|
|
|
|
# Build app
|
|
RUN set -x && \
|
|
# Make absolutely sure we didn't accidentally bundle a SQLite dev database
|
|
rm -rf /app/db.sqlite3 && \
|
|
# Run any required app commands
|
|
/usr/bin/python3 -B /app/manage.py compilescss && \
|
|
/usr/bin/python3 -B /app/manage.py collectstatic --no-input --link && \
|
|
# Create config, downloads and run dirs
|
|
mkdir -v -p /run/app && \
|
|
mkdir -v -p /config/media && \
|
|
mkdir -v -p /config/cache/pycache && \
|
|
mkdir -v -p /downloads/audio && \
|
|
mkdir -v -p /downloads/video
|
|
|
|
|
|
# Append software versions
|
|
RUN set -x && \
|
|
ffmpeg_version=$(/usr/local/bin/ffmpeg -version | awk -v 'ev=31' '1 == NR && "ffmpeg" == $1 { print $3; ev=0; } END { exit ev; }') && \
|
|
test -n "${ffmpeg_version}" && \
|
|
printf -- "ffmpeg_version = '%s'\n" "${ffmpeg_version}" >> /app/common/third_party_versions.py
|
|
|
|
# Copy root
|
|
COPY config/root /
|
|
|
|
# Create a healthcheck
|
|
HEALTHCHECK --interval=1m --timeout=10s CMD /app/healthcheck.py http://127.0.0.1:8080/healthcheck
|
|
|
|
# ENVS and ports
|
|
ENV PYTHONPATH="/app" PYTHONPYCACHEPREFIX="/config/cache/pycache"
|
|
EXPOSE 4848
|
|
|
|
# Volumes
|
|
VOLUME ["/config", "/downloads"]
|
|
|
|
# Entrypoint, start s6 init
|
|
ENTRYPOINT ["/init"]
|