2
0
mirror of https://github.com/spritsail/plex-media-server.git synced 2024-11-05 01:16:23 +00:00
plex-media-server/Dockerfile
Joe Groocock 074e4476a8
Build Plex on musl, from scratch
Plex now provide a first-party musl Plex build that works without any
external dependencies whatsoever. It's built with LLVM with many
compiler and linker optimisations enabled:
https://forums.plex.tv/t/plex-media-server-forum-preview-faster-and-smaller-builds-with-new-toolchain/699575

Restructure build into multiple distinct Docker build stages to better
leverage caching and significantly improve build time on multicore
systems with BuildKit, particularly with LTO enabled.

Changes for this release include:
- Build `FROM spritsail/alpine` instead of `FROM debian` to ensure musl
  compatibility with all compiled binaries. Use `FROM scratch` for the
  resulting image. ld-musl is provided by Plex.
- Build busybox, su-exec and tini as they're no longer provided by the
  base image.
- Build binaries/libraries with standard hardening flags, including the
  popular -flto.

Signed-off-by: Joe Groocock <me@frebib.net>
2021-05-04 21:38:06 +01:00

368 lines
9.9 KiB
Docker

ARG PLEX_VER=1.23.0.4482-62106842a
ARG PLEX_SHA=022f2ac2a18ec602f0402baf94d69f405b9207a4
ARG BUSYBOX_VER=1.33.0
ARG SU_EXEC_VER=0.4
ARG TINI_VER=0.19.0
ARG ZLIB_VER=1.2.11
ARG LIBXML2_VER=v2.9.10
ARG LIBXSLT_VER=v1.1.34
ARG XMLSTAR_VER=1.6.1
ARG OPENSSL_VER=1.1.1i
ARG CURL_VER=curl-7_76_1
ARG OUTPUT=/output
ARG DESTDIR=/prefix
ARG CFLAGS="-O2 -pipe -fstack-protector-strong -D_FORTIFY_SOURCE=2 -flto"
ARG LDFLAGS="$CFLAGS -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FROM spritsail/alpine:3.13 AS builder
RUN apk add --no-cache \
autoconf \
automake \
binutils \
cmake \
curl \
dpkg \
file \
gcc \
git \
libtool \
linux-headers \
make \
musl-dev \
nghttp2-dev \
pkgconfig \
xxd
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FROM builder AS plex
ARG PLEX_VER
ARG PLEX_SHA
ARG OUTPUT
WORKDIR $OUTPUT
# Fetch Plex and required libraries
RUN curl -fsSL -o plexmediaserver.deb https://downloads.plex.tv/plex-media-server-new/${PLEX_VER}/debian/plexmediaserver_${PLEX_VER}_amd64.deb \
&& echo "$PLEX_SHA plexmediaserver.deb" | sha1sum -c - \
&& dpkg-deb -x plexmediaserver.deb . \
\
&& rm -r \
etc/ usr/share/ \
plexmediaserver.deb \
\
&& cd usr/lib/plexmediaserver \
&& rm \
lib/libcrypto.so* \
lib/libcurl.so* \
lib/libssl.so* \
lib/libnghttp2.so* \
lib/libxml2.so* \
lib/libxslt.so* \
lib/libexslt.so* \
lib/plexmediaserver.* \
etc/ld-musl-x86_64.path \
Resources/start.sh \
\
# Place shared libraries in usr/lib so they can be actually shared
&& mv lib/*.so* lib/dri ../ \
&& rmdir lib etc \
&& ln -sv ../ lib \
# Replace hardlink with a symlink; these files are the same
&& cd .. && ln -sfvn ld-musl-x86_64.so.1 libc.so
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FROM builder AS busybox
ARG BUSYBOX_VER
ARG SU_EXEC_VER
ARG TINI_VER
ARG CFLAGS
ARG LDFLAGS
ARG MAKEFLAGS
ARG OUTPUT
WORKDIR /tmp/busybox
RUN curl -fsSL https://busybox.net/downloads/busybox-${BUSYBOX_VER}.tar.bz2 \
| tar xj --strip-components=1 \
&& make defconfig \
&& make \
&& install -Dm755 busybox "$OUTPUT/usr/bin/busybox" \
# "Install" busybox, creating symlinks to all binaries it provides
&& mkdir -p "$OUTPUT/usr/bin" "$OUTPUT/usr/sbin" \
&& ./busybox --list-full | sed -E 's@^(s?bin)@usr/\1@' | xargs -i ln -Tsv /usr/bin/busybox "$OUTPUT/{}"
WORKDIR /tmp/su-exec
RUN curl -fL https://github.com/frebib/su-exec/archive/v${SU_EXEC_VER}.tar.gz \
| tar xz --strip-components=1 \
&& make \
&& install -Dm755 su-exec "$OUTPUT/usr/sbin/su-exec"
WORKDIR /tmp/tini
RUN curl -fL https://github.com/krallin/tini/archive/v${TINI_VER}.tar.gz \
| tar xz --strip-components=1 \
&& cmake . \
&& make tini \
&& install -Dm755 tini "$OUTPUT/usr/sbin/tini"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FROM builder AS zlib
ARG ZLIB_VER
ARG CFLAGS
ARG LDFLAGS
ARG MAKEFLAGS
ARG OUTPUT
ARG DESTDIR
WORKDIR /tmp/zlib
RUN curl -sSf https://www.zlib.net/zlib-$ZLIB_VER.tar.xz \
| tar xJ --strip-components=1 \
&& ./configure \
--prefix=/usr \
--shared \
&& make DESTDIR="$DESTDIR" install \
&& mkdir -p "$OUTPUT/usr/lib" \
&& cp -a "$DESTDIR"/usr/lib/*.so* "$OUTPUT/usr/lib"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FROM builder AS xml
ARG LIBXML2_VER
ARG LIBXSLT_VER
ARG XMLSTAR_VER
ARG CFLAGS
ARG LDFLAGS
ARG MAKEFLAGS
ARG OUTPUT
ARG DESTDIR
COPY --from=zlib "$DESTDIR" "$DESTDIR"
WORKDIR /tmp/libxml2
RUN git clone https://gitlab.gnome.org/GNOME/libxml2.git --branch $LIBXML2_VER --depth 1 . \
&& ./autogen.sh \
--prefix=/usr \
--with-zlib="$DESTDIR/usr" \
--without-catalog \
--without-docbook \
--without-ftp \
--without-http \
--without-iconv \
--without-iso8859x \
--without-legacy \
--without-modules \
--without-python \
&& make DESTDIR="$DESTDIR" install \
&& mkdir -p "$OUTPUT/usr/lib" \
&& cp -a "$DESTDIR"/usr/lib/*.so* "$OUTPUT/usr/lib"
WORKDIR /tmp/libxslt
RUN git clone https://gitlab.gnome.org/GNOME/libxslt.git --branch $LIBXSLT_VER --depth 1 . \
&& ./autogen.sh \
--prefix=/usr \
--with-libxml-src=../libxml2 \
--without-crypto \
--without-plugins \
--without-python \
&& make DESTDIR="$DESTDIR" install \
&& mkdir -p "$OUTPUT/usr/lib" \
&& cp -a "$DESTDIR"/usr/lib/*.so* "$OUTPUT/usr/lib"
ADD xmlstarlet-*.patch /tmp
WORKDIR /tmp/xmlstarlet
RUN git clone git://git.code.sf.net/p/xmlstar/code --branch $XMLSTAR_VER --depth 1 . \
&& git apply /tmp/xmlstarlet*.patch \
&& autoreconf -sif \
&& ./configure \
--prefix=/usr \
--disable-build-docs \
--with-libxml-prefix="$DESTDIR/usr" \
--with-libxslt-prefix="$DESTDIR/usr" \
&& make DESTDIR="$DESTDIR" install \
&& install -Dm755 "$DESTDIR/usr/bin/xml" "$OUTPUT/usr/bin/xmlstarlet"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FROM builder AS curl
ARG OPENSSL_VER
ARG CURL_VER
ARG CFLAGS
ARG LDFLAGS
ARG MAKEFLAGS
ARG OUTPUT
ARG DESTDIR
COPY --from=zlib "$DESTDIR" "$DESTDIR"
WORKDIR /tmp/openssl
RUN curl -sSL https://openssl.org/source/openssl-${OPENSSL_VER}.tar.gz \
| tar xz --strip-components=1 \
&& ./config \
--prefix=/usr \
--libdir=lib \
--with-zlib-lib="$DESTDIR/usr/lib" \
--with-zlib-include="$DESTDIR/usr/include" \
shared \
zlib-dynamic \
no-engine \
no-rc5 \
no-ssl3-method \
&& make build_libs \
&& make build_programs \
&& make DESTDIR="$DESTDIR" \
install_sw \
install_ssldirs \
&& mkdir -p "$OUTPUT/usr/lib" \
&& cp -a "$DESTDIR"/usr/lib/*.so* "$OUTPUT/usr/lib" \
&& sed -i "s@prefix=/usr@prefix=$DESTDIR/usr@g" "$DESTDIR"/usr/lib/pkgconfig/*.pc
# /usr/lib # curl --version
# curl 7.74.0-DEV (x86_64-pc-linux-musl) libcurl/7.73.0-DEV OpenSSL/1.1.1i zlib/1.2.11 nghttp2/1.41.0
# Protocols: http https
# Features: AsynchDNS HTTP2 HTTPS-proxy IPv6 Largefile libz SSL UnixSockets
WORKDIR /tmp/curl
RUN git clone https://github.com/curl/curl.git --branch $CURL_VER --depth 1 . \
&& autoreconf -sif \
&& ./configure \
--prefix=/usr \
--enable-http \
--enable-ipv6 \
--enable-largefile \
--enable-proxy \
--enable-unix-sockets \
--with-ssl="$DESTDIR/usr" \
--with-zlib="$DESTDIR/usr" \
--enable-optimize \
--enable-symbol-hiding \
--enable-versioned-symbols \
--enable-threaded-resolver \
--disable-cookies \
--disable-crypto-auth \
--disable-curldebug \
--disable-dependency-tracking \
--disable-dict \
--disable-file \
--disable-ftp \
--disable-gopher \
--disable-imap \
--disable-ldap \
--disable-ldaps \
--disable-libcurl-option \
--disable-manual \
--disable-mqtt \
--disable-ntlm-wb \
--disable-pop3 \
--disable-rtsp \
--disable-smb \
--disable-smtp \
--disable-sspi \
--disable-telnet \
--disable-tftp \
--disable-tls-srp \
--disable-verbose \
--without-axtls \
--without-libmetalink \
--without-libpsl \
--without-librtmp \
--without-winidn \
&& make DESTDIR="$DESTDIR" install \
&& install -Dm755 "$DESTDIR/usr/bin/curl" "$OUTPUT/usr/bin/curl" \
# Cheat and "borrow" libnghttp2 from Alpine
&& mkdir -p "$OUTPUT/usr/lib" \
&& cp -a "$DESTDIR"/usr/lib/*.so* /usr/lib/libnghttp2.so* "$OUTPUT/usr/lib"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FROM builder AS combine
ARG OUTPUT
WORKDIR $OUTPUT
COPY --from=plex "$OUTPUT" .
COPY --from=busybox "$OUTPUT" .
COPY --from=zlib "$OUTPUT" .
COPY --from=xml "$OUTPUT" .
COPY --from=curl "$OUTPUT" .
RUN install -m 1777 -o root -g root -d tmp \
&& ln -sv /usr/lib /usr/bin /usr/sbin . \
# Link Plex ca-certificates as system store so curl and others can use them too
&& mkdir -p etc/ssl/certs \
&& ln -sv /usr/lib/plexmediaserver/Resources/cacert.pem etc/ssl/certs/ca-certificates.crt \
# Strip all unneeded symbols for optimum size
&& find . -type f -exec sh -c 'file "{}" | grep -q ELF && strip --strip-debug "{}"' \;
ADD --chmod=755 \
entrypoint \
claim-server.sh \
gen-config.sh \
plex-util.sh \
usr/bin/
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FROM scratch
ARG PLEX_VER
ARG XMLSTAR_VER
ARG BUSYBOX_VER
ARG SU_EXEC_VER
ARG TINI_VER
ARG OPENSSL_VER
ARG CURL_VER
ARG OUTPUT
LABEL maintainer="Spritsail <plex@spritsail.io>" \
org.label-schema.vendor="Spritsail" \
org.label-schema.name="Plex Media Server" \
org.label-schema.url="https://www.plex.tv/downloads/" \
org.label-schema.description="Tiny Docker image for Plex Media Server, built on busybox" \
org.label-schema.version=${PLEX_VER} \
io.spritsail.version.plex=${PLEX_VER} \
io.spritsail.version.xmlstarlet=${XMLSTAR_VER} \
io.spritsail.version.busybox=${BUSYBOX_VER} \
io.spritsail.version.su-exec=${SU_EXEC_VER} \
io.spritsail.version.tini=${TINI_VER} \
io.spritsail.version.openssl=${OPENSSL_VER} \
io.spritsail.version.curl=${CURL_VER}
WORKDIR /usr/lib/plexmediaserver
COPY --from=combine "$OUTPUT" /
ENV SUID=900 SGID=900 \
PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS="6" \
PLEX_MEDIA_SERVER_MAX_STACK_SIZE="3000" \
PLEX_MEDIA_SERVER_TMPDIR="/tmp" \
PLEX_MEDIA_SERVER_HOME="/usr/lib/plexmediaserver" \
PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR="/var/lib/plexmediaserver"
HEALTHCHECK --interval=10s --timeout=5s \
CMD [ "wget", "-O", "/dev/null", "-T", "10", "-q", "localhost:32400/identity" ]
EXPOSE 32400
VOLUME ["/config", "/transcode"]
RUN mkdir -p "$PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR" \
&& ln -sfv /config "$PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR/Plex Media Server"
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["/usr/bin/entrypoint"]