/
/
/
1# syntax=docker/dockerfile:1
2
3# Builder image. It builds the venv that will be copied to the final image
4#
5ARG BASE_IMAGE_VERSION=latest
6FROM ghcr.io/music-assistant/base:$BASE_IMAGE_VERSION AS builder
7
8ADD dist dist
9COPY requirements_all.txt .
10
11# ensure UV is installed
12COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
13
14# create venv which will be copied to the final image
15ENV VIRTUAL_ENV=/app/venv
16RUN uv venv $VIRTUAL_ENV
17
18# pre-install ALL requirements into the venv
19# comes at a cost of a slightly larger image size but is faster to start
20# because we do not have to install dependencies at runtime
21RUN uv pip install \
22 -r requirements_all.txt
23
24# Install PyAV from pre-built wheel (built against system FFmpeg in base image)
25# First verify the wheel version matches what pip resolved to avoid version mismatch
26RUN REQUIRED_VERSION=$($VIRTUAL_ENV/bin/python -c "import importlib.metadata; print(importlib.metadata.version('av'))") && \
27 WHEEL_VERSION=$(ls /usr/local/share/pyav-wheels/av*.whl | grep -oP 'av-\K[0-9.]+') && \
28 if [ "$REQUIRED_VERSION" != "$WHEEL_VERSION" ]; then \
29 echo "ERROR: PyAV version mismatch! Requirements need $REQUIRED_VERSION but base image has $WHEEL_VERSION" && \
30 echo "Please rebuild the base image with the correct PyAV version." && \
31 exit 1; \
32 fi && \
33 uv pip install --force-reinstall --no-deps /usr/local/share/pyav-wheels/av*.whl
34
35# Install Music Assistant from prebuilt wheel
36ARG MASS_VERSION
37RUN uv pip install \
38 --no-cache \
39 "music-assistant@dist/music_assistant-${MASS_VERSION}-py3-none-any.whl"
40
41# Pre-compile Python bytecode for faster startup
42RUN $VIRTUAL_ENV/bin/python -m compileall -q $VIRTUAL_ENV/lib/python*/site-packages/music_assistant
43
44# we need to set (very permissive) permissions to the workdir
45# and /tmp to allow running the container as non-root
46# IMPORTANT: chmod here, NOT on the final image, to avoid creating extra layers and increase size!
47#
48RUN chmod -R 777 /app
49
50##################################################################################################
51
52# FINAL docker image for music assistant server
53
54FROM ghcr.io/music-assistant/base:$BASE_IMAGE_VERSION
55
56ENV VIRTUAL_ENV=/app/venv
57ENV PATH="$VIRTUAL_ENV/bin:$PATH"
58
59# copy the already built /app dir
60COPY --from=builder /app /app
61
62# the /app contents have correct permissions but for some reason /app itself does not.
63# so apply again, but ONLY to the dir (otherwise we increase the size)
64RUN chmod 777 /app
65
66# Set some labels
67ARG MASS_VERSION
68ARG TARGETPLATFORM
69LABEL \
70 org.opencontainers.image.title="Music Assistant Server" \
71 org.opencontainers.image.description="Music Assistant is a free, opensource Media library manager that connects to your streaming services and a wide range of connected speakers. The server is the beating heart, the core of Music Assistant and must run on an always-on device like a Raspberry Pi, a NAS or an Intel NUC or alike." \
72 org.opencontainers.image.source="https://github.com/music-assistant/server" \
73 org.opencontainers.image.authors="The Music Assistant Team" \
74 org.opencontainers.image.documentation="https://music-assistant.io" \
75 org.opencontainers.image.licenses="Apache License 2.0" \
76 io.hass.version="${MASS_VERSION}" \
77 io.hass.type="addon" \
78 io.hass.name="Music Assistant Server" \
79 io.hass.description="Music Assistant Server" \
80 io.hass.platform="${TARGETPLATFORM}" \
81 io.hass.type="addon"
82
83VOLUME [ "/data" ]
84EXPOSE 8095
85
86WORKDIR $VIRTUAL_ENV
87
88# Entrypoint script that enables jemalloc for the main process only
89RUN printf '#!/bin/sh\n\
90for path in /usr/lib/*/libjemalloc.so.2; do\n\
91 [ -f "$path" ] && export LD_PRELOAD="$path" && break\n\
92done\n\
93exec mass "$@"\n' > /usr/local/bin/entrypoint.sh && chmod +x /usr/local/bin/entrypoint.sh
94
95ENTRYPOINT ["/usr/local/bin/entrypoint.sh", "--data-dir", "/data", "--cache-dir", "/data/.cache"]
96