diff --git a/Dockerfile b/Dockerfile index feb95af15..7d878293e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 \ @@ -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 @@ -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 \ @@ -69,63 +82,160 @@ RUN apt-get update -qq && \ libevent-dev \ qemu-user-static \ wget \ - jq - -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 \ - && 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 \ - && make \ - && make install && cd .. && rm sqlite-src-3290000.zip && rm -rf sqlite-src-3290000 - -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 rustup toolchain install stable --component rustfmt --allow-downgrade - -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) + 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 pip3 wheel cryptography -RUN pip3 install grpcio-tools -RUN /root/.local/bin/poetry export -o requirements.txt --without-hashes --with dev -RUN pip3 install -r requirements.txt +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" + +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.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.zip && rm -rf sqlite-* + +ENV RUST_PROFILE=release +ENV PATH=$PATH:/root/.cargo/bin/ +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 + +# 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) + +# 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/* @@ -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 diff --git a/tools/build-release.sh b/tools/build-release.sh index 924ac7af1..ed9953af9 100755 --- a/tools/build-release.sh +++ b/tools/build-release.sh @@ -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."