Files
spectre/backend/Dockerfile
Jimmy Fitzpatrick cec57b69a0 fix: issue-239 Resolve RX-888 MK II dropping samples (#241)
* fix: issue-239 Fix dropped samples from the RX-888 MK II

* chore: Bump version
2026-05-16 15:41:18 +01:00

566 lines
18 KiB
Docker

# SPDX-FileCopyrightText: © 2024-2026 Jimmy Fitzpatrick <jimmy@spectregrams.org>
# This file is part of SPECTRE
# SPDX-License-Identifier: GPL-3.0-or-later
# --------------------------------- #
# Create the base stage.
# --------------------------------- #
FROM ubuntu:22.04 AS base
# Stop interactive dialogue, only for the duration of the build.
ARG DEBIAN_FRONTEND=noninteractive
# By default, we use the /tmp directory to hold build artifacts.
WORKDIR /tmp
# Explictly set the user to root by default for each stage.
USER root
# Install dependencies which are both required for all the build stages, and must be present in the final runtime image.
RUN apt-get update && apt-get install -y --no-install-recommends \
gosu \
python3 \
wget \
ca-certificates \
libpython3.10 \
libusb-1.0-0 \
liblog4cpp5-dev \
libspdlog1 \
libuhd4.1.0 \
libfftw3-3 \
libsoapysdr0.8 \
soapysdr-tools \
libboost-program-options1.74.0 \
libboost-thread1.74.0 \
libboost-chrono1.74.0 \
libboost-filesystem1.74.0 \
libboost-system1.74.0 \
libboost-serialization1.74.0 && \
rm -rf /var/lib/apt/lists/*
# -------------------------------------- #
# Install shared build dependencies.
# -------------------------------------- #
FROM base AS build
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
cmake \
clang-format \
build-essential \
twine \
python3-dev \
python3-packaging \
python3-pip \
python3-setuptools \
python3-requests \
python3-mako \
python3-numpy \
python3-build \
python3-venv \
python3-yaml \
python3-pygccxml \
python3-click \
python3-click-plugins \
pybind11-dev \
libusb-1.0-0-dev \
libsoapysdr-dev \
libspdlog-dev \
libudev-dev \
libfftw3-dev \
libgmp-dev \
libgsm1-dev \
libthrift-dev \
libcppunit-dev \
libboost-program-options1.74-dev \
libboost-thread1.74-dev \
libboost-chrono1.74-dev \
libboost-filesystem1.74-dev \
libboost-system1.74-dev \
libboost-serialization1.74-dev \
libboost-date-time1.74-dev \
libboost-regex1.74-dev \
libboost-test1.74-dev && \
python3 -m pip install --upgrade pip setuptools build twine && \
rm -rf /var/lib/apt/lists/*
# --------------------------------------------- #
# Install UHD.
# --------------------------------------------- #
FROM build AS uhd
WORKDIR /tmp
# Minimal UHD install, to reduce image size.
RUN git clone --branch v4.9.0.0 --depth 1 https://github.com/EttusResearch/uhd.git && \
cd uhd/host && \
mkdir build && \
cd build && \
cmake -Wno-dev \
-DCMAKE_INSTALL_PREFIX=/opt/uhd \
-DENABLE_B100=ON \
-DENABLE_B200=ON \
-DENABLE_USRP1=ON \
-DENABLE_USRP2=ON \
-DENABLE_LIBUHD=ON \
-DENABLE_USB=ON \
-DENABLE_PYTHON_API=ON \
-DENABLE_UTILS=ON \
-DENABLE_X300=OFF \
-DENABLE_X400=OFF \
-DENABLE_E320=OFF \
-DENABLE_E300=OFF \
-DENABLE_N320=OFF \
-DENABLE_N300=OFF \
-DENABLE_EXAMPLES=OFF \
-DENABLE_TESTS=OFF \
-DENABLE_MAN_PAGES=OFF \
-DENABLE_DOXYGEN=OFF \
-DENABLE_MANUAL=OFF \
-DENABLE_SIM=OFF \
-DENABLE_MPMD=OFF \
-DENABLE_OCTOCLOCK=OFF \
-DENABLE_C_API=OFF \
.. && \
make -j"$(nproc)" && \
make install && \
rm -rf /tmp/*
RUN /opt/uhd/lib/uhd/utils/uhd_images_downloader.py --install-location=/opt/uhd/share/uhd/images/ \
--types b2xx && \
rm -rf /tmp/*
# --------------------------------------------- #
# Install Volk.
# --------------------------------------------- #
FROM build AS volk
WORKDIR /tmp
COPY --from=uhd /opt/uhd/include /usr/include
COPY --from=uhd /opt/uhd/lib /usr/lib
COPY --from=uhd /opt/uhd/bin /usr/bin
COPY --from=uhd /opt/uhd/share /usr/share
# Minimal volk install, to reduce image size.
RUN git clone --branch v2.5.1 --recursive --depth 1 --shallow-submodules https://github.com/gnuradio/volk.git && \
cd volk && \
mkdir build && \
cd build && \
cmake -Wno-dev \
-DCMAKE_INSTALL_PREFIX=/opt/volk \
-DCMAKE_BUILD_TYPE=MinSizeRel \
-DBUILD_TESTING=OFF \
-DENABLE_TESTING=OFF \
.. && \
make -j"$(nproc)" && \
make install && \
rm -rf /tmp/*
# --------------------------------------------- #
# Install GNU Radio.
# --------------------------------------------- #
FROM build AS gnuradio
WORKDIR /tmp
COPY --from=uhd /opt/uhd/include /usr/include
COPY --from=uhd /opt/uhd/lib /usr/lib
COPY --from=uhd /opt/uhd/bin /usr/bin
COPY --from=uhd /opt/uhd/share /usr/share
COPY --from=volk /opt/volk/include /usr/include
COPY --from=volk /opt/volk/lib /usr/lib
COPY --from=volk /opt/volk/bin /usr/bin
# Minimal GNU Radio install, to reduce image size. Notably, our installation is headless.
# Currently using a custom fork with a one-line patch (see PR: https://github.com/gnuradio/gnuradio/pull/7751
# TODO: Build GNU Radio from an official branch. See https://github.com/jcfitzpatrick12/spectre/issues/108
RUN git clone --branch v3.10.1.1-streamtag-fix --depth 1 https://github.com/jcfitzpatrick12/gnuradio.git && \
cd gnuradio && \
mkdir build && \
cd build && \
cmake -Wno-dev \
-DCMAKE_INSTALL_PREFIX=/opt/gnuradio \
-DGR_PYTHON_DIR=/opt/gnuradio/lib/python3.10/dist-packages \
-DENABLE_GNURADIO_RUNTIME=ON \
-DENABLE_PYTHON=ON \
-DENABLE_GR_UHD=ON \
-DENABLE_GR_BLOCKS=ON \
-DENABLE_GR_FILTER=ON \
-DENABLE_GR_ANALOG=ON \
-DENABLE_GR_FFT=ON \
-DENABLE_GR_SOAPY=ON \
-DENABLE_GR_UTILS=OFF \
-DENABLE_GR_MODTOOL=OFF \
-DENABLE_GR_BLOCKTOOL=OFF \
-DENABLE_GR_PDU=OFF \
-DENABLE_GR_AUDIO=OFF \
-DENABLE_GR_CHANNELS=OFF \
-DENABLE_GR_CTRLPORT=OFF \
-DENABLE_GR_DTV=OFF \
-DENABLE_GR_FEC=OFF \
-DENABLE_GR_NETWORK=OFF \
-DENABLE_GR_QTGUI=OFF \
-DENABLE_GR_TRELLIS=OFF \
-DENABLE_GR_VIDEO_SDL=OFF \
-DENABLE_GR_VOCODER=OFF \
-DENABLE_GR_ZEROMQ=OFF \
-DENABLE_MANPAGES=OFF \
-DENABLE_TESTING=OFF \
-DENABLE_DOXYGEN=OFF \
-DENABLE_EXAMPLES=OFF \
-DENABLE_GRC=OFF \
.. && \
make -j"$(nproc)" && \
make install && \
rm -rf /tmp/*
# --------------------------------- #
# Install the SDRplay API.
# --------------------------------- #
FROM build AS sdrplay_api
WORKDIR /tmp/sdrplay_api
ARG SDRPLAY_API_MAJ_MIN=3.15
ARG SDRPLAY_API_PATCH=2
ARG SDRPLAY_VERSION=${SDRPLAY_API_MAJ_MIN}.${SDRPLAY_API_PATCH}
ARG SDRPLAY_API_LIB=libsdrplay_api
RUN mkdir -p /opt/sdrplay_api/include \
/opt/sdrplay_api/lib \
/opt/sdrplay_api/bin \
/opt/sdrplay_api/share/doc/ && \
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-${SDRPLAY_VERSION}.run && \
sh SDRplay_RSP_API-Linux-${SDRPLAY_VERSION}.run --tar xf && \
ARCH=$(uname -m | sed 's/aarch64/arm64/' | sed 's/x86_64/amd64/') && \
cp ${ARCH}/${SDRPLAY_API_LIB}.so.${SDRPLAY_API_MAJ_MIN} /opt/sdrplay_api/lib/ && \
cp ${ARCH}/sdrplay_apiService /opt/sdrplay_api/bin/ && \
cp inc/* /opt/sdrplay_api/include/ && \
cp sdrplay_license.txt /opt/sdrplay_api/share/doc/ && \
ln --symbolic ${SDRPLAY_API_LIB}.so.${SDRPLAY_API_MAJ_MIN} /opt/sdrplay_api/lib/${SDRPLAY_API_LIB}.so.3 && \
ln --symbolic ${SDRPLAY_API_LIB}.so.${SDRPLAY_API_MAJ_MIN} /opt/sdrplay_api/lib/${SDRPLAY_API_LIB}.so && \
rm -rf /tmp/*
# --------------------------------------------- #
# Create an executable to find SDRplay devices.
# --------------------------------------------- #
FROM build AS sdrplay_find_devices
WORKDIR /tmp/sdrplay_find_devices
COPY --from=sdrplay_api /opt/sdrplay_api/include/ /usr/include/
COPY --from=sdrplay_api /opt/sdrplay_api/lib/ /usr/lib/
COPY ./scripts/cpp/sdrplay_find_devices.cpp sdrplay_find_devices.cpp
RUN mkdir -p /opt/sdrplay_find_devices/bin && \
g++ sdrplay_find_devices.cpp -l sdrplay_api -o /opt/sdrplay_find_devices/bin/sdrplay_find_devices && \
rm -rf /tmp/*
# --------------------------------------------- #
# Install hackRF host software.
# --------------------------------------------- #
FROM build AS hackrf
WORKDIR /tmp
RUN git clone --depth 1 -b v2022.09.1 https://github.com/greatscottgadgets/hackrf.git && \
cd hackrf/host && \
mkdir build && \
cd build && \
cmake -Wno-dev \
-DCMAKE_INSTALL_PREFIX=/opt/hackrf \
-DINSTALL_UDEV_RULES=OFF \
.. && \
make -j"$(nproc)" && \
make install && \
rm -rf /tmp/*
# --------------------------------------------- #
# Install the hackRF Soapy plugin.
# --------------------------------------------- #
FROM build AS soapy_hackrf
WORKDIR /tmp
COPY --from=hackrf /opt/hackrf/include /usr/include
COPY --from=hackrf /opt/hackrf/bin /usr/bin
COPY --from=hackrf /opt/hackrf/lib /usr/lib
RUN git clone --depth 1 -b soapy-hackrf-0.3.4 https://github.com/pothosware/SoapyHackRF.git && \
cd SoapyHackRF && \
mkdir build && \
cd build && \
cmake -Wno-dev \
-DCMAKE_INSTALL_PREFIX=/opt/soapy_hackrf \
.. && \
make -j"$(nproc)" && \
make install && \
rm -rf /tmp/*
# --------------------------------------------- #
# Install RTL-SDR library
# --------------------------------------------- #
FROM build AS rtlsdr
WORKDIR /tmp
RUN git clone --depth 1 -b v2.0.1 https://github.com/osmocom/rtl-sdr.git rtlsdr && \
cd rtlsdr && \
mkdir build && \
cd build && \
cmake -Wno-dev \
-DCMAKE_INSTALL_PREFIX=/opt/rtlsdr \
-DDETACH_KERNEL_DRIVER=ON \
.. && \
make -j"$(nproc)" && \
make install && \
rm -rf /tmp/*
# --------------------------------------------- #
# Install the RTL-SDR Soapy plugin.
# --------------------------------------------- #
FROM build AS soapy_rtlsdr
WORKDIR /tmp
COPY --from=rtlsdr /opt/rtlsdr/include /usr/include
COPY --from=rtlsdr /opt/rtlsdr/bin /usr/bin
COPY --from=rtlsdr /opt/rtlsdr/lib /usr/lib
RUN git clone --depth 1 -b soapy-rtl-sdr-0.3.3 https://github.com/pothosware/SoapyRTLSDR.git && \
cd SoapyRTLSDR && \
mkdir build && \
cd build && \
cmake -Wno-dev \
-DCMAKE_INSTALL_PREFIX=/opt/soapy_rtlsdr \
.. && \
make -j"$(nproc)" && \
make install && \
rm -rf /tmp/*
# --------------------------------------------- #
# Install the Soapy SDDC plugin.
# --------------------------------------------- #
FROM build AS soapy_sddc
WORKDIR /tmp
ARG TARGETARCH
# Use a custom fork with a patch providing support for the RX-888 MK II on the platform `linux/arm64`.
# See PR: (https://github.com/ik1xpv/ExtIO_sddc/pull/246).
# TODO: Buld ExtIO_sddc from an official branch.
RUN git clone --depth 1 -b v0.0.2 https://github.com/spectregrams/ExtIO_sddc && \
cd ExtIO_sddc && \
mkdir build && \
cd build && \
cmake -Wno-dev \
-DCMAKE_INSTALL_PREFIX=/opt/soapy_sddc \
.. && \
make -j"$(nproc)" && \
make install && \
rm -rf /tmp/*
# --------------------------------------------- #
# Shared build dependencies for OOT modules.
# --------------------------------------------- #
FROM build AS oot_module
WORKDIR /tmp
# Copy in the GNU Radio dependencies.
COPY --from=uhd /opt/uhd/include /usr/include
COPY --from=uhd /opt/uhd/lib /usr/lib
COPY --from=uhd /opt/uhd/bin /usr/bin
COPY --from=uhd /opt/uhd/share /usr/share
COPY --from=volk /opt/volk/include /usr/include
COPY --from=volk /opt/volk/lib /usr/lib
COPY --from=volk /opt/volk/bin /usr/bin
COPY --from=gnuradio /opt/gnuradio/lib /usr/lib
COPY --from=gnuradio /opt/gnuradio/bin /usr/bin
COPY --from=gnuradio /opt/gnuradio/share /usr/share
COPY --from=gnuradio /opt/gnuradio/include /usr/include
# A bash script used to build OOT modules consistently.
COPY --chmod=0755 ./scripts/bash/build_oot_module.sh build_oot_module.sh
# --------------------------------------------- #
# Install the gr-sdrplay3 OOT module.
# --------------------------------------------- #
FROM oot_module AS gr_sdrplay3
COPY --from=sdrplay_api /opt/sdrplay_api/include/ /usr/include/
COPY --from=sdrplay_api /opt/sdrplay_api/lib/ /usr/lib/
RUN . ./build_oot_module.sh && \
build_from_repo https://github.com/fventuri/gr-sdrplay3.git v3.11.0.9 && \
rm -rf /tmp/*
# --------------------------------------------- #
# Install the gr-spectre OOT module.
# --------------------------------------------- #
FROM oot_module AS gr_spectre
RUN . ./build_oot_module.sh && \
build_from_repo https://github.com/spectregrams/gr-spectre.git v2.1.1 && \
rm -rf /tmp/*
# --------------------------------- #
# Install the spectre server.
# --------------------------------- #
# Use the `base` stage instead of `build` to avoid copying Python packages needed only for building GNU Radio.
# Otherwise, since we're not using venvs and everything is installed system wide, these would be copied into the
# final runtime image later.
FROM base AS spectre_server
WORKDIR /tmp/spectre_server
RUN apt-get update && apt-get install -y --no-install-recommends \
python3-pip && \
python3 -m pip install --upgrade pip && \
rm -rf /var/lib/apt/lists/*
# Copy in the source code and build requirements.
COPY pyproject.toml ./
COPY src src
# Finally, install the Python dependencies system wide.
RUN pip install . && \
rm -rf /tmp/*
COPY gunicorn.conf.py /opt/spectre_server/
# --------------------------------- #
# Create the final runtime image.
# --------------------------------- #
FROM base AS runtime
LABEL maintainer="Jimmy Fitzpatrick <jimmy@spectregrams.org>" \
version="3.5.1-alpha" \
description="Docker image for running the `spectre-server`." \
license="GPL-3.0-or-later"
WORKDIR /app
ENV SPECTRE_DATA_DIR_PATH="/app/.spectre-data"
ENV MPLCONFIGDIR="/app/.mplconfigdir"
ENV UHD_IMAGES_DIR="/usr/share/uhd/images"
# Copy in the SDRplay runtime dependencies.
COPY --from=sdrplay_api /opt/sdrplay_api/bin /usr/bin
COPY --from=sdrplay_api /opt/sdrplay_api/lib /usr/lib
COPY --from=sdrplay_find_devices /opt/sdrplay_find_devices/bin /usr/bin
# Copy in the hackRF runtime dependencies.
COPY --from=hackrf /opt/hackrf/bin /usr/bin
COPY --from=hackrf /opt/hackrf/lib /usr/lib
COPY --from=soapy_hackrf /opt/soapy_hackrf/lib /usr/local/lib
# Copy in the rtlsdr runtime dependencies.
COPY --from=rtlsdr /opt/rtlsdr/bin /usr/bin
COPY --from=rtlsdr /opt/rtlsdr/lib /usr/lib
COPY --from=soapy_rtlsdr /opt/soapy_rtlsdr/lib /usr/local/lib
# Copy in the sddc runtime dependencies.
COPY --from=soapy_sddc /opt/soapy_sddc/lib /usr/local/lib
# Copy in the UHD runtime dependencies.
COPY --from=uhd /opt/uhd/lib /usr/lib
COPY --from=uhd /opt/uhd/bin /usr/bin
COPY --from=uhd /opt/uhd/share /usr/share
# Copy in the Volk runtime dependencies.
COPY --from=volk /opt/volk/lib /usr/lib
COPY --from=volk /opt/volk/bin /usr/bin
# Copy in the GNU Radio runtime dependencies.
COPY --from=gnuradio /opt/gnuradio/lib /usr/lib
COPY --from=gnuradio /opt/gnuradio/bin /usr/bin
COPY --from=gnuradio /opt/gnuradio/share /usr/share
# Copy in the gr-sdrplay3 OOT module runtime dependencies.
COPY --from=gr_sdrplay3 /opt/gr_sdrplay3/lib/ /usr/lib
COPY --from=gr_sdrplay3 /opt/gr_sdrplay3/local/ /usr/local/
# Copy in the gr-spectre OOT module runtime dependencies.
COPY --from=gr_spectre /opt/gr_spectre/lib/ /usr/lib
COPY --from=gr_spectre /opt/gr_spectre/local/ /usr/local/
# Copy in the spectre server runtime dependencies.
COPY --from=spectre_server /usr/local/lib/python3.10/dist-packages/ /usr/local/lib/python3.10/dist-packages/
COPY --from=spectre_server /opt/spectre_server/gunicorn.conf.py /app/gunicorn.conf.py
# Copy in the scripts which will run when the container starts.
COPY --chmod=0755 scripts/bash/entrypoint.sh entrypoint.sh
COPY --chmod=0755 scripts/bash/cmd.sh cmd.sh
# Add a non-root user to run the application.
RUN useradd -u 1000 -M -d /app appuser
# We cannot use the `USER` directive, since non-root user running the application can't write to the mounted volume,
# or (by default) access USB devices. So, the container starts as root to change ownership of things, then drops
# privileges and runs as the non-root user to execute the application.
# See https://stackoverflow.com/questions/65574334/docker-is-it-safe-to-switch-to-non-root-user-in-entrypoint for
# some discussion on this approach.
ENTRYPOINT ["/bin/sh", "entrypoint.sh"]
CMD ["/app/cmd.sh"]
# ----------------------------------------------------------- #
# Optional target, where you can run the application as root.
# ----------------------------------------------------------- #
FROM runtime AS root_runtime
# Override inherited entrypoint to allow running as root without privilege drop.
ENTRYPOINT [ ]
CMD ["/app/cmd.sh"]
# --------------------------------- #
# Create the development stage.
# --------------------------------- #
FROM base AS development
LABEL maintainer="Jimmy Fitzpatrick <jimmy@spectregrams.org>" \
version="3.5.1-alpha" \
description="Docker image for developing the `spectre-server`." \
license="GPL-3.0-or-later"
WORKDIR /app
ENV SPECTRE_DATA_DIR_PATH="/app/.spectre-data"
ENV MPLCONFIGDIR="/app/.mplconfigdir"
ENV UHD_IMAGES_DIR="/usr/share/uhd/images"
# Broadly copy in the build dependencies.
COPY --from=build /usr /usr
# Broadly copy in the runtime dependencies.
COPY --from=runtime /usr /usr
# GNU Radio header files.
COPY --from=uhd /opt/uhd/include /usr/include
COPY --from=volk /opt/volk/include /usr/include
COPY --from=gnuradio /opt/gnuradio/include /usr/include
# Get the latest version of `spectre-server`, overriding that from the `runtime` stage.
RUN git clone https://github.com/spectregrams/spectre.git --no-checkout && cd spectre && \
git sparse-checkout init --no-cone && \
git sparse-checkout set backend/ && \
git checkout && \
pip install --editable backend/[test]
# Get the latest version of `gr-spectre`, but don't build it by default.
RUN git clone https://github.com/spectregrams/gr-spectre
# Disable the existing entrypoint and start up commands, and run as root.
ENTRYPOINT [ ]
CMD [ "/bin/bash" ]