Skip to content

Commit

Permalink
Use cross compile in dockerfile, fix arm32 support
Browse files Browse the repository at this point in the history
  • Loading branch information
NicolasDorier authored and endothermicdev committed May 23, 2024
1 parent 877df5a commit 738ddc6
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 100 deletions.
204 changes: 157 additions & 47 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
# This dockerfile is meant to compile a core-lightning x64 image
# It is using multi stage build:
# * downloader: Download litecoin/bitcoin and qemu binaries needed for core-lightning
# * builder: Compile core-lightning dependencies, then core-lightning itself with static linking
# * final: Copy the binaries required at runtime
# The resulting image uploaded to dockerhub will only contain what is needed for runtime.
# From the root of the repository, run "docker build -t yourimage:yourtag ."
FROM debian:bullseye-slim as downloader
# This Dockerfile is used by buildx to build ARM64, AMD64, and ARM32 Docker images from an AMD64 host.
# To speed up the build process, we are cross-compiling rather than relying on QEMU.
# There are four main stages:
# * downloader: Downloads specific binaries needed for c-lightning for each architecture.
# * builder: Cross-compiles for each architecture.
# * builder-python: Builds Python dependencies for cln-rest with QEMU.
# * final: Creates the runtime image.

ARG BASE_DISTRO="debian:bullseye-slim"

FROM --platform=$BUILDPLATFORM ${BASE_DISTRO} as base-downloader
RUN set -ex \
&& apt-get update \
&& apt-get install -qq --no-install-recommends ca-certificates dirmngr wget qemu-user-static binfmt-support

FROM base-downloader as base-downloader-linux-amd64
ENV TARBALL_ARCH_FINAL=x86_64-linux-gnu

FROM base-downloader as base-downloader-linux-arm64
ENV TARBALL_ARCH_FINAL=aarch64-linux-gnu

FROM base-downloader as base-downloader-linux-arm
ENV TARBALL_ARCH_FINAL=arm-linux-gnueabihf

FROM base-downloader-${TARGETOS}-${TARGETARCH} as downloader

RUN set -ex \
&& apt-get update \
Expand All @@ -14,9 +31,7 @@ RUN set -ex \
WORKDIR /opt


ARG BITCOIN_VERSION=22.0
ARG TARBALL_ARCH=x86_64-linux-gnu
ENV TARBALL_ARCH_FINAL=$TARBALL_ARCH
ENV BITCOIN_VERSION=22.0
ENV BITCOIN_TARBALL bitcoin-${BITCOIN_VERSION}-${TARBALL_ARCH_FINAL}.tar.gz
ENV BITCOIN_URL https://bitcoincore.org/bin/bitcoin-core-$BITCOIN_VERSION/$BITCOIN_TARBALL
ENV BITCOIN_ASC_URL https://bitcoincore.org/bin/bitcoin-core-$BITCOIN_VERSION/SHA256SUMS
Expand All @@ -39,9 +54,7 @@ RUN mkdir /opt/litecoin && cd /opt/litecoin \
&& tar -xzvf litecoin.tar.gz litecoin-$LITECOIN_VERSION/bin/litecoin-cli --strip-components=1 --exclude=*-qt \
&& rm litecoin.tar.gz

FROM debian:bullseye-slim as builder

ENV LIGHTNINGD_VERSION=master
FROM --platform=linux/amd64 ${BASE_DISTRO} as base-builder
RUN apt-get update -qq && \
apt-get install -qq -y --no-install-recommends \
autoconf \
Expand Down Expand Up @@ -69,63 +82,160 @@ RUN apt-get update -qq && \
libevent-dev \
qemu-user-static \
wget \
jq
unzip \
tclsh

ENV PYTHON_VERSION=3
RUN curl -sSL https://install.python-poetry.org | python3 -
RUN update-alternatives --install /usr/bin/python python /usr/bin/python3.9 1
RUN pip3 install --upgrade pip setuptools wheel

RUN wget -q https://zlib.net/fossils/zlib-1.2.13.tar.gz -O zlib.tar.gz && \
wget -q https://www.sqlite.org/2019/sqlite-src-3290000.zip -O sqlite.zip

WORKDIR /opt/lightningd
COPY . /tmp/lightning
RUN git clone --recursive /tmp/lightning . && \
git checkout $(git --work-tree=/tmp/lightning --git-dir=/tmp/lightning/.git rev-parse HEAD)

# Do not build clnrest here, since it's python, we can't cross compile it.
RUN sed -i '/^clnrest/d' pyproject.toml && \
/root/.local/bin/poetry export -o requirements.txt --without-hashes
RUN pip3 install -r requirements.txt && pip3 cache purge
WORKDIR /

FROM base-builder as base-builder-linux-amd64

FROM base-builder as base-builder-linux-arm64
ENV target_host=aarch64-linux-gnu \
target_host_rust=aarch64-unknown-linux-gnu \
target_host_qemu=qemu-aarch64-static

RUN apt-get install -qq -y --no-install-recommends \
libc6-arm64-cross \
gcc-${target_host} \
g++-${target_host}

ENV AR=${target_host}-ar \
AS=${target_host}-as \
CC=${target_host}-gcc \
CXX=${target_host}-g++ \
LD=${target_host}-ld \
STRIP=${target_host}-strip \
QEMU_LD_PREFIX=/usr/${target_host} \
HOST=${target_host} \
TARGET=${target_host_rust} \
RUSTUP_INSTALL_OPTS="--target ${target_host_rust} --default-host ${target_host_rust}" \
PKG_CONFIG_PATH="/usr/${target_host}/lib/pkgconfig"

ENV \
ZLIB_CONFIG="--prefix=${QEMU_LD_PREFIX}" \
SQLITE_CONFIG="--host=${target_host} --prefix=$QEMU_LD_PREFIX"

RUN wget -q https://zlib.net/fossils/zlib-1.2.13.tar.gz \
&& tar xvf zlib-1.2.13.tar.gz \
&& cd zlib-1.2.13 \
&& ./configure \
FROM base-builder as base-builder-linux-arm

ENV target_host=arm-linux-gnueabihf \
target_host_rust=armv7-unknown-linux-gnueabihf \
target_host_qemu=qemu-arm-static

RUN apt-get install -qq -y --no-install-recommends \
libc6-armhf-cross \
gcc-${target_host} \
g++-${target_host}

ENV AR=${target_host}-ar \
AS=${target_host}-as \
CC=${target_host}-gcc \
CXX=${target_host}-g++ \
LD=${target_host}-ld \
STRIP=${target_host}-strip \
QEMU_LD_PREFIX=/usr/${target_host} \
HOST=${target_host} \
TARGET=${target_host_rust} \
RUSTUP_INSTALL_OPTS="--target ${target_host_rust} --default-host ${target_host_rust}" \
PKG_CONFIG_PATH="/usr/${target_host}/lib/pkgconfig"

ENV \
ZLIB_CONFIG="--prefix=${QEMU_LD_PREFIX}" \
SQLITE_CONFIG="--host=${target_host} --prefix=$QEMU_LD_PREFIX"

FROM base-builder-${TARGETOS}-${TARGETARCH} as builder

ENV LIGHTNINGD_VERSION=master

RUN mkdir zlib && tar xvf zlib.tar.gz -C zlib --strip-components=1 \
&& cd zlib \
&& ./configure ${ZLIB_CONFIG} \
&& make \
&& make install && cd .. && \
rm zlib-1.2.13.tar.gz && \
rm -rf zlib-1.2.13

RUN apt-get install -y --no-install-recommends unzip tclsh \
&& wget -q https://www.sqlite.org/2019/sqlite-src-3290000.zip \
&& unzip sqlite-src-3290000.zip \
&& cd sqlite-src-3290000 \
&& ./configure --enable-static --disable-readline --disable-threadsafe --disable-load-extension \
rm zlib.tar.gz && \
rm -rf zlib

RUN unzip sqlite.zip \
&& cd sqlite-* \
&& ./configure --enable-static --disable-readline --disable-threadsafe --disable-load-extension ${SQLITE_CONFIG} \
&& make \
&& make install && cd .. && rm sqlite-src-3290000.zip && rm -rf sqlite-src-3290000
&& make install && cd .. && rm sqlite.zip && rm -rf sqlite-*

USER root
ENV RUST_PROFILE=release
ENV PATH=$PATH:/root/.cargo/bin/
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y ${RUSTUP_INSTALL_OPTS}
RUN rustup toolchain install stable --component rustfmt --allow-downgrade

COPY --from=downloader /usr/bin/${target_host_qemu} /usr/bin/${target_host_qemu}
WORKDIR /opt/lightningd
COPY . /tmp/lightning

RUN git clone --recursive /tmp/lightning . && \
git checkout $(git --work-tree=/tmp/lightning --git-dir=/tmp/lightning/.git rev-parse HEAD)

ENV PYTHON_VERSION=3
RUN curl -sSL https://install.python-poetry.org | python3 -

RUN update-alternatives --install /usr/bin/python python /usr/bin/python3.9 1

RUN pip3 install --upgrade pip setuptools wheel
RUN pip3 wheel cryptography
RUN pip3 install grpcio-tools
# If cross-compiling, need to tell it to cargo.
RUN ( ! [ -n "${target_host}" ] ) || \
(mkdir -p .cargo && echo "[target.${target_host_rust}]\nlinker = \"${target_host}-gcc\"" > .cargo/config)

RUN /root/.local/bin/poetry export -o requirements.txt --without-hashes --with dev
RUN pip3 install -r requirements.txt
# Weird errors with cargo for cln-grpc on arm7 https://github.com/ElementsProject/lightning/issues/6596
RUN ( ! [ "${target_host}" = "arm-linux-gnueabihf" ] ) || \
(sed -i '/documentation = "https:\/\/docs.rs\/cln-grpc"/a include = ["**\/*.*"]' cln-grpc/Cargo.toml)

RUN ./configure --prefix=/tmp/lightning_install --enable-static && \
make && \
/root/.local/bin/poetry run make install

FROM debian:bullseye-slim as final
# We need to build cln-rest on the target's arch because python doesn't support cross build
FROM ${BASE_DISTRO} as builder-python
RUN apt-get update -qq && \
apt-get install -qq -y --no-install-recommends \
git \
curl \
libtool \
pkg-config \
autoconf \
automake \
build-essential \
libffi-dev \
libssl-dev \
python3.9 \
python3-dev \
python3-pip && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

RUN update-alternatives --install /usr/bin/python python /usr/bin/python3.9 1
ENV PATH=$PATH:/root/.cargo/bin/
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
RUN rustup toolchain install stable --component rustfmt --allow-downgrade

WORKDIR /opt/lightningd
COPY plugins/clnrest/requirements.txt plugins/clnrest/requirements.txt
ENV PYTHON_VERSION=3
RUN pip3 install -r plugins/clnrest/requirements.txt && pip3 cache purge

FROM ${BASE_DISTRO} as final

RUN apt-get update && \
apt-get install -y --no-install-recommends \
tini \
socat \
inotify-tools \
jq \
python3.9 \
python3-pip \
qemu-user-static \
libpq5 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
Expand All @@ -140,7 +250,7 @@ RUN mkdir $LIGHTNINGD_DATA && \
VOLUME [ "/root/.lightning" ]

COPY --from=builder /tmp/lightning_install/ /usr/local/
COPY --from=builder /usr/local/lib/python3.9/dist-packages/ /usr/local/lib/python3.9/dist-packages/
COPY --from=builder-python /usr/local/lib/python3.9/dist-packages/ /usr/local/lib/python3.9/dist-packages/
COPY --from=downloader /opt/bitcoin/bin /usr/bin
COPY --from=downloader /opt/litecoin/bin /usr/bin
COPY tools/docker-entrypoint.sh entrypoint.sh
Expand Down
63 changes: 10 additions & 53 deletions tools/build-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -175,61 +175,18 @@ done
if [ -z "${TARGETS##* docker *}" ]; then
echo "Building Docker Images"
DOCKER_USER="elementsproject"
PLATFORMS="amd64 arm64v8"
for d in $PLATFORMS; do
TMPDIR="$(mktemp -d /tmp/lightningd-docker-"$d".XXXXXX)"
SRCDIR="$(pwd)"
echo "Bundling $d image in ${TMPDIR}"
git clone --recursive . "${TMPDIR}"
(
cd "${TMPDIR}"
if ! $FORCE_UNCLEAN; then
git checkout "v${BARE_VERSION}"
fi
cp "${SRCDIR}/Dockerfile" "${TMPDIR}/"
case "$d" in
"arm32v7")
TARBALL_ARCH="arm-linux-gnueabihf"
PLATFORM="linux/arm/v7"
;;
"arm64v8")
TARBALL_ARCH="aarch64-linux-gnu"
PLATFORM="linux/arm64"
;;
"amd64")
TARBALL_ARCH="x86_64-linux-gnu"
PLATFORM="linux/amd64"
;;
esac
if $DOCKER_PUSH; then
docker buildx build --push --platform $PLATFORM --build-arg TARBALL_ARCH=$TARBALL_ARCH -t "$DOCKER_USER"/lightningd:"$VERSION"-"$d" -f Dockerfile "${TMPDIR}"
echo "Docker Image for $PLATFORM Built and Uploaded on Dockerhub."
else
docker buildx build --load --platform $PLATFORM --build-arg TARBALL_ARCH=$TARBALL_ARCH -t "$DOCKER_USER"/lightningd:"$VERSION"-"$d" -f Dockerfile "${TMPDIR}"
echo "Docker Image for $PLATFORM Built. Ready to Upload on Dockerhub."
fi
)
rm -rf "${TMPDIR}"
done
echo "Creating a multi-platform image tagged as $VERSION"
docker manifest create --amend "$DOCKER_USER"/lightningd:"$VERSION" "$DOCKER_USER"/lightningd:"$VERSION"-amd64 "$DOCKER_USER"/lightningd:"$VERSION"-arm64v8
docker manifest annotate "$DOCKER_USER"/lightningd:"$VERSION" "$DOCKER_USER"/lightningd:"$VERSION"-amd64 --os linux --arch amd64
docker manifest annotate "$DOCKER_USER"/lightningd:"$VERSION" "$DOCKER_USER"/lightningd:"$VERSION"-arm64v8 --os linux --arch arm64 --variant v8
# FIXME: Throws ERROR: failed to solve: debian:bullseye-slim: no match for platform in manifest
# docker buildx create --use
# docker buildx build --push --platform linux/amd64,linux/arm64v8 -t "$DOCKER_USER/lightningd:"$VERSION"-$d" .
echo "Creating a multi-platform image tagged as latest"
# Remove the old image
docker rmi "$DOCKER_USER"/lightningd:latest
# Remove the old manifest
docker manifest rm "$DOCKER_USER"/lightningd:latest
docker manifest create "$DOCKER_USER"/lightningd:latest "$DOCKER_USER"/lightningd:"$VERSION"-amd64 "$DOCKER_USER"/lightningd:"$VERSION"-arm64v8
docker manifest annotate "$DOCKER_USER"/lightningd:latest "$DOCKER_USER"/lightningd:"$VERSION"-amd64 --os linux --arch amd64
docker manifest annotate "$DOCKER_USER"/lightningd:latest "$DOCKER_USER"/lightningd:"$VERSION"-arm64v8 --os linux --arch arm64 --variant v8
DOCKER_OPTS="--platform linux/amd64,linux/arm64,linux/arm/v7"
$DOCKER_PUSH && DOCKER_OPTS="$DOCKER_OPTS --push"
DOCKER_OPTS="$DOCKER_OPTS -t $DOCKER_USER/lightningd:$VERSION"
DOCKER_OPTS="$DOCKER_OPTS -t $DOCKER_USER/lightningd:latest"

#docker buildx create --use

# shellcheck disable=SC2086
docker buildx build $DOCKER_OPTS .

if $DOCKER_PUSH; then
docker manifest push "$DOCKER_USER"/lightningd:"$VERSION"
echo "Pushed a multi-platform image tagged as $VERSION"
docker manifest push "$DOCKER_USER"/lightningd:latest
echo "Pushed a multi-platform image tagged as latest"
else
echo "Docker Images Built. Ready to Upload on Dockerhub."
Expand Down

0 comments on commit 738ddc6

Please sign in to comment.